From: <eli...@us...> - 2008-04-12 20:07:28
|
Revision: 3007 http://java-game-lib.svn.sourceforge.net/java-game-lib/?rev=3007&view=rev Author: elias_naur Date: 2008-04-12 13:07:23 -0700 (Sat, 12 Apr 2008) Log Message: ----------- Linux: Rewrote focus handling to cope with the weird focus behaviour when running in an XEmbed enabled jvm (applet mode) Modified Paths: -------------- trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxEvent.java trunk/LWJGL/src/native/linux/org_lwjgl_opengl_Display.c trunk/LWJGL/src/native/linux/org_lwjgl_opengl_LinuxEvent.c Modified: trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java 2008-04-11 12:23:07 UTC (rev 3006) +++ trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxDisplay.java 2008-04-12 20:07:23 UTC (rev 3007) @@ -57,6 +57,18 @@ public final static int AutoRepeatModeDefault = 2; public final static int None = 0; + private final static int KeyPressMask = 1 << 0; + private final static int KeyReleaseMask = 1 << 1; + private final static int ButtonPressMask = 1 << 2; + private final static int ButtonReleaseMask = 1 << 3; + + private final static int NotifyAncestor = 0; + private final static int NotifyNonlinear = 3; + private final static int NotifyPointer = 5; + private final static int NotifyPointerRoot = 6; + private final static int NotifyDetailNone = 7; + + /** Window mode enum */ private static final int FULLSCREEN_LEGACY = 1; private static final int FULLSCREEN_NETWM = 2; @@ -78,6 +90,7 @@ /** Event buffer */ private final LinuxEvent event_buffer = new LinuxEvent(); + private final LinuxEvent tmp_event_buffer = new LinuxEvent(); /** Current mode swithcing API */ private int current_displaymode_extension = NONE; @@ -103,10 +116,13 @@ private boolean minimized; private boolean dirty; private boolean close_requested; - private boolean focused_at_least_once; private long current_cursor; private long blank_cursor; private Canvas parent; + private long parent_focus_window; + private boolean parent_focus_window_valid; + private long parent_window; + private boolean xembedded; private LinuxKeyboard keyboard; private LinuxMouse mouse; @@ -371,16 +387,17 @@ current_window_mode = getWindowMode(fullscreen); boolean undecorated = Display.getPrivilegedBoolean("org.lwjgl.opengl.Window.undecorated") || current_window_mode != WINDOWED; this.parent = parent; - long parent_window = parent != null ? getHandle(parent) : getRootWindow(getDisplay(), getDefaultScreen()); + parent_window = parent != null ? getHandle(parent) : getRootWindow(getDisplay(), getDefaultScreen()); current_window = nCreateWindow(getDisplay(), getDefaultScreen(), handle, mode, current_window_mode, x, y, undecorated, parent_window); + xembedded = parent != null && isAncestorXEmbedded(parent_window); blank_cursor = createBlankCursor(); + parent_focus_window_valid = false; current_cursor = None; - focused = true; + focused = false; input_released = false; pointer_grabbed = false; keyboard_grabbed = false; close_requested = false; - focused_at_least_once = false; grab = false; minimized = false; dirty = true; @@ -397,7 +414,22 @@ } private static native long nCreateWindow(long display, int screen, ByteBuffer peer_info_handle, DisplayMode mode, int window_mode, int x, int y, boolean undecorated, long parent_handle) throws LWJGLException; private static native long getRootWindow(long display, int screen); + private static native boolean hasProperty(long display, long window, long property); + private static native long getParentWindow(long display, long window) throws LWJGLException; + private boolean isAncestorXEmbedded(long window) throws LWJGLException { + long xembed_atom = internAtom("_XEMBED_INFO", true); + if (xembed_atom != None) { + long w = parent_window; + while (w != None) { + if (hasProperty(getDisplay(), w, xembed_atom)) + return true; + w = getParentWindow(getDisplay(), w); + } + } + return false; + } + private static long getHandle(Canvas parent) throws LWJGLException { AWTCanvasImplementation awt_impl = AWTGLCanvas.createImplementation(); LinuxPeerInfo parent_peer_info = (LinuxPeerInfo)awt_impl.createPeerInfo(parent, null); @@ -623,17 +655,49 @@ static native void setInputFocus(long display, long window, long time); + private void relayEventToParent(LinuxEvent event_buffer, int event_mask) { + tmp_event_buffer.copyFrom(event_buffer); + tmp_event_buffer.setWindow(parent_window); + tmp_event_buffer.sendEvent(getDisplay(), parent_window, true, event_mask); + } + + private void relayEventToParent(LinuxEvent event_buffer) { + if (parent == null) + return; + switch (event_buffer.getType()) { + case LinuxEvent.KeyPress: + relayEventToParent(event_buffer, KeyPressMask); + break; + case LinuxEvent.KeyRelease: + relayEventToParent(event_buffer, KeyPressMask); + break; + case LinuxEvent.ButtonPress: + relayEventToParent(event_buffer, KeyPressMask); + break; + case LinuxEvent.ButtonRelease: + relayEventToParent(event_buffer, KeyPressMask); + break; + default: + break; + } + } + private void processEvents() { while (LinuxEvent.getPending(getDisplay()) > 0) { event_buffer.nextEvent(getDisplay()); long event_window = event_buffer.getWindow(); - if (event_buffer.getType() == LinuxEvent.ButtonPress && parent != null) - setInputFocus(getDisplay(), getWindow(), event_buffer.getButtonTime()); + relayEventToParent(event_buffer); if (event_window != getWindow() || event_buffer.filterEvent(event_window) || (mouse != null && mouse.filterEvent(grab, shouldWarpPointer(), event_buffer)) || (keyboard != null && keyboard.filterEvent(event_buffer))) continue; switch (event_buffer.getType()) { + case LinuxEvent.FocusIn: + setFocused(true, event_buffer.getFocusDetail()); + break; + case LinuxEvent.FocusOut: + setFocused(false, event_buffer.getFocusDetail()); + break; case LinuxEvent.ClientMessage: if ((event_buffer.getClientFormat() == 32) && (event_buffer.getClientData(0) == delete_atom)) close_requested = true; @@ -641,7 +705,6 @@ case LinuxEvent.MapNotify: dirty = true; minimized = false; - updateInputGrab(); break; case LinuxEvent.UnmapNotify: dirty = true; @@ -743,29 +806,41 @@ } private void checkInput() { - long current_focus = nGetInputFocus(getDisplay()); - focused = current_focus == getWindow(); + if (parent == null) + return; if (focused) { - focused_at_least_once = true; - acquireInput(); + if (xembedded && !parent.isFocusOwner() && parent_focus_window_valid) { + setInputFocusUnsafe(parent_focus_window); + } } else { - if (focused_at_least_once) - releaseInput(); - if (parent != null && parent.isFocusOwner()) { - setInputFocusUnsafe(); + if (parent.isFocusOwner()) { + if (xembedded) { + parent_focus_window = nGetInputFocus(getDisplay()); + parent_focus_window_valid = true; + } + setInputFocusUnsafe(getWindow()); } } } + + private void setFocused(boolean got_focus, int focus_detail) { + if (focused == got_focus || focus_detail == NotifyDetailNone || focus_detail == NotifyPointer || focus_detail == NotifyPointerRoot) + return; + focused = got_focus; + if (focused) { + acquireInput(); + } else { + releaseInput(); + } + } static native long nGetInputFocus(long display); - private static native void grabServer(long display); - private static native void ungrabServer(long display); - private static void setInputFocusUnsafe() { - setInputFocus(getDisplay(), getWindow(), CurrentTime); + private void setInputFocusUnsafe(long window) { + setInputFocus(getDisplay(), window, CurrentTime); try { checkXError(getDisplay()); } catch (LWJGLException e) { - // Since we don't have any event timings for XSetInputFocus, a race condition might give a BadMatch, which we'll catch ang ignore + // Since we don't have any event timings for XSetInputFocus, a race condition might give a BadMatch, which we'll catch and ignore LWJGLUtil.log("Got exception while trying to focus: " + e); } } @@ -921,10 +996,6 @@ } } -/* public int isStateKeySet(int key) { - return Keyboard.STATE_UNKNOWN; - } -*/ private static native long nCreateCursor(long display, int width, int height, int xHotspot, int yHotspot, int numImages, IntBuffer images, int images_offset, IntBuffer delays, int delays_offset) throws LWJGLException; private static long createBlankCursor() { Modified: trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxEvent.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxEvent.java 2008-04-11 12:23:07 UTC (rev 3006) +++ trunk/LWJGL/src/java/org/lwjgl/opengl/LinuxEvent.java 2008-04-12 20:07:23 UTC (rev 3007) @@ -41,6 +41,8 @@ * $Id: LinuxPeerInfo.java 2286 2006-03-23 19:32:21Z matzon $ */ final class LinuxEvent { + public final static int FocusIn = 9; + public final static int FocusOut = 10; public final static int KeyPress = 2; public final static int KeyRelease = 3; public final static int ButtonPress = 4; @@ -58,8 +60,21 @@ } private static native ByteBuffer createEventBuffer(); + public final void copyFrom(LinuxEvent event) { + int pos = event_buffer.position(); + int event_pos = event.event_buffer.position(); + event_buffer.put(event.event_buffer); + event_buffer.position(pos); + event.event_buffer.position(event_pos); + } + public final static native int getPending(long display); + public final void sendEvent(long display, long window, boolean propagate, long event_mask) { + nSendEvent(event_buffer, display, window, propagate, event_mask); + } + private static native void nSendEvent(ByteBuffer event_buffer, long display, long window, boolean propagate, long event_mask); + public final boolean filterEvent(long window) { return nFilterEvent(event_buffer, window); } @@ -80,6 +95,23 @@ } private static native long nGetWindow(ByteBuffer event_buffer); + public final void setWindow(long window) { + nSetWindow(event_buffer, window); + } + private static native void nSetWindow(ByteBuffer event_buffer, long window); + + /* Focus methods */ + + public final int getFocusMode() { + return nGetFocusMode(event_buffer); + } + private static native int nGetFocusMode(ByteBuffer event_buffer); + + public final int getFocusDetail() { + return nGetFocusDetail(event_buffer); + } + private static native int nGetFocusDetail(ByteBuffer event_buffer); + /* ClientMessage methods */ public final long getClientMessageType() { Modified: trunk/LWJGL/src/native/linux/org_lwjgl_opengl_Display.c =================================================================== --- trunk/LWJGL/src/native/linux/org_lwjgl_opengl_Display.c 2008-04-11 12:23:07 UTC (rev 3006) +++ trunk/LWJGL/src/native/linux/org_lwjgl_opengl_Display.c 2008-04-12 20:07:23 UTC (rev 3007) @@ -288,7 +288,7 @@ return false; cmap = XCreateColormap(disp, parent, vis_info->visual, AllocNone); attribs.colormap = cmap; - attribs.event_mask = ExposureMask | /*FocusChangeMask | */VisibilityChangeMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; + attribs.event_mask = ExposureMask | FocusChangeMask | VisibilityChangeMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask; attribmask = CWColormap | CWEventMask; if (isLegacyFullscreen(window_mode)) { attribmask |= CWOverrideRedirect; @@ -334,14 +334,38 @@ return win; } -JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_grabServer(JNIEnv *env, jclass unused, jlong display) { +JNIEXPORT jlong JNICALL Java_org_lwjgl_opengl_LinuxDisplay_getParentWindow(JNIEnv *env, jclass unused, jlong display, jlong window_ptr) { Display *disp = (Display *)(intptr_t)display; - XGrabServer(disp); + Window window = (Window)window_ptr; + Window root, parent; + Window *children; + unsigned int nchildren; + if (XQueryTree(disp, window, &root, &parent, &children, &nchildren) == 0) { + throwException(env, "XQueryTree failed"); + return None; + } + if (children != NULL) + XFree(children); + return parent; } -JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_ungrabServer(JNIEnv *env, jclass unused, jlong display) { +JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_LinuxDisplay_hasProperty(JNIEnv *env, jclass unusued, jlong display, jlong window_ptr, jlong property_ptr) { Display *disp = (Display *)(intptr_t)display; - XUngrabServer(disp); + Window window = (Window)window_ptr; + Atom property = (Atom)property_ptr; + int num_props; + Atom *properties = XListProperties(disp, window, &num_props); + if (properties == NULL) + return JNI_FALSE; + jboolean result = JNI_FALSE; + for (int i = 0; i < num_props; i++) { + if (properties[i] == property) { + result = JNI_TRUE; + break; + } + } + XFree(properties); + return result; } JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_setInputFocus(JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jlong time) { Modified: trunk/LWJGL/src/native/linux/org_lwjgl_opengl_LinuxEvent.c =================================================================== --- trunk/LWJGL/src/native/linux/org_lwjgl_opengl_LinuxEvent.c 2008-04-11 12:23:07 UTC (rev 3006) +++ trunk/LWJGL/src/native/linux/org_lwjgl_opengl_LinuxEvent.c 2008-04-12 20:07:23 UTC (rev 3007) @@ -53,6 +53,29 @@ return XPending(disp); } +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxEvent_nSetWindow(JNIEnv *env, jclass unused, jobject event_buffer, jlong window_ptr) { + XEvent *event = (XEvent *)(*env)->GetDirectBufferAddress(env, event_buffer); + Window window = (Window)window_ptr; + event->xany.window = window; +} + +JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxEvent_nSendEvent(JNIEnv *env, jclass unused, jobject event_buffer, jlong display_ptr, jlong window_ptr, jboolean propagate, jlong eventmask) { + XEvent *event = (XEvent *)(*env)->GetDirectBufferAddress(env, event_buffer); + Display *disp = (Display *)(intptr_t)display_ptr; + Window window = (Window)window_ptr; + XSendEvent(disp, window, propagate == JNI_TRUE ? True : False, eventmask, event); +} + +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxEvent_nGetFocusDetail(JNIEnv *env, jclass unused, jobject event_buffer) { + XEvent *event = (XEvent *)(*env)->GetDirectBufferAddress(env, event_buffer); + return event->xfocus.detail; +} + +JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxEvent_nGetFocusMode(JNIEnv *env, jclass unused, jobject event_buffer) { + XEvent *event = (XEvent *)(*env)->GetDirectBufferAddress(env, event_buffer); + return event->xfocus.mode; +} + JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_LinuxEvent_nFilterEvent(JNIEnv *env, jclass unused, jobject event_buffer, jlong window_ptr) { XEvent *event = (XEvent *)(*env)->GetDirectBufferAddress(env, event_buffer); Window window = (Window)window_ptr; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |