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