diff --git a/src/java/org/lwjgl/opengl/LinuxDisplay.java b/src/java/org/lwjgl/opengl/LinuxDisplay.java index 13e3bf88..e8967086 100644 --- a/src/java/org/lwjgl/opengl/LinuxDisplay.java +++ b/src/java/org/lwjgl/opengl/LinuxDisplay.java @@ -44,6 +44,7 @@ import java.nio.IntBuffer; import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; +import org.lwjgl.BufferUtils; import org.lwjgl.input.Keyboard; final class LinuxDisplay implements DisplayImplementation { @@ -78,6 +79,28 @@ final class LinuxDisplay implements DisplayImplementation { private static PeerInfo peer_info; + /** Saved gamma used to restore display settings */ + private static ByteBuffer saved_gamma; + private static ByteBuffer current_gamma; + + private static ByteBuffer getCurrentGammaRamp() throws LWJGLException { + lockAWT(); + try { + incDisplay(); + try { + if (isXF86VidModeSupported()) + return nGetCurrentGammaRamp(); + else + return BufferUtils.createByteBuffer(0); + } finally { + decDisplay(); + } + } finally { + unlockAWT(); + } + } + private static native ByteBuffer nGetCurrentGammaRamp() throws LWJGLException; + private static int getBestDisplayModeExtension() throws LWJGLException { lockAWT(); try { @@ -233,30 +256,55 @@ final class LinuxDisplay implements DisplayImplementation { public void resetDisplayMode() { lockAWT(); try { - nResetDisplayMode(current_displaymode_extension); + nResetDisplayMode(current_displaymode_extension, saved_gamma); } finally { unlockAWT(); } } - private static native void nResetDisplayMode(int extension); + private static native void nResetDisplayMode(int extension, ByteBuffer gamma_ramp); public int getGammaRampLength() { lockAWT(); - int length = nGetGammaRampLength(); - unlockAWT(); - return length; + try { + try { + incDisplay(); + int length; + if (isXF86VidModeSupported()) { + length = nGetGammaRampLength(); + } else + length = 0; + decDisplay(); + return length; + } catch (LWJGLException e) { + LWJGLUtil.log("Failed to get gamma ramp length: " + e); + return 0; + } + } finally { + unlockAWT(); + } } private static native int nGetGammaRampLength(); public void setGammaRamp(FloatBuffer gammaRamp) throws LWJGLException { lockAWT(); try { - nSetGammaRamp(gammaRamp); + incDisplay(); + boolean xf86_support = isXF86VidModeSupported(); + decDisplay(); + if (!xf86_support) + throw new LWJGLException("No gamma ramp support (Missing XF86VM extension)"); + current_gamma = convertToNativeRamp(gammaRamp); + nSetGammaRamp(current_gamma); } finally { unlockAWT(); } } - private static native void nSetGammaRamp(FloatBuffer gammaRamp) throws LWJGLException; + private static native void nSetGammaRamp(ByteBuffer gammaRamp) throws LWJGLException; + + private static ByteBuffer convertToNativeRamp(FloatBuffer ramp) throws LWJGLException { + return nConvertToNativeRamp(ramp, ramp.position(), ramp.remaining()); + } + private static native ByteBuffer nConvertToNativeRamp(FloatBuffer ramp, int offset, int length) throws LWJGLException; public String getAdapter() { return null; @@ -273,6 +321,8 @@ final class LinuxDisplay implements DisplayImplementation { if (current_displaymode_extension == NONE) throw new LWJGLException("No display mode extension is available"); DisplayMode mode = nInit(current_displaymode_extension); + saved_gamma = getCurrentGammaRamp(); + current_gamma = saved_gamma; return mode; } finally { unlockAWT(); @@ -327,10 +377,10 @@ final class LinuxDisplay implements DisplayImplementation { public void update() { lockAWT(); - nUpdate(current_displaymode_extension, current_window_mode); + nUpdate(current_displaymode_extension, current_window_mode, saved_gamma, current_gamma); unlockAWT(); } - private static native void nUpdate(int extension, int current_window_mode); + private static native void nUpdate(int extension, int current_window_mode, ByteBuffer saved_gamma, ByteBuffer current_gamma); public void reshape(int x, int y, int width, int height) { lockAWT(); diff --git a/src/native/linux/display.c b/src/native/linux/display.c index 82446923..a1c35fef 100644 --- a/src/native/linux/display.c +++ b/src/native/linux/display.c @@ -70,10 +70,6 @@ static int saved_freq; static int current_width; static int current_height; static int current_freq; -static int saved_gamma_ramp_length = 0; -static unsigned short *saved_ramp = NULL; -static unsigned short *current_ramp = NULL; -static int current_gamma_ramp_length = 0; int getScreenModeWidth(void) { return current_width; @@ -281,18 +277,8 @@ static bool setMode(JNIEnv *env, Display *disp, int screen, jint extension, int return result; } -static void freeSavedGammaRamps() { - free(saved_ramp); - saved_ramp = NULL; - saved_gamma_ramp_length = 0; -} - -static int getGammaRampLengthOfDisplay(JNIEnv *env, Display *disp, int screen) { +int getGammaRampLengthOfDisplay(JNIEnv *env, Display *disp, int screen) { int ramp_size; - if (!isXF86VidModeSupported(env, disp)) { - printfDebugJava(env, "XF86VidMode extension version >= 2 not found"); - return 0; - } if (XF86VidModeGetGammaRampSize(disp, screen, &ramp_size) == False) { printfDebugJava(env, "XF86VidModeGetGammaRampSize call failed"); return 0; @@ -300,15 +286,23 @@ static int getGammaRampLengthOfDisplay(JNIEnv *env, Display *disp, int screen) { return ramp_size; } -int getGammaRampLength(JNIEnv *env, int screen) { - Display *disp = XOpenDisplay(NULL); - if (disp == NULL) { - printfDebugJava(env, "Could not open display"); - return 0; +JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nConvertToNativeRamp(JNIEnv *env, jclass unused, jobject ramp_buffer, jint buffer_offset, jint length) { + const jfloat *ramp_ptr = (const jfloat *)(*env)->GetDirectBufferAddress(env, ramp_buffer) + buffer_offset; + jobject native_ramp = newJavaManagedByteBuffer(env, length*3*sizeof(unsigned short)); + if (native_ramp == NULL) { + throwException(env, "Failed to allocate gamma ramp buffer"); + return NULL; } - int length = getGammaRampLengthOfDisplay(env, disp, screen); - XCloseDisplay(disp); - return length; + unsigned short *native_ramp_ptr = (unsigned short *)(*env)->GetDirectBufferAddress(env, native_ramp); + int i; + for (i = 0; i < length; i++) { + float scaled_gamma = ramp_ptr[i]*0xffff; + short scaled_gamma_short = (unsigned short)round(scaled_gamma); + native_ramp_ptr[i] = scaled_gamma_short; + native_ramp_ptr[i + length] = scaled_gamma_short; + native_ramp_ptr[i + length*2] = scaled_gamma_short; + } + return native_ramp; } jobject initDisplay(JNIEnv *env, int screen, jint extension) { @@ -337,38 +331,41 @@ jobject initDisplay(JNIEnv *env, int screen, jint extension) { free(avail_modes); - /* Fetch the current gamma ramp */ - saved_gamma_ramp_length = getGammaRampLengthOfDisplay(env, disp, screen); - if (saved_gamma_ramp_length > 0) { - saved_ramp = (unsigned short *)malloc(sizeof(unsigned short)*3*saved_gamma_ramp_length); - if (!XF86VidModeGetGammaRamp(disp, screen, saved_gamma_ramp_length, saved_ramp, - saved_ramp + saved_gamma_ramp_length, saved_ramp + saved_gamma_ramp_length*2)) - freeSavedGammaRamps(); - } XCloseDisplay(disp); return newMode; } -static void freeCurrentGamma(void) { - if (current_ramp != NULL) { - free(current_ramp); - current_ramp = NULL; - current_gamma_ramp_length = 0; +JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetCurrentGammaRamp(JNIEnv *env, jclass unused) { + int ramp_size = getGammaRampLengthOfDisplay(env, getDisplay(), getCurrentScreen()); + jobject ramp_buffer = newJavaManagedByteBuffer(env, sizeof(unsigned short)*3*ramp_size); + if (ramp_buffer == NULL) { + throwException(env, "Could not allocate gamma ramp buffer"); + return NULL; } + unsigned short *ramp = (unsigned short *)(*env)->GetDirectBufferAddress(env, ramp_buffer); + if (!XF86VidModeGetGammaRamp(getDisplay(), getCurrentScreen(), ramp_size, ramp, + ramp + ramp_size, ramp + ramp_size*2)) { + throwException(env, "Could not get the current gamma ramp"); + return NULL; + } + return ramp_buffer; } -static void setCurrentGamma(Display *disp, int screen, JNIEnv *env) { - if (current_gamma_ramp_length == 0) +static void setGamma(JNIEnv *env, Display *disp, int screen, jobject ramp_buffer, bool throw_on_error) { + unsigned short *ramp_ptr = (unsigned short *)(*env)->GetDirectBufferAddress(env, ramp_buffer); + jlong capacity = (*env)->GetDirectBufferCapacity(env, ramp_buffer); + int size = capacity/(sizeof(unsigned short)*3); + if (size == 0) return; - if (XF86VidModeSetGammaRamp(disp, screen, current_gamma_ramp_length, current_ramp, current_ramp, current_ramp) == False) { - if (env != NULL) + if (XF86VidModeSetGammaRamp(disp, screen, size, ramp_ptr, ramp_ptr + size, ramp_ptr + size*2) == False) { + if (throw_on_error) throwException(env, "Could not set gamma ramp."); else - printfDebugJava(env, "Could not set gamma ramp"); + printfDebugJava(env, "Could not set gamma ramp."); } } -void temporaryRestoreMode(JNIEnv *env, int screen, jint extension) { +void temporaryRestoreMode(JNIEnv *env, int screen, jint extension, jobject saved_gamma_ramp) { Display *disp = XOpenDisplay(NULL); if (disp == NULL) { printfDebugJava(env, "Could not open display"); @@ -376,9 +373,9 @@ void temporaryRestoreMode(JNIEnv *env, int screen, jint extension) { } if (!setMode(env, disp, screen, extension, current_width, current_height, current_freq, false)) printfDebugJava(env, "Could not restore mode"); - setCurrentGamma(disp, screen, NULL); - XCloseDisplay(disp); // Don't propagate error to caller + setGamma(env, disp, screen, saved_gamma_ramp, false); + XCloseDisplay(disp); } void switchDisplayMode(JNIEnv * env, jobject mode, int screen, jint extension) { @@ -403,7 +400,7 @@ void switchDisplayMode(JNIEnv * env, jobject mode, int screen, jint extension) { XCloseDisplay(disp); } -void resetDisplayMode(JNIEnv *env, int screen, jint extension, bool temporary) { +void resetDisplayMode(JNIEnv *env, int screen, jint extension, jobject gamma_ramp, bool temporary) { Display *disp = XOpenDisplay(NULL); if (disp == NULL) { printfDebugJava(env, "Failed to contact X Server"); @@ -412,11 +409,7 @@ void resetDisplayMode(JNIEnv *env, int screen, jint extension, bool temporary) { if (!setMode(env, disp, screen, extension, saved_width, saved_height, saved_freq, temporary)) { printfDebugJava(env, "Failed to reset mode"); } - if (saved_gamma_ramp_length > 0) { - XF86VidModeSetGammaRamp(disp, screen, saved_gamma_ramp_length, saved_ramp, saved_ramp + - saved_gamma_ramp_length, saved_ramp + saved_gamma_ramp_length*2); - } -// decDisplay(); + setGamma(env, disp, screen, gamma_ramp, false); XCloseDisplay(disp); } @@ -456,19 +449,6 @@ void setGammaRamp(JNIEnv *env, jobject gamma_ramp_buffer, int screen) { throwException(env, "Could not open display"); return; } - freeCurrentGamma(); - current_gamma_ramp_length = getGammaRampLengthOfDisplay(env, disp, screen); - if (current_gamma_ramp_length == 0) { - throwException(env, "Gamma ramp not supported"); - return; - } - const float *gamma_ramp = (const float *)(*env)->GetDirectBufferAddress(env, gamma_ramp_buffer); - current_ramp = (unsigned short *)malloc(sizeof(unsigned short)*current_gamma_ramp_length); - int i; - for (i = 0; i < current_gamma_ramp_length; i++) { - float scaled_gamma = gamma_ramp[i]*0xffff; - current_ramp[i] = (unsigned short)round(scaled_gamma); - } - setCurrentGamma(disp, screen, env); + setGamma(env, disp, screen, gamma_ramp_buffer, true); XCloseDisplay(disp); } diff --git a/src/native/linux/display.h b/src/native/linux/display.h index 717f7397..65c139f8 100644 --- a/src/native/linux/display.h +++ b/src/native/linux/display.h @@ -49,10 +49,10 @@ extern int getScreenModeWidth(void); extern int getScreenModeHeight(void); extern jobject initDisplay(JNIEnv *env, int screen, jint extension); extern void switchDisplayMode(JNIEnv * env, jobject mode, int screen, jint extension); -extern void resetDisplayMode(JNIEnv *env, int screen, jint extension, bool temporary); +extern void resetDisplayMode(JNIEnv *env, int screen, jint extension, jobject gamma_ramp, bool temporary); extern jobjectArray getAvailableDisplayModes(JNIEnv * env, int screen, jint extension); -extern int getGammaRampLength(JNIEnv *env, int screen); +extern int getGammaRampLengthOfDisplay(JNIEnv *env, Display *disp, int screen); extern void setGammaRamp(JNIEnv *env, jobject gamma_ramp_buffer, int screen); -extern void temporaryRestoreMode(JNIEnv *env, int screen, jint extension); +extern void temporaryRestoreMode(JNIEnv *env, int screen, jint extension, jobject gamma_ramp); #endif diff --git a/src/native/linux/org_lwjgl_opengl_Display.c b/src/native/linux/org_lwjgl_opengl_Display.c index f681e2db..18875077 100644 --- a/src/native/linux/org_lwjgl_opengl_Display.c +++ b/src/native/linux/org_lwjgl_opengl_Display.c @@ -182,7 +182,7 @@ static void setDecorations(int dec) { XChangeProperty (getDisplay(), getCurrentWindow(), motif_hints_atom, motif_hints_atom, 32, PropModeReplace, (unsigned char *)&motif_hints, sizeof(MotifWmHints)/sizeof(long)); } -static bool releaseInput(JNIEnv *env, jint extension, jint window_mode) { +static bool releaseInput(JNIEnv *env, jint extension, jint window_mode, jobject gamma_ramp) { if (isLegacyFullscreen(window_mode) || input_released) return false; input_released = true; @@ -190,19 +190,19 @@ static bool releaseInput(JNIEnv *env, jint extension, jint window_mode) { updateInputGrab(window_mode); if (window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_NETWM) { XIconifyWindow(getDisplay(), getCurrentWindow(), getCurrentScreen()); - resetDisplayMode(env, getCurrentScreen(), extension, true); + resetDisplayMode(env, getCurrentScreen(), extension, gamma_ramp, true); } return true; } -static void acquireInput(JNIEnv *env, jint extension, jint window_mode) { +static void acquireInput(JNIEnv *env, jint extension, jint window_mode, jobject gamma_ramp) { if (isLegacyFullscreen(window_mode) || !input_released) return; input_released = false; setRepeatMode(env, AutoRepeatModeOff); updateInputGrab(window_mode); if (window_mode == org_lwjgl_opengl_LinuxDisplay_FULLSCREEN_NETWM) { - temporaryRestoreMode(env, getCurrentScreen(), extension); + temporaryRestoreMode(env, getCurrentScreen(), extension, gamma_ramp); } } @@ -229,20 +229,20 @@ void setGrab(jint window_mode, bool new_grab) { } } -static void checkInput(JNIEnv *env, jint extension, jint window_mode) { +static void checkInput(JNIEnv *env, jint extension, jint window_mode, jobject saved_gamma, jobject current_gamma) { Window win; int revert_mode; XGetInputFocus(getDisplay(), &win, &revert_mode); if (win == current_win) { - acquireInput(env, extension, window_mode); + acquireInput(env, extension, window_mode, current_gamma); focused = true; } else { - releaseInput(env, extension, window_mode); + releaseInput(env, extension, window_mode, saved_gamma); focused = false; } } -void handleMessages(JNIEnv *env, jint extension, jint window_mode) { +void handleMessages(JNIEnv *env, jint extension, jint window_mode, jobject saved_gamma, jobject current_gamma) { XEvent event; /* Window win; int revert_mode;*/ @@ -293,7 +293,7 @@ void handleMessages(JNIEnv *env, jint extension, jint window_mode) { break; } } - checkInput(env, extension, window_mode); + checkInput(env, extension, window_mode, saved_gamma, current_gamma); } static void setWindowTitle(const char *title) { @@ -454,9 +454,9 @@ int getWindowHeight(void) { } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUpdate - (JNIEnv *env, jclass clazz, jint extension, jint window_mode) + (JNIEnv *env, jclass clazz, jint extension, jint window_mode, jobject saved_gamma, jobject current_gamma) { - handleMessages(env, extension, window_mode); + handleMessages(env, extension, window_mode, saved_gamma, current_gamma); } JNIEXPORT jobjectArray JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetAvailableDisplayModes(JNIEnv *env, jclass clazz, jint extension) { @@ -467,12 +467,12 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSwitchDisplayMode(JNI switchDisplayMode(env, mode, getCurrentScreen(), extension); } -JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nResetDisplayMode(JNIEnv *env, jclass clazz, jint extension) { - resetDisplayMode(env, getCurrentScreen(), extension, false); +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nResetDisplayMode(JNIEnv *env, jclass clazz, jint extension, jobject gamma_ramp) { + resetDisplayMode(env, getCurrentScreen(), extension, gamma_ramp, false); } JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nGetGammaRampLength(JNIEnv *env, jclass clazz) { - return (jint)getGammaRampLength(env, getCurrentScreen()); + return (jint)getGammaRampLengthOfDisplay(env, getDisplay(), getCurrentScreen()); } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetGammaRamp(JNIEnv *env, jclass clazz, jobject gamma_buffer) {