mirror of
https://github.com/shadowfacts/lwjgl2-arm64.git
synced 2026-03-29 17:45:04 +02:00
Linux: Rewrote focus handling to cope with the weird focus behaviour when running in an XEmbed enabled jvm (applet mode)
This commit is contained in:
parent
c8d4eb6a86
commit
a015dc4558
|
|
@ -57,6 +57,18 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
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 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
|
||||
/** 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 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
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 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
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,6 +414,21 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
}
|
||||
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();
|
||||
|
|
@ -623,17 +655,49 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
|
||||
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 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
case LinuxEvent.MapNotify:
|
||||
dirty = true;
|
||||
minimized = false;
|
||||
updateInputGrab();
|
||||
break;
|
||||
case LinuxEvent.UnmapNotify:
|
||||
dirty = true;
|
||||
|
|
@ -743,29 +806,41 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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 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 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
}
|
||||
}
|
||||
|
||||
/* 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() {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import java.nio.ByteBuffer;
|
|||
* $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 @@ final class LinuxEvent {
|
|||
}
|
||||
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 @@ final class LinuxEvent {
|
|||
}
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ static Window createWindow(JNIEnv* env, Display *disp, int screen, jint window_m
|
|||
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 @@ 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) {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,29 @@ JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxEvent_getPending(JNIEnv *env,
|
|||
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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue