diff --git a/src/java/org/lwjgl/opengl/LinuxDisplay.java b/src/java/org/lwjgl/opengl/LinuxDisplay.java index 6ca1ba80..1c94fed3 100644 --- a/src/java/org/lwjgl/opengl/LinuxDisplay.java +++ b/src/java/org/lwjgl/opengl/LinuxDisplay.java @@ -623,8 +623,6 @@ final class LinuxDisplay implements DisplayImplementation { private native static void setInputFocus(long display, long window); private void processEvents() { - if (!focused && parent != null && parent.isFocusOwner()) - setInputFocus(getDisplay(), getWindow()); while (LinuxEvent.getPending(getDisplay()) > 0) { event_buffer.nextEvent(getDisplay()); long event_window = event_buffer.getWindow(); @@ -742,15 +740,30 @@ final class LinuxDisplay implements DisplayImplementation { } private void checkInput() { - focused = nGetInputFocus(getDisplay()) == getWindow(); + long current_focus = nGetInputFocus(getDisplay()); + focused = current_focus == getWindow(); if (focused) { focused_at_least_once = true; acquireInput(); - } else if (focused_at_least_once) { - releaseInput(); + } else { + if (focused_at_least_once) + releaseInput(); + if (parent != null && parent.isFocusOwner()) { + // Normally, a real time stamp from an event should be passed to XSetInputFocus instead of CurrentTime, but we don't get timestamps + // from awt. Instead we grab the server and check if the focus changed to avoid a race where our window is made unviewable while focusing it. + grabServer(getDisplay()); + try { + if (nGetInputFocus(getDisplay()) == current_focus) + setInputFocus(getDisplay(), getWindow()); + } finally { + ungrabServer(getDisplay()); + } + } } } static native long nGetInputFocus(long display); + private static native void grabServer(long display); + private static native void ungrabServer(long display); private void releaseInput() { if (isLegacyFullscreen() || input_released) diff --git a/src/native/linux/org_lwjgl_opengl_Display.c b/src/native/linux/org_lwjgl_opengl_Display.c index 0cedfc0d..a935af21 100644 --- a/src/native/linux/org_lwjgl_opengl_Display.c +++ b/src/native/linux/org_lwjgl_opengl_Display.c @@ -327,14 +327,20 @@ static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_m return win; } +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_grabServer(JNIEnv *env, jclass unused, jlong display) { + Display *disp = (Display *)(intptr_t)display; + XGrabServer(disp); +} + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_ungrabServer(JNIEnv *env, jclass unused, jlong display) { + Display *disp = (Display *)(intptr_t)display; + XUngrabServer(disp); +} + JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_setInputFocus(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr) { Display *disp = (Display *)(intptr_t)display; Window window = (Window)window_ptr; - // Normally, a real time stamp from an event should be passed instead of CurrentTime, but we don't get timestamps - // from awt. Instead we grab the server before and ungrab it after the request - XGrabServer(disp); XSetInputFocus(disp, window, RevertToParent, CurrentTime); - XUngrabServer(disp); } JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nCreateWindow(JNIEnv *env, jclass clazz, jlong display, jint screen, jobject peer_info_handle, jobject mode, jint window_mode, jint x, jint y, jboolean undecorated, jlong parent_handle) {