diff --git a/src/native/linux/Window.h b/src/native/linux/Window.h index 48110b36..ccc29646 100644 --- a/src/native/linux/Window.h +++ b/src/native/linux/Window.h @@ -124,7 +124,7 @@ /* * Return true if we are in fullscreen mode */ - extern bool isFullscreen(void); + extern bool isLegacyFullscreen(void); /* * convert bit-per-pixel to bits-per-element diff --git a/src/native/linux/display.cpp b/src/native/linux/display.cpp index 3b348cda..9febe640 100644 --- a/src/native/linux/display.cpp +++ b/src/native/linux/display.cpp @@ -51,27 +51,32 @@ #include "common_tools.h" #include "Window.h" -typedef enum {XRANDR, XF86VIDMODE, NONE} extension; - typedef struct { int width; int height; int freq; union { - int size_index; - XF86VidModeModeInfo xf86vm_modeinfo; + int size_index; // Data for Xrandr extension + XF86VidModeModeInfo xf86vm_modeinfo; // Data for XF86VidMode extension } mode_data; } mode_info; static int saved_width; static int saved_height; static int saved_freq; -static int gamma_ramp_length = 0; +static int current_width; +static int current_height; +static int current_freq; +static int saved_gamma_ramp_length = 0; static unsigned short *r_ramp; static unsigned short *g_ramp; static unsigned short *b_ramp; static extension current_extension = NONE; +extension getCurrentDisplayModeExtension(void) { + return current_extension; +} + static bool getXF86VidModeVersion(Display *disp, int *major, int *minor) { int event_base, error_base; @@ -253,7 +258,7 @@ static void freeSavedGammaRamps() { r_ramp = NULL; g_ramp = NULL; b_ramp = NULL; - gamma_ramp_length = 0; + saved_gamma_ramp_length = 0; } static int getGammaRampLength(Display *disp, int screen) { @@ -269,16 +274,24 @@ static int getGammaRampLength(Display *disp, int screen) { return ramp_size; } -jobject initDisplay(JNIEnv *env) { +int getGammaRampLength(int screen) { + Display *disp = XOpenDisplay(NULL); + if (disp == NULL) { + printfDebug("Could not open display"); + return 0; + } + return getGammaRampLength(disp, screen); + XCloseDisplay(disp); +} + +jobject initDisplay(JNIEnv *env, int screen) { int num_modes; mode_info *avail_modes; - int screen; Display *disp = XOpenDisplay(NULL); if (disp == NULL) { throwException(env, "Could not open display"); return NULL; } - screen = DefaultScreen(disp); current_extension = getBestDisplayModeExtension(disp); if (current_extension == NONE) { @@ -292,9 +305,9 @@ jobject initDisplay(JNIEnv *env) { XCloseDisplay(disp); return NULL; } - saved_width = avail_modes[0].width; - saved_height = avail_modes[0].height; - saved_freq = avail_modes[0].freq; + saved_width = current_width = avail_modes[0].width; + saved_height = current_height = avail_modes[0].height; + saved_freq = current_freq = avail_modes[0].freq; int bpp = XDefaultDepth(disp, screen); printfDebug("Original display dimensions: width %d, height %d freq %d\n", saved_width, saved_height, saved_freq); jclass jclass_DisplayMode = env->FindClass("org/lwjgl/opengl/DisplayMode"); @@ -304,19 +317,43 @@ jobject initDisplay(JNIEnv *env) { free(avail_modes); /* Fetch the current gamma ramp */ - gamma_ramp_length = getGammaRampLength(disp, screen); - if (gamma_ramp_length > 0) { - r_ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); - g_ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); - b_ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); - if (!XF86VidModeGetGammaRamp(disp, screen, gamma_ramp_length, r_ramp, g_ramp, b_ramp)) + saved_gamma_ramp_length = getGammaRampLength(disp, screen); + if (saved_gamma_ramp_length > 0) { + r_ramp = (unsigned short *)malloc(sizeof(unsigned short)*saved_gamma_ramp_length); + g_ramp = (unsigned short *)malloc(sizeof(unsigned short)*saved_gamma_ramp_length); + b_ramp = (unsigned short *)malloc(sizeof(unsigned short)*saved_gamma_ramp_length); + if (!XF86VidModeGetGammaRamp(disp, screen, saved_gamma_ramp_length, r_ramp, g_ramp, b_ramp)) freeSavedGammaRamps(); } XCloseDisplay(disp); return newMode; } -void switchDisplayMode(JNIEnv * env, jobject mode) { +void temporaryRestoreMode(int screen) { + Display *disp = XOpenDisplay(NULL); + if (disp == NULL) { + printfDebug("Could not open display"); + return; + } + if (!setMode(disp, screen, current_width, current_height, current_freq)) + printfDebug("Could not restore mode\n"); + XCloseDisplay(disp); + // Don't propagate error to caller +} + +void temporaryResetMode(int screen) { + Display *disp = XOpenDisplay(NULL); + if (disp == NULL) { + printfDebug("Could not open display"); + return; + } + if (!setMode(disp, screen, saved_width, saved_height, saved_freq)) + printfDebug("Could not reset mode\n"); + XCloseDisplay(disp); + // Don't propagate error to caller +} + +void switchDisplayMode(JNIEnv * env, jobject mode, int screen) { if (mode == NULL) { throwException(env, "mode must be non-null"); return; @@ -328,39 +365,38 @@ void switchDisplayMode(JNIEnv * env, jobject mode) { int width = env->GetIntField(mode, fid_width); int height = env->GetIntField(mode, fid_height); int freq = env->GetIntField(mode, fid_freq); - int screen; Display *disp = XOpenDisplay(NULL); if (disp == NULL) { throwException(env, "Could not open display"); return; } - screen = DefaultScreen(disp); - if (!setMode(disp, screen, width, height, freq)) + if (setMode(disp, screen, width, height, freq)) { + current_width = width; + current_height = height; + current_freq = freq; + } else throwException(env, "Could not switch mode."); XCloseDisplay(disp); } -void resetDisplayMode(JNIEnv *env) { - int screen; +void resetDisplayMode(JNIEnv *env, int screen) { Display *disp = XOpenDisplay(NULL); // Display *disp = incDisplay(env); if (disp == NULL) return; - screen = DefaultScreen(disp); if (!setMode(disp, screen, saved_width, saved_height, saved_freq)) { printfDebug("Failed to reset mode"); } - if (gamma_ramp_length > 0) { - XF86VidModeSetGammaRamp(disp, screen, gamma_ramp_length, r_ramp, g_ramp, b_ramp); + if (saved_gamma_ramp_length > 0) { + XF86VidModeSetGammaRamp(disp, screen, saved_gamma_ramp_length, r_ramp, g_ramp, b_ramp); freeSavedGammaRamps(); } // decDisplay(); XCloseDisplay(disp); } -jobjectArray getAvailableDisplayModes(JNIEnv * env) { +jobjectArray getAvailableDisplayModes(JNIEnv * env, int screen) { int num_modes, i; - int screen; mode_info *avail_modes; Display *disp = XOpenDisplay(NULL); if (disp == NULL) { @@ -368,7 +404,6 @@ jobjectArray getAvailableDisplayModes(JNIEnv * env) { return NULL; } - screen = DefaultScreen(disp); int bpp = XDefaultDepth(disp, screen); avail_modes = getDisplayModes(disp, screen, &num_modes); if (avail_modes == NULL) { @@ -390,21 +425,17 @@ jobjectArray getAvailableDisplayModes(JNIEnv * env) { return ret; } -int getGammaRampLength(void) { - return gamma_ramp_length; -} - -void setGammaRamp(JNIEnv *env, jobject gamma_ramp_buffer) { - if (gamma_ramp_length == 0) { - throwException(env, "gamma ramp length == 0."); - return; - } +void setGammaRamp(JNIEnv *env, jobject gamma_ramp_buffer, int screen) { Display * disp = XOpenDisplay(NULL); if (disp == NULL) { throwException(env, "Could not open display"); return; } - int screen = DefaultScreen(disp); + int gamma_ramp_length = getGammaRampLength(disp, screen); + if (gamma_ramp_length == 0) { + throwException(env, "Gamma ramp not supported"); + return; + } const float *gamma_ramp = (const float *)env->GetDirectBufferAddress(gamma_ramp_buffer); unsigned short *ramp; ramp = (unsigned short *)malloc(sizeof(unsigned short)*gamma_ramp_length); diff --git a/src/native/linux/display.h b/src/native/linux/display.h index d7ec9597..6d0bd750 100644 --- a/src/native/linux/display.h +++ b/src/native/linux/display.h @@ -44,11 +44,16 @@ #include -extern jobject initDisplay(JNIEnv *env); -extern void switchDisplayMode(JNIEnv * env, jobject mode); -extern void resetDisplayMode(JNIEnv * env); -extern jobjectArray getAvailableDisplayModes(JNIEnv * env); -extern int getGammaRampLength(void); -extern void setGammaRamp(JNIEnv *env, jobject gamma_ramp_buffer); +typedef enum {XRANDR, XF86VIDMODE, NONE} extension; + +extern jobject initDisplay(JNIEnv *env, int screen); +extern void switchDisplayMode(JNIEnv * env, jobject mode, int screen); +extern void resetDisplayMode(JNIEnv * env, int screen); +extern jobjectArray getAvailableDisplayModes(JNIEnv * env, int screen); +extern int getGammaRampLength(int screen); +extern void setGammaRamp(JNIEnv *env, jobject gamma_ramp_buffer, int screen); +extern extension getCurrentDisplayModeExtension(); +extern void temporaryResetMode(int screen); +extern void temporaryRestoreMode(int screen); #endif diff --git a/src/native/linux/org_lwjgl_input_Keyboard.cpp b/src/native/linux/org_lwjgl_input_Keyboard.cpp index 3f2c7937..da1a22e2 100644 --- a/src/native/linux/org_lwjgl_input_Keyboard.cpp +++ b/src/native/linux/org_lwjgl_input_Keyboard.cpp @@ -80,7 +80,7 @@ static void ungrabKeyboard(void) { void updateKeyboardGrab(void) { if (!created) return; - if (isFullscreen()/* || shouldGrab()*/) { + if (isLegacyFullscreen()/* || shouldGrab()*/) { grabKeyboard(); } else { ungrabKeyboard(); diff --git a/src/native/linux/org_lwjgl_input_Mouse.cpp b/src/native/linux/org_lwjgl_input_Mouse.cpp index c225840b..aa414302 100644 --- a/src/native/linux/org_lwjgl_input_Mouse.cpp +++ b/src/native/linux/org_lwjgl_input_Mouse.cpp @@ -140,7 +140,7 @@ static void grabPointer(void) { if (result == GrabSuccess) { pointer_grabbed = true; // make sure we have a centered window - if (isFullscreen()) { + if (isLegacyFullscreen()) { XWindowAttributes win_attribs; XGetWindowAttributes(getDisplay(), getCurrentWindow(), &win_attribs); // XF86VidModeSetViewPort(getDisplay(), getCurrentScreen(), 0, 0); @@ -162,7 +162,7 @@ static void ungrabPointer(void) { void updatePointerGrab(void) { if (!created) return; - if (isFullscreen() || shouldGrab()) { + if (isLegacyFullscreen() || shouldGrab()) { grabPointer(); } else { ungrabPointer(); diff --git a/src/native/linux/org_lwjgl_opengl_Display.cpp b/src/native/linux/org_lwjgl_opengl_Display.cpp index 4305d5a6..47af3a84 100644 --- a/src/native/linux/org_lwjgl_opengl_Display.cpp +++ b/src/native/linux/org_lwjgl_opengl_Display.cpp @@ -56,6 +56,8 @@ #define USEGLX13 extgl_Extensions.GLX13 #define ERR_MSG_SIZE 1024 +typedef enum {FULLSCREEN_LEGACY, FULLSCREEN_NETWM, WINDOWED} window_mode; + static GLXContext context = NULL; // OpenGL rendering context static GLXFBConfig *configs = NULL; static GLXWindow glx_window; @@ -64,7 +66,7 @@ static XVisualInfo *vis_info = NULL; static Atom delete_atom; static Colormap cmap; static Window current_win; -static bool current_fullscreen; +static window_mode current_window_mode; static int current_height; static int current_width; @@ -158,7 +160,6 @@ void decDisplay(void) { static void waitMapped(Window win) { XEvent event; - do { XMaskEvent(getDisplay(), StructureNotifyMask, &event); } while ((event.type != MapNotify) || (event.xmap.event != win)); @@ -182,27 +183,31 @@ static void setRepeatMode(int mode) { } bool releaseInput(void) { - if (current_fullscreen || input_released) + if (isLegacyFullscreen() || input_released) return false; input_released = true; setRepeatMode(AutoRepeatModeDefault); updateInputGrab(); -/* if (current_fullscreen) { + if (current_window_mode == FULLSCREEN_NETWM) { XIconifyWindow(getDisplay(), getCurrentWindow(), getCurrentScreen()); - }*/ + temporaryResetMode(getCurrentScreen()); + } return true; } static void acquireInput(void) { - if (current_fullscreen || !input_released) + if (isLegacyFullscreen() || !input_released) return; input_released = false; setRepeatMode(AutoRepeatModeOff); updateInputGrab(); + if (current_window_mode == FULLSCREEN_NETWM) { + temporaryRestoreMode(getCurrentScreen()); + } } -bool isFullscreen(void) { - return current_fullscreen; +bool isLegacyFullscreen(void) { + return current_window_mode == FULLSCREEN_LEGACY; } bool shouldGrab(void) { @@ -210,8 +215,15 @@ bool shouldGrab(void) { } void setGrab(bool new_grab) { - grab = new_grab; - updateInputGrab(); + if (new_grab != grab) { + grab = new_grab; + updateInputGrab(); +/* // Attempt to regain focus + if (grab) { + XMapRaised(getDisplay(), getCurrentWindow()); + waitMapped(getCurrentWindow()); + }*/ + } } static void handleMotion(XMotionEvent *event) { @@ -303,8 +315,32 @@ static void destroyWindow(void) { setRepeatMode(AutoRepeatModeDefault); } +static bool isNetWMFullscreenSupported() { + unsigned long nitems; + Atom actual_type; + int actual_format; + unsigned long bytes_after; + Atom *supported_list; + Atom netwm_supported_atom = XInternAtom(getDisplay(), "_NET_SUPPORTED", False); + int result = XGetWindowProperty(getDisplay(), RootWindow(getDisplay(), getCurrentScreen()), netwm_supported_atom, 0, 10000, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char **)&supported_list); + if (result != Success) { + printfDebug("Anable to query _NET_SUPPORTED window property\n"); + return false; + } + Atom fullscreen_atom = XInternAtom(getDisplay(), "_NET_WM_STATE_FULLSCREEN", False); + bool supported = false; + for (unsigned long i = 0; i < nitems; i++) { + if (fullscreen_atom == supported_list[i]) { + supported = true; + break; + } + } + XFree(supported_list); + return supported; +} + static bool createWindow(JNIEnv* env, int width, int height) { - bool undecorated = getBooleanProperty(env, "org.lwjgl.opengl.Window.undecorated"); +// bool undecorated = getBooleanProperty(env, "org.lwjgl.opengl.Window.undecorated"); dirty = true; focused = true; minimized = false; @@ -320,7 +356,6 @@ static bool createWindow(JNIEnv* env, int width, int height) { input_released = false; current_width = width; current_height = height; - root_win = RootWindow(getDisplay(), getCurrentScreen()); cmap = XCreateColormap(getDisplay(), root_win, vis_info->visual, AllocNone); attribs.colormap = cmap; @@ -328,7 +363,7 @@ static bool createWindow(JNIEnv* env, int width, int height) { attribs.background_pixel = 0xFF000000; attribs.win_gravity = NorthWestGravity; attribmask = CWColormap | CWBackPixel | CWEventMask | CWWinGravity; - if (current_fullscreen || undecorated) { + if (isLegacyFullscreen()/* || undecorated*/) { attribmask |= CWOverrideRedirect; attribs.override_redirect = True; } @@ -349,11 +384,11 @@ static bool createWindow(JNIEnv* env, int width, int height) { XFree(size_hints); delete_atom = XInternAtom(getDisplay(), "WM_DELETE_WINDOW", False); XSetWMProtocols(getDisplay(), win, &delete_atom, 1); -/* if (current_fullscreen) { + if (current_window_mode == FULLSCREEN_NETWM) { Atom fullscreen_atom = XInternAtom(getDisplay(), "_NET_WM_STATE_FULLSCREEN", False); XChangeProperty(getDisplay(), getCurrentWindow(), XInternAtom(getDisplay(), "_NET_WM_STATE", False), XInternAtom(getDisplay(), "ATOM", False), 32, PropModeReplace, (const unsigned char*)&fullscreen_atom, 1); - }*/ + } XMapRaised(getDisplay(), win); waitMapped(win); XClearWindow(getDisplay(), win); @@ -609,27 +644,27 @@ static bool initWindowGLX(JNIEnv *env, jobject pixel_format) { } JNIEXPORT jobjectArray JNICALL Java_org_lwjgl_opengl_Display_nGetAvailableDisplayModes(JNIEnv *env, jclass clazz) { - return getAvailableDisplayModes(env); + return getAvailableDisplayModes(env, getCurrentScreen()); } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_nSwitchDisplayMode(JNIEnv *env, jclass clazz, jobject mode) { - switchDisplayMode(env, mode); + switchDisplayMode(env, mode, getCurrentScreen()); } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_resetDisplayMode(JNIEnv *env, jclass clazz) { - resetDisplayMode(env); + resetDisplayMode(env, getCurrentScreen()); } JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Display_getGammaRampLength(JNIEnv *env, jclass clazz) { - return (jint)getGammaRampLength(); + return (jint)getGammaRampLength(getCurrentScreen()); } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_setGammaRamp(JNIEnv *env, jclass clazz, jobject gamma_buffer) { - setGammaRamp(env, gamma_buffer); + setGammaRamp(env, gamma_buffer, getCurrentScreen()); } JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_Display_init(JNIEnv *env, jclass clazz) { - return initDisplay(env); + return initDisplay(env, getCurrentScreen()); } JNIEXPORT jstring JNICALL Java_org_lwjgl_opengl_Display_getAdapter(JNIEnv *env , jclass clazz) { @@ -665,7 +700,14 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_destroyContext(JNIEnv *env, } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_nCreateWindow(JNIEnv *env, jclass clazz, jobject mode, jboolean fullscreen) { - current_fullscreen = fullscreen == JNI_TRUE; + bool current_fullscreen = fullscreen == JNI_TRUE; + if (current_fullscreen) { + if (getCurrentDisplayModeExtension() == XRANDR && isNetWMFullscreenSupported()) + current_window_mode = FULLSCREEN_NETWM; + else + current_window_mode = FULLSCREEN_LEGACY; + } else + current_window_mode = WINDOWED; jclass cls_displayMode = env->GetObjectClass(mode); jfieldID fid_width = env->GetFieldID(cls_displayMode, "width", "I"); jfieldID fid_height = env->GetFieldID(cls_displayMode, "height", "I"); @@ -689,11 +731,6 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_nDestroyWindow(JNIEnv *env, destroyWindow(); } -/* - * Class: org_lwjgl_opengl_GLWindow - * Method: swapBuffers - * Signature: ()V - */ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_swapBuffers(JNIEnv * env, jclass clazz) { dirty = false; @@ -703,12 +740,6 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Display_swapBuffers(JNIEnv * env, j glXSwapBuffers(getDisplay(), getCurrentWindow()); } - -/* - * Class: org_lwjgl_opengl_Window - * Method: nIsDirty - * Signature: ()Z - */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Display_nIsDirty (JNIEnv *env, jclass clazz) { bool result = dirty; @@ -716,21 +747,11 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Display_nIsDirty return result ? JNI_TRUE : JNI_FALSE; } -/* - * Class: org_lwjgl_opengl_Window - * Method: nIsVisible - * Signature: ()Z - */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Display_nIsVisible (JNIEnv *env, jclass clazz) { return minimized ? JNI_FALSE : JNI_TRUE; } -/* - * Class: org_lwjgl_opengl_Window - * Method: nIsCloseRequested - * Signature: ()Z - */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Display_nIsCloseRequested (JNIEnv *, jclass) { bool saved = closerequested; @@ -738,11 +759,6 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Display_nIsCloseRequested return saved; } -/* - * Class: org_lwjgl_opengl_Window - * Method: nIsActive - * Signature: ()Z - */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Display_nIsActive (JNIEnv *env, jclass clazz) { return focused ? JNI_TRUE : JNI_FALSE;