Linux: Implemented support for Extended Window Manager Hints. LWJGL now cooperates

much better with the window manager, if the X randr and EWMH extensions are supported.
Especially fullscreen handling has improved, by avoiding the use of the override_redirect
flag.
This commit is contained in:
Elias Naur 2004-08-23 08:46:35 +00:00
parent 0c5bb83832
commit bb1d59fffe
6 changed files with 150 additions and 98 deletions

View File

@ -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

View File

@ -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);

View File

@ -44,11 +44,16 @@
#include <jni.h>
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

View File

@ -80,7 +80,7 @@ static void ungrabKeyboard(void) {
void updateKeyboardGrab(void) {
if (!created)
return;
if (isFullscreen()/* || shouldGrab()*/) {
if (isLegacyFullscreen()/* || shouldGrab()*/) {
grabKeyboard();
} else {
ungrabKeyboard();

View File

@ -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();

View File

@ -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;