diff --git a/src/java/org/lwjgl/input/Cursor.java b/src/java/org/lwjgl/input/Cursor.java index e8c6e401..0e14b490 100644 --- a/src/java/org/lwjgl/input/Cursor.java +++ b/src/java/org/lwjgl/input/Cursor.java @@ -83,27 +83,29 @@ public class Cursor { * @throws LWJGLException if the cursor could not be created for any reason */ public Cursor(int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, IntBuffer delays) throws LWJGLException { - if ((getCapabilities() & CURSOR_ONE_BIT_TRANSPARENCY) == 0) - throw new LWJGLException("Native cursors not supported"); - BufferChecks.checkBuffer(images, width*height*numImages); - if (!Mouse.isCreated()) - throw new IllegalStateException("Mouse must be created before creating cursor objects"); - if (width*height*numImages > images.remaining()) - throw new IllegalArgumentException("width*height*numImages > images.remaining()"); - if (delays != null && numImages > delays.remaining()) - BufferChecks.checkBuffer(delays, numImages); - if (xHotspot >= width || xHotspot < 0) - throw new IllegalArgumentException("xHotspot > width || xHotspot < 0"); - if (yHotspot >= height || yHotspot < 0) - throw new IllegalArgumentException("yHotspot > height || yHotspot < 0"); - - Sys.initialize(); - - // Hmm - yHotspot = height - 1 - yHotspot; - - // create cursor (or cursors if multiple images supplied) - cursors = createCursors(width, height, xHotspot, yHotspot, numImages, images, delays); + synchronized (OpenGLPackageAccess.global_lock) { + if ((getCapabilities() & CURSOR_ONE_BIT_TRANSPARENCY) == 0) + throw new LWJGLException("Native cursors not supported"); + BufferChecks.checkBuffer(images, width*height*numImages); + if (!Mouse.isCreated()) + throw new IllegalStateException("Mouse must be created before creating cursor objects"); + if (width*height*numImages > images.remaining()) + throw new IllegalArgumentException("width*height*numImages > images.remaining()"); + if (delays != null && numImages > delays.remaining()) + BufferChecks.checkBuffer(delays, numImages); + if (xHotspot >= width || xHotspot < 0) + throw new IllegalArgumentException("xHotspot > width || xHotspot < 0"); + if (yHotspot >= height || yHotspot < 0) + throw new IllegalArgumentException("yHotspot > height || yHotspot < 0"); + + Sys.initialize(); + + // Hmm + yHotspot = height - 1 - yHotspot; + + // create cursor (or cursors if multiple images supplied) + cursors = createCursors(width, height, xHotspot, yHotspot, numImages, images, delays); + } } /** @@ -114,9 +116,11 @@ public class Cursor { * @return the maximum size of a native cursor */ public static int getMinCursorSize() { - if (!Mouse.isCreated()) - throw new IllegalStateException("Mouse must be created."); - return Mouse.getImplementation().getMinCursorSize(); + synchronized (OpenGLPackageAccess.global_lock) { + if (!Mouse.isCreated()) + throw new IllegalStateException("Mouse must be created."); + return Mouse.getImplementation().getMinCursorSize(); + } } /** @@ -127,9 +131,11 @@ public class Cursor { * @return the maximum size of a native cursor */ public static int getMaxCursorSize() { - if (!Mouse.isCreated()) - throw new IllegalStateException("Mouse must be created."); - return Mouse.getImplementation().getMaxCursorSize(); + synchronized (OpenGLPackageAccess.global_lock) { + if (!Mouse.isCreated()) + throw new IllegalStateException("Mouse must be created."); + return Mouse.getImplementation().getMaxCursorSize(); + } } /** @@ -141,10 +147,12 @@ public class Cursor { * @return A bit mask with native cursor capabilities. */ public static int getCapabilities() { - if (Mouse.getImplementation() != null) - return Mouse.getImplementation().getNativeCursorCapabilities(); - else - return Mouse.createImplementation().getNativeCursorCapabilities(); + synchronized (OpenGLPackageAccess.global_lock) { + if (Mouse.getImplementation() != null) + return Mouse.getImplementation().getNativeCursorCapabilities(); + else + return OpenGLPackageAccess.createImplementation().getNativeCursorCapabilities(); + } } /** @@ -247,19 +255,21 @@ public class Cursor { * OS cursor) */ public void destroy() { - if (destroyed) - return; - if (Mouse.getNativeCursor() == this) { - try { - Mouse.setNativeCursor(null); - } catch (LWJGLException e) { - // ignore + synchronized (OpenGLPackageAccess.global_lock) { + if (destroyed) + return; + if (Mouse.getNativeCursor() == this) { + try { + Mouse.setNativeCursor(null); + } catch (LWJGLException e) { + // ignore + } } + for(int i=0; i @@ -152,7 +147,9 @@ public class Mouse { * @return the currently bound native cursor, if any. */ public static synchronized Cursor getNativeCursor() { - return currentCursor; + synchronized (OpenGLPackageAccess.global_lock) { + return currentCursor; + } } /** @@ -167,19 +164,21 @@ public class Mouse { * @throws LWJGLException if the cursor could not be set for any reason */ public static synchronized Cursor setNativeCursor(Cursor cursor) throws LWJGLException { - if ((Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) == 0) - throw new IllegalStateException("Mouse doesn't support native cursors"); - Cursor oldCursor = currentCursor; - currentCursor = cursor; - if (isCreated()) { - if (currentCursor != null) { - implementation.setNativeCursor(currentCursor.getHandle()); - currentCursor.setTimeout(); - } else { - implementation.setNativeCursor(null); + synchronized (OpenGLPackageAccess.global_lock) { + if ((Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) == 0) + throw new IllegalStateException("Mouse doesn't support native cursors"); + Cursor oldCursor = currentCursor; + currentCursor = cursor; + if (isCreated()) { + if (currentCursor != null) { + implementation.setNativeCursor(currentCursor.getHandle()); + currentCursor.setTimeout(); + } else { + implementation.setNativeCursor(null); + } } + return oldCursor; } - return oldCursor; } /** @@ -192,12 +191,14 @@ public class Mouse { * to the window origin. */ public static synchronized void setCursorPosition(int new_x, int new_y) { - if (!isCreated()) - throw new IllegalStateException("Mouse is not created"); - x = event_x = new_x; - y = event_y = new_y; - if (!isGrabbed() && (Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) != 0) - implementation.setCursorPosition(x, y); + synchronized (OpenGLPackageAccess.global_lock) { + if (!isCreated()) + throw new IllegalStateException("Mouse is not created"); + x = event_x = new_x; + y = event_y = new_y; + if (!isGrabbed() && (Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) != 0) + implementation.setCursorPosition(x, y); + } } /** @@ -225,23 +226,6 @@ public class Mouse { return implementation; } - static InputImplementation createImplementation() { - /* Use reflection since we can't make Display.getImplementation - * public - */ - try { - return (InputImplementation)AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - Method getImplementation_method = Display.class.getDeclaredMethod("getImplementation", null); - getImplementation_method.setAccessible(true); - return getImplementation_method.invoke(null, null); - } - }); - } catch (PrivilegedActionException e) { - throw new Error(e); - } - } - /** * "Create" the mouse with the given custom implementation. This is used * reflectively by AWTInputAdapter. @@ -277,28 +261,34 @@ public class Mouse { * @throws LWJGLException if the mouse could not be created for any reason */ public static synchronized void create() throws LWJGLException { - if (!Display.isCreated()) throw new IllegalStateException("Display must be created."); + synchronized (OpenGLPackageAccess.global_lock) { + if (!Display.isCreated()) throw new IllegalStateException("Display must be created."); - create(createImplementation()); + create(OpenGLPackageAccess.createImplementation()); + } } /** * @return true if the mouse has been created */ public static synchronized boolean isCreated() { - return created; + synchronized (OpenGLPackageAccess.global_lock) { + return created; + } } /** * "Destroy" the mouse. */ public static synchronized void destroy() { - if (!created) return; - created = false; - buttons = null; - coord_buffer = null; - - implementation.destroyMouse(); + synchronized (OpenGLPackageAccess.global_lock) { + if (!created) return; + created = false; + buttons = null; + coord_buffer = null; + + implementation.destroyMouse(); + } } /** @@ -323,30 +313,32 @@ public class Mouse { * @see org.lwjgl.input.Mouse#getDWheel() */ public static synchronized void poll() { - if (!created) throw new IllegalStateException("Mouse must be created before you can poll it"); - implementation.pollMouse(coord_buffer, buttons); + synchronized (OpenGLPackageAccess.global_lock) { + if (!created) throw new IllegalStateException("Mouse must be created before you can poll it"); + implementation.pollMouse(coord_buffer, buttons); - /* If we're grabbed, poll returns mouse deltas, if not it returns absolute coordinates */ - int poll_coord1 = coord_buffer.get(0); - int poll_coord2 = coord_buffer.get(1); - /* The wheel is always relative */ - int poll_dwheel = coord_buffer.get(2); + /* If we're grabbed, poll returns mouse deltas, if not it returns absolute coordinates */ + int poll_coord1 = coord_buffer.get(0); + int poll_coord2 = coord_buffer.get(1); + /* The wheel is always relative */ + int poll_dwheel = coord_buffer.get(2); - if (isGrabbed()) { - dx += poll_coord1; - dy += poll_coord2; - x += poll_coord1; - y += poll_coord2; - } else { - dx = poll_coord1 - x; - dy = poll_coord2 - y; - x = poll_coord1; - y = poll_coord2; + if (isGrabbed()) { + dx += poll_coord1; + dy += poll_coord2; + x += poll_coord1; + y += poll_coord2; + } else { + dx = poll_coord1 - x; + dy = poll_coord2 - y; + x = poll_coord1; + y = poll_coord2; + } + x = Math.min(implementation.getWidth() - 1, Math.max(0, x)); + y = Math.min(implementation.getHeight() - 1, Math.max(0, y)); + dwheel += poll_dwheel; + read(); } - x = Math.min(implementation.getWidth() - 1, Math.max(0, x)); - y = Math.min(implementation.getHeight() - 1, Math.max(0, y)); - dwheel += poll_dwheel; - read(); } private static void read() { @@ -362,11 +354,13 @@ public class Mouse { * @return true if the specified button is down */ public static synchronized boolean isButtonDown(int button) { - if (!created) throw new IllegalStateException("Mouse must be created before you can poll the button state"); - if (button >= buttonCount || button < 0) - return false; - else - return buttons.get(button) == 1; + synchronized (OpenGLPackageAccess.global_lock) { + if (!created) throw new IllegalStateException("Mouse must be created before you can poll the button state"); + if (button >= buttonCount || button < 0) + return false; + else + return buttons.get(button) == 1; + } } /** @@ -375,10 +369,12 @@ public class Mouse { * @return a String with the button's human readable name in it or null if the button is unnamed */ public static synchronized String getButtonName(int button) { - if (button >= buttonName.length || button < 0) - return null; - else - return buttonName[button]; + synchronized (OpenGLPackageAccess.global_lock) { + if (button >= buttonName.length || button < 0) + return null; + else + return buttonName[button]; + } } /** @@ -386,11 +382,13 @@ public class Mouse { * @param buttonName The button name */ public static synchronized int getButtonIndex(String buttonName) { - Integer ret = (Integer) buttonMap.get(buttonName); - if (ret == null) - return -1; - else - return ret.intValue(); + synchronized (OpenGLPackageAccess.global_lock) { + Integer ret = (Integer) buttonMap.get(buttonName); + if (ret == null) + return -1; + else + return ret.intValue(); + } } /** @@ -403,37 +401,41 @@ public class Mouse { * @return true if a mouse event was read, false otherwise */ public static synchronized boolean next() { - if (!created) throw new IllegalStateException("Mouse must be created before you can read events"); - if (readBuffer.hasRemaining()) { - eventButton = readBuffer.get(); - eventState = readBuffer.get() != 0; - if (isGrabbed()) { - event_dx = readBuffer.getInt(); - event_dy = readBuffer.getInt(); - event_x += event_dx; - event_y += event_dy; - } else { - int new_event_x = readBuffer.getInt(); - int new_event_y = readBuffer.getInt(); - event_dx = new_event_x - event_x; - event_dy = new_event_y - event_y; - event_x = new_event_x; - event_y = new_event_y; - } - event_x = Math.min(implementation.getWidth() - 1, Math.max(0, event_x)); - event_y = Math.min(implementation.getHeight() - 1, Math.max(0, event_y)); - event_dwheel = readBuffer.getInt(); - event_nanos = readBuffer.getLong(); - return true; - } else - return false; + synchronized (OpenGLPackageAccess.global_lock) { + if (!created) throw new IllegalStateException("Mouse must be created before you can read events"); + if (readBuffer.hasRemaining()) { + eventButton = readBuffer.get(); + eventState = readBuffer.get() != 0; + if (isGrabbed()) { + event_dx = readBuffer.getInt(); + event_dy = readBuffer.getInt(); + event_x += event_dx; + event_y += event_dy; + } else { + int new_event_x = readBuffer.getInt(); + int new_event_y = readBuffer.getInt(); + event_dx = new_event_x - event_x; + event_dy = new_event_y - event_y; + event_x = new_event_x; + event_y = new_event_y; + } + event_x = Math.min(implementation.getWidth() - 1, Math.max(0, event_x)); + event_y = Math.min(implementation.getHeight() - 1, Math.max(0, event_y)); + event_dwheel = readBuffer.getInt(); + event_nanos = readBuffer.getLong(); + return true; + } else + return false; + } } /** * @return Current events button. Returns -1 if no button state was changed */ public static synchronized int getEventButton() { - return eventButton; + synchronized (OpenGLPackageAccess.global_lock) { + return eventButton; + } } /** @@ -441,42 +443,54 @@ public class Mouse { * @return Current events button state. */ public static synchronized boolean getEventButtonState() { - return eventState; + synchronized (OpenGLPackageAccess.global_lock) { + return eventState; + } } /** * @return Current events delta x. Only valid when the mouse is grabbed. */ public static synchronized int getEventDX() { - return event_dx; + synchronized (OpenGLPackageAccess.global_lock) { + return event_dx; + } } /** * @return Current events delta y. Only valid when the mouse is grabbed. */ public static synchronized int getEventDY() { - return event_dy; + synchronized (OpenGLPackageAccess.global_lock) { + return event_dy; + } } /** * @return Current events absolute x. Only valid when the mouse is not grabbed. */ public static synchronized int getEventX() { - return event_x; + synchronized (OpenGLPackageAccess.global_lock) { + return event_x; + } } /** * @return Current events absolute y. Only valid when the mouse is not grabbed. */ public static synchronized int getEventY() { - return event_y; + synchronized (OpenGLPackageAccess.global_lock) { + return event_y; + } } /** * @return Current events delta z */ public static synchronized int getEventDWheel() { - return event_dwheel; + synchronized (OpenGLPackageAccess.global_lock) { + return event_dwheel; + } } /** @@ -488,7 +502,9 @@ public class Mouse { * @return The time in nanoseconds of the current event */ public static synchronized long getEventNanoseconds() { - return event_nanos; + synchronized (OpenGLPackageAccess.global_lock) { + return event_nanos; + } } /** @@ -498,7 +514,9 @@ public class Mouse { * @return Absolute x axis position of mouse */ public static synchronized int getX() { - return x; + synchronized (OpenGLPackageAccess.global_lock) { + return x; + } } /** @@ -508,55 +526,69 @@ public class Mouse { * @return Absolute y axis position of mouse */ public static synchronized int getY() { - return y; + synchronized (OpenGLPackageAccess.global_lock) { + return y; + } } /** * @return Movement on the x axis since last time getDX() was called. Only valid when the mouse is grabbed. */ public static synchronized int getDX() { - int result = dx; - dx = 0; - return result; + synchronized (OpenGLPackageAccess.global_lock) { + int result = dx; + dx = 0; + return result; + } } /** * @return Movement on the y axis since last time getDY() was called. Only valid when the mouse is grabbed. */ public static synchronized int getDY() { - int result = dy; - dy = 0; - return result; + synchronized (OpenGLPackageAccess.global_lock) { + int result = dy; + dy = 0; + return result; + } } /** * @return Movement of the wheel since last time getDWheel() was called */ public static synchronized int getDWheel() { - int result = dwheel; - dwheel = 0; - return result; + synchronized (OpenGLPackageAccess.global_lock) { + int result = dwheel; + dwheel = 0; + return result; + } } /** * @return Number of buttons on this mouse */ public static synchronized int getButtonCount() { - return buttonCount; + synchronized (OpenGLPackageAccess.global_lock) { + return buttonCount; + } } /** * @return Whether or not this mouse has wheel support */ public static synchronized boolean hasWheel() { - return hasWheel; + synchronized (OpenGLPackageAccess.global_lock) { + return hasWheel; + } } /** * @return whether or not the mouse has grabbed the cursor */ public static synchronized boolean isGrabbed() { - return isGrabbed; + synchronized (OpenGLPackageAccess.global_lock) { + return isGrabbed; + } } /** @@ -568,14 +600,16 @@ public class Mouse { * @param grab whether the mouse should be grabbed */ public static synchronized void setGrabbed(boolean grab) { - isGrabbed = grab; - if (isCreated()) { - implementation.grabMouse(isGrabbed); - // Get latest values from native side - poll(); - event_x = x; - event_y = y; - resetMouse(); + synchronized (OpenGLPackageAccess.global_lock) { + isGrabbed = grab; + if (isCreated()) { + implementation.grabMouse(isGrabbed); + // Get latest values from native side + poll(); + event_x = x; + event_y = y; + resetMouse(); + } } } @@ -585,12 +619,14 @@ public class Mouse { * shouldn't be called otherwise */ public static synchronized void updateCursor() { - if (emulateCursorAnimation && currentCursor != null && currentCursor.hasTimedOut()) { - currentCursor.nextCursor(); - try { - setNativeCursor(currentCursor); - } catch (LWJGLException e) { - if (LWJGLUtil.DEBUG) e.printStackTrace(); + synchronized (OpenGLPackageAccess.global_lock) { + if (emulateCursorAnimation && currentCursor != null && currentCursor.hasTimedOut()) { + currentCursor.nextCursor(); + try { + setNativeCursor(currentCursor); + } catch (LWJGLException e) { + if (LWJGLUtil.DEBUG) e.printStackTrace(); + } } } } diff --git a/src/java/org/lwjgl/input/OpenGLPackageAccess.java b/src/java/org/lwjgl/input/OpenGLPackageAccess.java new file mode 100644 index 00000000..d8edaab7 --- /dev/null +++ b/src/java/org/lwjgl/input/OpenGLPackageAccess.java @@ -0,0 +1,49 @@ +package org.lwjgl.input; + +import org.lwjgl.opengl.InputImplementation; +import org.lwjgl.opengl.Display; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; + +/** + * This class contains utilities for accessing the org.lwjgl.opengl + * package through (privileged) reflection. + */ +final class OpenGLPackageAccess { + final static Object global_lock; + + static { + try { + global_lock = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + Field lock_field = Class.forName("org.lwjgl.opengl.GlobalLock").getDeclaredField("lock"); + lock_field.setAccessible(true); + return lock_field.get(null); + } + }); + } catch (PrivilegedActionException e) { + throw new Error(e); + } + } + + static InputImplementation createImplementation() { + /* Use reflection since we can't make Display.getImplementation + * public + */ + try { + return (InputImplementation)AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + Method getImplementation_method = Display.class.getDeclaredMethod("getImplementation", null); + getImplementation_method.setAccessible(true); + return getImplementation_method.invoke(null, null); + } + }); + } catch (PrivilegedActionException e) { + throw new Error(e); + } + } +} diff --git a/src/java/org/lwjgl/opengl/Display.java b/src/java/org/lwjgl/opengl/Display.java index d7e34276..08200ebe 100644 --- a/src/java/org/lwjgl/opengl/Display.java +++ b/src/java/org/lwjgl/opengl/Display.java @@ -102,6 +102,9 @@ public final class Display { private static PeerInfo peer_info; private static Context context; + /** The Drawable instance that tracks the current Display context */ + private final static Drawable drawable; + private static boolean window_created = false; static { @@ -113,23 +116,22 @@ public final class Display { } catch (LWJGLException e) { throw new RuntimeException(e); } + drawable = new Drawable() { + public Context getContext() { + synchronized (GlobalLock.lock) { + return isCreated() ? context : null; + } + } + }; } /** * Fetch the Drawable from the Display. * - * @return the Drawable corresponding to the Display context, or null if display is - * not created. + * @return the Drawable corresponding to the Display context */ public static Drawable getDrawable() { - if (context != null) { - return new Drawable() { - public Context getContext() { - return context; - } - }; - } else - return null; + return drawable; } private static DisplayImplementation createDisplayImplementation() { @@ -167,22 +169,24 @@ public final class Display { * @return an array of all display modes the system reckons it can handle. */ public static DisplayMode[] getAvailableDisplayModes() throws LWJGLException { - DisplayMode[] unfilteredModes = display_impl.getAvailableDisplayModes(); + synchronized (GlobalLock.lock) { + DisplayMode[] unfilteredModes = display_impl.getAvailableDisplayModes(); - if (unfilteredModes == null) { - return new DisplayMode[0]; + if (unfilteredModes == null) { + return new DisplayMode[0]; + } + + // We'll use a HashSet to filter out the duplicated modes + HashSet modes = new HashSet(unfilteredModes.length); + + modes.addAll(Arrays.asList(unfilteredModes)); + DisplayMode[] filteredModes = new DisplayMode[modes.size()]; + modes.toArray(filteredModes); + + LWJGLUtil.log("Removed " + (unfilteredModes.length - filteredModes.length) + " duplicate displaymodes"); + + return filteredModes; } - - // We'll use a HashSet to filter out the duplicated modes - HashSet modes = new HashSet(unfilteredModes.length); - - modes.addAll(Arrays.asList(unfilteredModes)); - DisplayMode[] filteredModes = new DisplayMode[modes.size()]; - modes.toArray(filteredModes); - - LWJGLUtil.log("Removed " + (unfilteredModes.length - filteredModes.length) + " duplicate displaymodes"); - - return filteredModes; } /** @@ -190,7 +194,9 @@ public final class Display { * @return The current display mode */ public static DisplayMode getDisplayMode() { - return current_mode; + synchronized (GlobalLock.lock) { + return current_mode; + } } /** @@ -204,24 +210,26 @@ public final class Display { * @throws LWJGLException if the display mode could not be set */ public static void setDisplayMode(DisplayMode mode) throws LWJGLException { - if (mode == null) - throw new NullPointerException("mode must be non-null"); - current_mode = mode; - if (isCreated()) { - destroyWindow(); - // If mode is not fullscreen capable, make sure we are in windowed mode - if (!mode.isFullscreen()) - resetFullscreen(); - try { - if (fullscreen) - switchDisplayMode(); - createWindow(); - makeCurrent(); - } catch (LWJGLException e) { - destroyContext(); - destroyPeerInfo(); - display_impl.resetDisplayMode(); - throw e; + synchronized (GlobalLock.lock) { + if (mode == null) + throw new NullPointerException("mode must be non-null"); + current_mode = mode; + if (isCreated()) { + destroyWindow(); + // If mode is not fullscreen capable, make sure we are in windowed mode + if (!mode.isFullscreen()) + resetFullscreen(); + try { + if (fullscreen) + switchDisplayMode(); + createWindow(); + makeCurrent(); + } catch (LWJGLException e) { + destroyContext(); + destroyPeerInfo(); + display_impl.resetDisplayMode(); + throw e; + } } } } @@ -304,35 +312,37 @@ public final class Display { * @param contrast The contrast, larger than 0.0. */ public static void setDisplayConfiguration(float gamma, float brightness, float contrast) throws LWJGLException { - if (!isCreated()) { - throw new LWJGLException("Display not yet created."); + synchronized (GlobalLock.lock) { + if (!isCreated()) { + throw new LWJGLException("Display not yet created."); + } + if (brightness < -1.0f || brightness > 1.0f) + throw new IllegalArgumentException("Invalid brightness value"); + if (contrast < 0.0f) + throw new IllegalArgumentException("Invalid contrast value"); + int rampSize = display_impl.getGammaRampLength(); + if (rampSize == 0) { + throw new LWJGLException("Display configuration not supported"); + } + FloatBuffer gammaRamp = BufferUtils.createFloatBuffer(rampSize); + for (int i = 0; i < rampSize; i++) { + float intensity = (float)i/(rampSize - 1); + // apply gamma + float rampEntry = (float)java.lang.Math.pow(intensity, gamma); + // apply brightness + rampEntry += brightness; + // apply contrast + rampEntry = (rampEntry - 0.5f)*contrast + 0.5f; + // Clamp entry to [0, 1] + if (rampEntry > 1.0f) + rampEntry = 1.0f; + else if (rampEntry < 0.0f) + rampEntry = 0.0f; + gammaRamp.put(i, rampEntry); + } + display_impl.setGammaRamp(gammaRamp); + LWJGLUtil.log("Gamma set, gamma = " + gamma + ", brightness = " + brightness + ", contrast = " + contrast); } - if (brightness < -1.0f || brightness > 1.0f) - throw new IllegalArgumentException("Invalid brightness value"); - if (contrast < 0.0f) - throw new IllegalArgumentException("Invalid contrast value"); - int rampSize = display_impl.getGammaRampLength(); - if (rampSize == 0) { - throw new LWJGLException("Display configuration not supported"); - } - FloatBuffer gammaRamp = BufferUtils.createFloatBuffer(rampSize); - for (int i = 0; i < rampSize; i++) { - float intensity = (float)i/(rampSize - 1); - // apply gamma - float rampEntry = (float)java.lang.Math.pow(intensity, gamma); - // apply brightness - rampEntry += brightness; - // apply contrast - rampEntry = (rampEntry - 0.5f)*contrast + 0.5f; - // Clamp entry to [0, 1] - if (rampEntry > 1.0f) - rampEntry = 1.0f; - else if (rampEntry < 0.0f) - rampEntry = 0.0f; - gammaRamp.put(i, rampEntry); - } - display_impl.setGammaRamp(gammaRamp); - LWJGLUtil.log("Gamma set, gamma = " + gamma + ", brightness = " + brightness + ", contrast = " + contrast); } /** @@ -342,14 +352,16 @@ public final class Display { * @param fps The desired frame rate, in frames per second */ public static void sync3(int fps) { - float frameTime = 1.0f / (fps > 1 ? fps - 1 : 1); - timeNow = Sys.getTime(); - while (timeNow > timeThen && (float) (timeNow - timeThen) / (float) Sys.getTimerResolution() < frameTime) { - // This is a system-friendly way of allowing other stuff to use CPU if it wants to - Thread.yield(); + synchronized (GlobalLock.lock) { + float frameTime = 1.0f / (fps > 1 ? fps - 1 : 1); timeNow = Sys.getTime(); + while (timeNow > timeThen && (float) (timeNow - timeThen) / (float) Sys.getTimerResolution() < frameTime) { + // This is a system-friendly way of allowing other stuff to use CPU if it wants to + Thread.yield(); + timeNow = Sys.getTime(); + } + timeThen = timeNow; } - timeThen = timeNow; } private static long timeLate; @@ -360,20 +372,22 @@ public final class Display { * @param fps The desired frame rate, in frames per second */ public static void sync2(int fps) { - long gapTo = Sys.getTimerResolution() / fps + timeThen; - timeNow = Sys.getTime(); - - while (gapTo > timeNow + timeLate) { - Thread.yield(); + synchronized (GlobalLock.lock) { + long gapTo = Sys.getTimerResolution() / fps + timeThen; timeNow = Sys.getTime(); + + while (gapTo > timeNow + timeLate) { + Thread.yield(); + timeNow = Sys.getTime(); + } + + if (gapTo < timeNow) + timeLate = timeNow - gapTo; + else + timeLate = 0; + + timeThen = timeNow; } - - if (gapTo < timeNow) - timeLate = timeNow - gapTo; - else - timeLate = 0; - - timeThen = timeNow; } /** @@ -382,23 +396,25 @@ public final class Display { * @param fps The desired frame rate, in frames per second */ public static void sync(int fps) { - long gapTo = Sys.getTimerResolution() / fps + timeThen; - timeNow = Sys.getTime(); - - while (gapTo > timeNow + timeLate) { - try { - Thread.sleep(1); - } catch (InterruptedException e) { - } + synchronized (GlobalLock.lock) { + long gapTo = Sys.getTimerResolution() / fps + timeThen; timeNow = Sys.getTime(); + + while (gapTo > timeNow + timeLate) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + } + timeNow = Sys.getTime(); + } + + if (gapTo < timeNow) + timeLate = timeNow - gapTo; + else + timeLate = 0; + + timeThen = timeNow; } - - if (gapTo < timeNow) - timeLate = timeNow - gapTo; - else - timeLate = 0; - - timeThen = timeNow; } /** @@ -420,13 +436,17 @@ public final class Display { * @return the title of the window */ public static String getTitle() { - return title; + synchronized (GlobalLock.lock) { + return title; + } } private static void resetFullscreen() { - if (Display.fullscreen) { - Display.fullscreen = false; - display_impl.resetDisplayMode(); + synchronized (GlobalLock.lock) { + if (Display.fullscreen) { + Display.fullscreen = false; + display_impl.resetDisplayMode(); + } } } @@ -442,24 +462,26 @@ public final class Display { * from getAvailableDisplayModes() or if the mode switch fails. */ public static void setFullscreen(boolean fullscreen) throws LWJGLException { - if (Display.fullscreen != fullscreen) { - Display.fullscreen = fullscreen; - if (!isCreated()) - return; - destroyWindow(); - try { - if (fullscreen) { - switchDisplayMode(); - } else { + synchronized (GlobalLock.lock) { + if (Display.fullscreen != fullscreen) { + Display.fullscreen = fullscreen; + if (!isCreated()) + return; + destroyWindow(); + try { + if (fullscreen) { + switchDisplayMode(); + } else { + display_impl.resetDisplayMode(); + } + createWindow(); + makeCurrent(); + } catch (LWJGLException e) { + destroyContext(); + destroyPeerInfo(); display_impl.resetDisplayMode(); + throw e; } - createWindow(); - makeCurrent(); - } catch (LWJGLException e) { - destroyContext(); - destroyPeerInfo(); - display_impl.resetDisplayMode(); - throw e; } } } @@ -468,7 +490,9 @@ public final class Display { * @return whether the Display is in fullscreen mode */ public static boolean isFullscreen() { - return fullscreen; + synchronized (GlobalLock.lock) { + return fullscreen; + } } /** @@ -476,42 +500,50 @@ public final class Display { * @param newTitle The new window title */ public static void setTitle(String newTitle) { - if (newTitle == null) { - newTitle = ""; + synchronized (GlobalLock.lock) { + if (newTitle == null) { + newTitle = ""; + } + title = newTitle; + if (isCreated()) + display_impl.setTitle(title); } - title = newTitle; - if (isCreated()) - display_impl.setTitle(title); } /** * @return true if the user or operating system has asked the window to close */ public static boolean isCloseRequested() { - if (!isCreated()) - throw new IllegalStateException("Cannot determine close requested state of uncreated window"); - display_impl.update(); - return display_impl.isCloseRequested(); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Cannot determine close requested state of uncreated window"); + display_impl.update(); + return display_impl.isCloseRequested(); + } } /** * @return true if the window is visible, false if not */ public static boolean isVisible() { - if (!isCreated()) - throw new IllegalStateException("Cannot determine minimized state of uncreated window"); - display_impl.update(); - return display_impl.isVisible(); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Cannot determine minimized state of uncreated window"); + display_impl.update(); + return display_impl.isVisible(); + } } /** * @return true if window is active, that is, the foreground display of the operating system. */ public static boolean isActive() { - if (!isCreated()) - throw new IllegalStateException("Cannot determine focused state of uncreated window"); - display_impl.update(); - return display_impl.isActive(); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Cannot determine focused state of uncreated window"); + display_impl.update(); + return display_impl.isActive(); + } } /** @@ -525,10 +557,12 @@ public final class Display { * and needs to repaint itself */ public static boolean isDirty() { - if (!isCreated()) - throw new IllegalStateException("Cannot determine dirty state of uncreated window"); - display_impl.update(); - return display_impl.isDirty(); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Cannot determine dirty state of uncreated window"); + display_impl.update(); + return display_impl.isDirty(); + } } /** @@ -537,10 +571,12 @@ public final class Display { * the application. */ public static void processMessages() { - if (!isCreated()) - throw new IllegalStateException("Display not created"); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Display not created"); - display_impl.update(); + display_impl.update(); + } } /** @@ -549,11 +585,13 @@ public final class Display { * @throws OpenGLException if an OpenGL error has occured since the last call to GL11.glGetError() */ public static void swapBuffers() throws LWJGLException { - if (!isCreated()) - throw new IllegalStateException("Display not created"); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Display not created"); - Util.checkGLError(); - Context.swapBuffers(); + Util.checkGLError(); + Context.swapBuffers(); + } } /** @@ -562,20 +600,22 @@ public final class Display { * @throws OpenGLException if an OpenGL error has occured since the last call to GL11.glGetError() */ public static void update() { - if (!isCreated()) - throw new IllegalStateException("Display not created"); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Display not created"); - // We paint only when the window is visible or dirty - if (isVisible() || isDirty()) { - try { - swapBuffers(); - } catch (LWJGLException e) { - throw new RuntimeException(e); + // We paint only when the window is visible or dirty + if (isVisible() || isDirty()) { + try { + swapBuffers(); + } catch (LWJGLException e) { + throw new RuntimeException(e); + } } - } - processMessages(); - pollDevices(); + processMessages(); + pollDevices(); + } } static void pollDevices() { @@ -600,10 +640,12 @@ public final class Display { * @throws LWJGLException If the context could not be released */ public static void releaseContext() throws LWJGLException { - if (!isCreated()) - throw new IllegalStateException("Display is not created"); - if (context.isCurrent()) - Context.releaseCurrentContext(); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Display is not created"); + if (context.isCurrent()) + Context.releaseCurrentContext(); + } } /** @@ -612,9 +654,11 @@ public final class Display { * @throws LWJGLException If the context could not be made current */ public static void makeCurrent() throws LWJGLException { - if (!isCreated()) - throw new IllegalStateException("Display is not created"); - context.makeCurrent(); + synchronized (GlobalLock.lock) { + if (!isCreated()) + throw new IllegalStateException("Display is not created"); + context.makeCurrent(); + } } /** @@ -629,7 +673,9 @@ public final class Display { * @throws LWJGLException */ public static void create() throws LWJGLException { - create(new PixelFormat()); + synchronized (GlobalLock.lock) { + create(new PixelFormat()); + } } /** @@ -645,7 +691,9 @@ public final class Display { * @throws LWJGLException */ public static void create(PixelFormat pixel_format) throws LWJGLException { - create(pixel_format, null); + synchronized (GlobalLock.lock) { + create(pixel_format, null); + } } private static void removeShutdownHook() { @@ -680,38 +728,40 @@ public final class Display { * @throws LWJGLException */ public static void create(PixelFormat pixel_format, Drawable shared_drawable) throws LWJGLException { - if (isCreated()) - throw new IllegalStateException("Only one LWJGL context may be instantiated at any one time."); - if (pixel_format == null) - throw new NullPointerException("pixel_format cannot be null"); - removeShutdownHook(); - registerShutdownHook(); - if (fullscreen) - switchDisplayMode(); - try { - peer_info = display_impl.createPeerInfo(pixel_format); + synchronized (GlobalLock.lock) { + if (isCreated()) + throw new IllegalStateException("Only one LWJGL context may be instantiated at any one time."); + if (pixel_format == null) + throw new NullPointerException("pixel_format cannot be null"); + removeShutdownHook(); + registerShutdownHook(); + if (fullscreen) + switchDisplayMode(); try { - createWindow(); + peer_info = display_impl.createPeerInfo(pixel_format); try { - context = new Context(peer_info, shared_drawable != null ? shared_drawable.getContext() : null); + createWindow(); try { - makeCurrent(); - initContext(); + context = new Context(peer_info, shared_drawable != null ? shared_drawable.getContext() : null); + try { + makeCurrent(); + initContext(); + } catch (LWJGLException e) { + destroyContext(); + throw e; + } } catch (LWJGLException e) { - destroyContext(); + destroyWindow(); throw e; } } catch (LWJGLException e) { - destroyWindow(); + destroyPeerInfo(); throw e; } } catch (LWJGLException e) { - destroyPeerInfo(); + display_impl.resetDisplayMode(); throw e; } - } catch (LWJGLException e) { - display_impl.resetDisplayMode(); - throw e; } } @@ -779,17 +829,19 @@ public final class Display { * regardless of whether the Display was the current rendering context. */ public static void destroy() { - if (!isCreated()) { - return; - } + synchronized (GlobalLock.lock) { + if (!isCreated()) { + return; + } - destroyWindow(); - destroyContext(); - destroyPeerInfo(); - x = y = -1; - cached_icons = null; - reset(); - removeShutdownHook(); + destroyWindow(); + destroyContext(); + destroyPeerInfo(); + x = y = -1; + cached_icons = null; + reset(); + removeShutdownHook(); + } } private static void destroyPeerInfo() { @@ -819,7 +871,7 @@ public final class Display { /** * @return the unique Display context (or null, if the Display has not been created) */ - public static Context getContext() { + private static Context getContext() { return context; } @@ -827,7 +879,9 @@ public final class Display { * @return true if the window's native peer has been created */ public static boolean isCreated() { - return window_created; + synchronized (GlobalLock.lock) { + return window_created; + } } /** @@ -840,9 +894,11 @@ public final class Display { * @param sync true to synchronize; false to ignore synchronization */ public static void setSwapInterval(int value) { - swap_interval = value; - if (isCreated()) - Context.setSwapInterval(swap_interval); + synchronized (GlobalLock.lock) { + swap_interval = value; + if (isCreated()) + Context.setSwapInterval(swap_interval); + } } @@ -852,7 +908,9 @@ public final class Display { * @param sync true to synchronize; false to ignore synchronization */ public static void setVSyncEnabled(boolean sync) { - setSwapInterval(sync ? 1 : 0); + synchronized (GlobalLock.lock) { + setSwapInterval(sync ? 1 : 0); + } } /** @@ -864,19 +922,21 @@ public final class Display { * @param x The new window location on the x axis * @param y The new window location on the y axis */ - public static void setLocation(int x, int y) { - if (fullscreen) { - return; - } + public static void setLocation(int new_x, int new_y) { + synchronized (GlobalLock.lock) { + if (fullscreen) { + return; + } - // offset if already created - if(isCreated()) { - display_impl.reshape(x, y, current_mode.getWidth(), current_mode.getHeight()); - } + // cache position + x = new_x; + y = new_y; - // cache position - Display.x = x; - Display.y = y; + // offset if already created + if(isCreated()) { + display_impl.reshape(x, y, current_mode.getWidth(), current_mode.getHeight()); + } + } } /** @@ -885,7 +945,9 @@ public final class Display { * @return a String */ public static String getAdapter() { - return display_impl.getAdapter(); + synchronized (GlobalLock.lock) { + return display_impl.getAdapter(); + } } /** @@ -894,7 +956,9 @@ public final class Display { * @return a String */ public static String getVersion() { - return display_impl.getVersion(); + synchronized (GlobalLock.lock) { + return display_impl.getVersion(); + } } @@ -915,22 +979,23 @@ public final class Display { * @return number of icons used, or 0 if display hasn't been created */ public static int setIcon(ByteBuffer[] icons) { - - // make deep copy so we dont rely on the supplied buffers later on - // don't recache! - if(cached_icons != icons) { - cached_icons = new ByteBuffer[icons.length]; - for(int i=0;i