diff --git a/src/java/org/lwjgl/DefaultSysImplementation.java b/src/java/org/lwjgl/DefaultSysImplementation.java index 485da949..84b84719 100644 --- a/src/java/org/lwjgl/DefaultSysImplementation.java +++ b/src/java/org/lwjgl/DefaultSysImplementation.java @@ -39,6 +39,13 @@ package org.lwjgl; * @version $Revision$ */ abstract class DefaultSysImplementation implements SysImplementation { + /** The native library name */ + protected static final String LIBRARY_NAME = "lwjgl"; + + public String[] getNativeLibraryNames() { + return new String[]{LIBRARY_NAME}; + } + public native String getNativeLibraryVersion(); public native void setDebug(boolean debug); diff --git a/src/java/org/lwjgl/LWJGLUtil.java b/src/java/org/lwjgl/LWJGLUtil.java index ad54485f..79f05e03 100644 --- a/src/java/org/lwjgl/LWJGLUtil.java +++ b/src/java/org/lwjgl/LWJGLUtil.java @@ -421,4 +421,28 @@ public class LWJGLUtil { System.err.println(msg); } } + + /** + * Method to determine if the current system is running a version of + * Mac OS X better than the given version. This is only useful for Mac OS X + * specific code and will not work for any other platform. + */ + public static boolean isMacOSXEqualsOrBetterThan(int major_required, int minor_required) { + String os_version = System.getProperty("os.version"); + StringTokenizer version_tokenizer = new StringTokenizer(os_version, "."); + int major; + int minor; + try { + String major_str = version_tokenizer.nextToken(); + String minor_str = version_tokenizer.nextToken(); + major = Integer.parseInt(major_str); + minor = Integer.parseInt(minor_str); + } catch (Exception e) { + LWJGLUtil.log("Exception occurred while trying to determine OS version: " + e); + // Best guess, no + return false; + } + return major > major_required || (major == major_required && minor >= minor_required); + } + } diff --git a/src/java/org/lwjgl/MacOSXSysImplementation.java b/src/java/org/lwjgl/MacOSXSysImplementation.java index 9fdd7010..6a7ba372 100644 --- a/src/java/org/lwjgl/MacOSXSysImplementation.java +++ b/src/java/org/lwjgl/MacOSXSysImplementation.java @@ -43,6 +43,37 @@ import java.security.PrivilegedExceptionAction; * @version $Revision$ */ class MacOSXSysImplementation extends J2SESysImplementation { + public String[] getNativeLibraryNames() { + /* If we're on 10.4, fine, we'll just try the default library name. For + * earlier versions of Mac OS X, try the legacy library first. + * + * Having a kludge like this is unfortunate, but necessary for the following reasons: + * 1. We need two libraries to support Mac OS X 10.2, 10.3 and 10.4. We could + * cover 10.2, 10.3 and 10.4 with one gcc 3 compiled library, but then we + * loose intel mac support. Instead, we'll distribute two versions of the lwjgl + * native library, the default and a legacy one. + * 2. The default library will be universal ('fat') with both intel and powerpc support + * compiled in. This requires gcc 4, and makes the library unusable on Mac OS X 10.3 + * and earlier (actually 10.3.9 has the required gcc 4 libraries, but we'll ignore that). + * We could still choose to load the default library first, and the legacy one later, + * but a bug in the Mac OS X java implementation forces a java program to exit + * if the loaded library has a missing dependency (The correct behaviour is to throw + * an UnsatisfiedLinkError, like on linux and windows). + * 3. If the LWJGL program is launched with an intelligent ClassLoader, this issue can be avoided + * altogether, and the legacy library naming can be avoided too. For example, when + * using webstart, one can supply two nativelib references, one for Mac OS X 10.4 + * (the default library), and one for earlier Mac OS X (the legacy library). This is the + * preferred way to deploy the libraries. The legacy naming is for the users that don't want to + * mess around with libraries and classloaders. They can simply supply make sure that lwjgl.jar + * is in the classpath and that both the default library and the legacy library is in the native + * library path (java.library.path). + */ + if (LWJGLUtil.isMacOSXEqualsOrBetterThan(10, 4)) + return super.getNativeLibraryNames(); + else + return new String[]{LIBRARY_NAME + "-legacy", LIBRARY_NAME}; + } + public boolean openURL(String url) { try { Method openURL_method = (Method)AccessController.doPrivileged(new PrivilegedExceptionAction() { diff --git a/src/java/org/lwjgl/Sys.java b/src/java/org/lwjgl/Sys.java index a9b10904..6fd123c7 100644 --- a/src/java/org/lwjgl/Sys.java +++ b/src/java/org/lwjgl/Sys.java @@ -54,20 +54,31 @@ public final class Sys { /** Current version of library */ private static final String VERSION = "0.99"; - /** The native library name */ - private static final String LIBRARY_NAME = "lwjgl"; - /** The implementation instance to delegate platform specific behavior to */ private final static SysImplementation implementation; - static { - implementation = createImplementation(); + private static void loadLibrary(final String name) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { - System.loadLibrary(LIBRARY_NAME); + System.loadLibrary(name); return null; } }); + } + + static { + implementation = createImplementation(); + String[] library_names = implementation.getNativeLibraryNames(); + UnsatisfiedLinkError last_load_error = null; + for (int i = 0; i < library_names.length; i++) { + try { + loadLibrary(library_names[i]); + } catch (UnsatisfiedLinkError e) { + last_load_error = e; + } + } + if (last_load_error != null) + throw last_load_error; String native_version = implementation.getNativeLibraryVersion(); if (!native_version.equals(getVersion())) throw new LinkageError("Version mismatch: jar version is '" + getVersion() + diff --git a/src/java/org/lwjgl/SysImplementation.java b/src/java/org/lwjgl/SysImplementation.java index 4299c4b4..bb113800 100644 --- a/src/java/org/lwjgl/SysImplementation.java +++ b/src/java/org/lwjgl/SysImplementation.java @@ -41,6 +41,12 @@ package org.lwjgl; * @version $Revision$ */ interface SysImplementation { + /** + * Return an array of possible library names. later names + * tried last. + */ + public String[] getNativeLibraryNames(); + /** * Return the version of the native library */ diff --git a/src/java/org/lwjgl/opengl/MacOSXDisplay.java b/src/java/org/lwjgl/opengl/MacOSXDisplay.java index 7ecc2a66..97f382f8 100644 --- a/src/java/org/lwjgl/opengl/MacOSXDisplay.java +++ b/src/java/org/lwjgl/opengl/MacOSXDisplay.java @@ -283,28 +283,10 @@ final class MacOSXDisplay implements DisplayImplementation { * when the OS version is 10.3 or lower. */ private void hideUI(boolean hide) { - if (!isMacOSXEqualsOrBetterThan(10, 4)) + if (!LWJGLUtil.isMacOSXEqualsOrBetterThan(10, 4)) nHideUI(hide); } - private static boolean isMacOSXEqualsOrBetterThan(int major_required, int minor_required) { - String os_version = System.getProperty("os.version"); - StringTokenizer version_tokenizer = new StringTokenizer(os_version, "."); - int major; - int minor; - try { - String major_str = version_tokenizer.nextToken(); - String minor_str = version_tokenizer.nextToken(); - major = Integer.parseInt(major_str); - minor = Integer.parseInt(minor_str); - } catch (Exception e) { - LWJGLUtil.log("Exception occurred while trying to determine OS version: " + e); - // Best guess, no - return false; - } - return major > major_required || (major == major_required && minor >= minor_required); - } - private native void nHideUI(boolean hide); native void getMouseDeltas(IntBuffer delta_buffer); @@ -360,7 +342,7 @@ final class MacOSXDisplay implements DisplayImplementation { private native void nGrabMouse(boolean grab); public int getNativeCursorCapabilities() { - if (isMacOSXEqualsOrBetterThan(10, 4)) { + if (LWJGLUtil.isMacOSXEqualsOrBetterThan(10, 4)) { int cursor_colors = Toolkit.getDefaultToolkit().getMaximumCursorColors(); boolean supported = cursor_colors >= Short.MAX_VALUE && getMaxCursorSize() > 0; int caps = supported ? org.lwjgl.input.Cursor.CURSOR_8_BIT_ALPHA | org.lwjgl.input.Cursor.CURSOR_ONE_BIT_TRANSPARENCY: 0; @@ -455,7 +437,7 @@ final class MacOSXDisplay implements DisplayImplementation { } public int getPbufferCapabilities() { - if (isMacOSXEqualsOrBetterThan(10, 3)) + if (LWJGLUtil.isMacOSXEqualsOrBetterThan(10, 3)) return Pbuffer.PBUFFER_SUPPORTED; else return 0;