From 2e170ad06fdc461a6ce486d39bc5aa16aaece25a Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Wed, 15 Dec 2021 00:16:57 +1100 Subject: [PATCH] [client] x11: properly detect WMEH support for focus events --- client/displayservers/X11/atoms.h | 4 ++ client/displayservers/X11/x11.c | 93 ++++++++++++++++++++++++++++++- client/displayservers/X11/x11.h | 5 ++ 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/client/displayservers/X11/atoms.h b/client/displayservers/X11/atoms.h index c9d0a7ad..5686f954 100644 --- a/client/displayservers/X11/atoms.h +++ b/client/displayservers/X11/atoms.h @@ -22,11 +22,15 @@ #define _H_X11DS_ATOMS_ #define DEF_ATOMS() \ + DEF_ATOM(_NET_SUPPORTING_WM_CHECK, True) \ + DEF_ATOM(_NET_SUPPORTED, True) \ + DEF_ATOM(_NET_WM_NAME, True) \ DEF_ATOM(_NET_REQUEST_FRAME_EXTENTS, True) \ DEF_ATOM(_NET_FRAME_EXTENTS, True) \ DEF_ATOM(_NET_WM_BYPASS_COMPOSITOR, False) \ DEF_ATOM(_NET_WM_STATE, True) \ DEF_ATOM(_NET_WM_STATE_FULLSCREEN, True) \ + DEF_ATOM(_NET_WM_STATE_FOCUSED, True) \ DEF_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ, True) \ DEF_ATOM(_NET_WM_STATE_MAXIMIZED_VERT, True) \ DEF_ATOM(_NET_WM_WINDOW_TYPE, True) \ diff --git a/client/displayservers/X11/x11.c b/client/displayservers/X11/x11.c index 18ae2398..aa104d60 100644 --- a/client/displayservers/X11/x11.c +++ b/client/displayservers/X11/x11.c @@ -82,6 +82,7 @@ static void x11SetFullscreen(bool fs); static int x11EventThread(void * unused); static void x11XInputEvent(XGenericEventCookie *cookie); static void x11XPresentEvent(XGenericEventCookie *cookie); +static void x11GrabPointer(void); static void x11DoPresent(void) { @@ -167,6 +168,69 @@ static bool x11EarlyInit(void) return true; } +static void x11CheckEWMHSupport(void) +{ + if (x11atoms._NET_SUPPORTING_WM_CHECK == None || + x11atoms._NET_SUPPORTED == None) + return; + + Atom type; + int fmt; + unsigned long num, bytes; + unsigned char *data; + + if (XGetWindowProperty(x11.display, DefaultRootWindow(x11.display), + x11atoms._NET_SUPPORTING_WM_CHECK, 0, ~0L, False, XA_WINDOW, + &type, &fmt, &num, &bytes, &data) != Success) + goto out; + + Window * windowFromRoot = (Window *)data; + + if (XGetWindowProperty(x11.display, *windowFromRoot, + x11atoms._NET_SUPPORTING_WM_CHECK, 0, ~0L, False, XA_WINDOW, + &type, &fmt, &num, &bytes, &data) != Success) + goto out_root; + + Window * windowFromChild = (Window *)data; + if (*windowFromChild != *windowFromRoot) + goto out_child; + + if (XGetWindowProperty(x11.display, DefaultRootWindow(x11.display), + x11atoms._NET_SUPPORTED, 0, ~0L, False, AnyPropertyType, + &type, &fmt, &num, &bytes, &data) != Success) + goto out_child; + + Atom * supported = (Atom *)data; + unsigned long supportedCount = num; + + if (XGetWindowProperty(x11.display, *windowFromRoot, + x11atoms._NET_WM_NAME, 0, ~0L, False, AnyPropertyType, + &type, &fmt, &num, &bytes, &data) != Success) + goto out_supported; + + char * wmName = (char *)data; + + for(unsigned long i = 0; i < supportedCount; ++i) + { + if (supported[i] == x11atoms._NET_WM_STATE_FOCUSED) + x11.ewmhHasFocusEvent = true; + } + + DEBUG_INFO("EWMH-complient window manager detected: %s", wmName); + x11.ewmhSupport = true; + + + XFree(wmName); +out_supported: + XFree(supported); +out_child: + XFree(windowFromChild); +out_root: + XFree(windowFromRoot); +out: + return; +} + static bool x11Init(const LG_DSInitParams params) { XIDeviceInfo *devinfo; @@ -272,6 +336,9 @@ static bool x11Init(const LG_DSInitParams params) X11AtomsInit(); XSetWMProtocols(x11.display, x11.window, &x11atoms.WM_DELETE_WINDOW, 1); + // check for Extended Window Manager Hints support + x11CheckEWMHSupport(); + if (params.borderless) { if (x11atoms._MOTIF_WM_HINTS) @@ -457,8 +524,12 @@ static bool x11Init(const LG_DSInitParams params) eventmask.mask_len = sizeof(mask); eventmask.mask = mask; - XISetMask(mask, XI_FocusIn ); - XISetMask(mask, XI_FocusOut ); + if (!x11.ewmhHasFocusEvent) + { + XISetMask(mask, XI_FocusIn ); + XISetMask(mask, XI_FocusOut); + } + XISetMask(mask, XI_Enter ); XISetMask(mask, XI_Leave ); XISetMask(mask, XI_Motion ); @@ -839,6 +910,7 @@ static int x11EventThread(void * unused) } case PropertyNotify: + // ignore property events that are not for us if (xe.xproperty.display != x11.display || xe.xproperty.window != x11.window || @@ -860,11 +932,20 @@ static int x11EventThread(void * unused) break; bool fullscreen = false; - for(int i = 0; i < num; ++i) + bool focused = false; + for(unsigned long i = 0; i < num; ++i) { Atom prop = ((Atom *)data)[i]; if (prop == x11atoms._NET_WM_STATE_FULLSCREEN) fullscreen = true; + else if (prop == x11atoms._NET_WM_STATE_FOCUSED) + focused = true; + } + + if (x11.focused != focused) + { + x11.focused = focused; + app_handleFocusEvent(focused); } x11.fullscreen = fullscreen; @@ -941,6 +1022,9 @@ static void x11XInputEvent(XGenericEventCookie *cookie) { case XI_FocusIn: { + if (x11.ewmhHasFocusEvent) + return; + atomic_store(&x11.lastWMEvent, microtime()); if (x11.focused) return; @@ -959,6 +1043,9 @@ static void x11XInputEvent(XGenericEventCookie *cookie) case XI_FocusOut: { + if (x11.ewmhHasFocusEvent) + return; + atomic_store(&x11.lastWMEvent, microtime()); if (!x11.focused) return; diff --git a/client/displayservers/X11/x11.h b/client/displayservers/X11/x11.h index 5f339d69..4d6532d5 100644 --- a/client/displayservers/X11/x11.h +++ b/client/displayservers/X11/x11.h @@ -54,6 +54,11 @@ struct X11DSState Window window; XVisualInfo * visual; + //Extended Window Manager Hints + //ref: https://specifications.freedesktop.org/wm-spec/latest/ + bool ewmhSupport; + bool ewmhHasFocusEvent; + _Atomic(uint64_t) lastWMEvent; bool invalidateAll;