From d303317a31c0efc4ba1821f4120a10132a6ab982 Mon Sep 17 00:00:00 2001 From: David Maciejak Date: Wed, 4 Feb 2026 19:16:58 -0500 Subject: [PATCH] wmaker: handle keybinding change notifications This patch is to fix an issue seen on FreeBSD 15 where keybinding are mixed up at the cold start of wmaker. It is mentioned at https://github.com/window-maker/wmaker/issues/43 Seems that issue is not happening on Linux. A warm restart ("restart window maker") from the root menu is getting rid of that issue temporarily. To solve that issue, now wmaker is reloading the keyboard mapping via the new wReadKeybindings function when a XkbNewKeyboardNotifyMask event is received. It means xkb, which is part of X11 core, is now used by default and not conditionally with modelock. I tried to delay reading the keybinding as late as possible but it did not solve the issue as seems X is started with a improper keyboard by default. Here some debug trace when the bindings are loaded by wmaker on FreeBSD: Keybind F12: keycode=96 modifier=0x0 <--- cold starting wmaker Keybind F11: keycode=95 modifier=0x0 Keybind Escape: keycode=9 modifier=0x4 Keybind M: keycode=58 modifier=0x8 Keybind H: keycode=43 modifier=0x8 Keybind Up: keycode=98 modifier=0x8 <--- keycode is wrong, provided by X11 Keybind Down: keycode=104 modifier=0x8 Keybind Tab: keycode=23 modifier=0x8 Keybind Tab: keycode=23 modifier=0x9 Keybind Right: keycode=102 modifier=0xc Keybind Left: keycode=100 modifier=0xc Keybind 1: keycode=10 modifier=0x8 Keybind 2: keycode=11 modifier=0x8 Keybind 3: keycode=12 modifier=0x8 Keybind 4: keycode=13 modifier=0x8 Keybind 5: keycode=14 modifier=0x8 Keybind 6: keycode=15 modifier=0x8 Keybind 7: keycode=16 modifier=0x8 Keybind 8: keycode=17 modifier=0x8 Keybind 9: keycode=18 modifier=0x8 Keybind 0: keycode=19 modifier=0x8 Keybind Print: keycode=111 modifier=0x0 <--- keycode is wrong, 111 is UP key /usr/ports/x11-wm/windowmaker/work/WindowMaker-0.96.0/src/.libs/wmaker(execInitScript(main.c:531)): error: /root/GNUstep/Library/WindowMaker/autostart:could not execute initialization script <--- warm restart from wmaker Keybind F12: keycode=96 modifier=0x0 Keybind F11: keycode=95 modifier=0x0 Keybind Escape: keycode=9 modifier=0x4 Keybind M: keycode=58 modifier=0x8 Keybind H: keycode=43 modifier=0x8 Keybind Up: keycode=111 modifier=0x8 <--- UP key keycode is correct Keybind Down: keycode=116 modifier=0x8 Keybind Tab: keycode=23 modifier=0x8 Keybind Tab: keycode=23 modifier=0x9 Keybind Right: keycode=114 modifier=0xc Keybind Left: keycode=113 modifier=0xc Keybind 1: keycode=10 modifier=0x8 Keybind 2: keycode=11 modifier=0x8 Keybind 3: keycode=12 modifier=0x8 Keybind 4: keycode=13 modifier=0x8 Keybind 5: keycode=14 modifier=0x8 Keybind 6: keycode=15 modifier=0x8 Keybind 7: keycode=16 modifier=0x8 Keybind 8: keycode=17 modifier=0x8 Keybind 9: keycode=18 modifier=0x8 Keybind 0: keycode=19 modifier=0x8 Keybind Print: keycode=107 modifier=0x0 <--- Print keycode is correct Alternatively, to mitigate the issue, .xinitrc can be set to: setxkbmap -layout us exec wmaker or whatever layout you are using. --- src/WindowMaker.h | 2 -- src/defaults.c | 23 +++++++++++++++++++++++ src/defaults.h | 1 + src/event.c | 26 +++++++++++++++++++++----- src/screen.c | 10 +++++----- src/startup.c | 7 ++++--- 6 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/WindowMaker.h b/src/WindowMaker.h index 098a6a07..23ca8741 100644 --- a/src/WindowMaker.h +++ b/src/WindowMaker.h @@ -619,12 +619,10 @@ extern struct wmaker_global_variables { } shape; #endif -#ifdef KEEP_XKB_LOCK_STATUS struct { Bool supported; int event_base; } xkb; -#endif #ifdef USE_RANDR struct { diff --git a/src/defaults.c b/src/defaults.c index 878f18b8..8720b4ac 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -1303,6 +1303,29 @@ void wReadDefaults(WScreen * scr, WMPropList * new_dict) } } +void wReadKeybindings(WScreen *scr, WMPropList *dict) +{ + WDefaultEntry *entry; + unsigned int i; + void *tdata; + + for (i = 0; i < wlengthof(optionList); i++) { + entry = &optionList[i]; + if (entry->convert == getKeybind) { + WMPropList *plvalue = NULL; + if (dict) + plvalue = WMGetFromPLDictionary(dict, entry->plkey); + if (!plvalue) + plvalue = entry->plvalue; + if (plvalue) { + int ok = (*entry->convert)(scr, entry, plvalue, entry->addr, &tdata); + if (ok && entry->update) + (*entry->update)(scr, entry, tdata, entry->extra_data); + } + } + } +} + void wDefaultUpdateIcons(WScreen *scr) { WAppIcon *aicon = scr->app_icon_list; diff --git a/src/defaults.h b/src/defaults.h index a03ff345..5aaf448a 100644 --- a/src/defaults.h +++ b/src/defaults.h @@ -33,6 +33,7 @@ WDDomain * wDefaultsInitDomain(const char *domain, Bool requireDictionary); void wDefaultsMergeGlobalMenus(WDDomain *menuDomain); void wReadDefaults(WScreen *scr, WMPropList *new_dict); +void wReadKeybindings(WScreen *scr, WMPropList *dict); void wDefaultUpdateIcons(WScreen *scr); void wReadStaticDefaults(WMPropList *dict); void wDefaultsCheckDomains(void *arg); diff --git a/src/event.c b/src/event.c index 67d30098..99fbba5a 100644 --- a/src/event.c +++ b/src/event.c @@ -49,9 +49,7 @@ #include #endif -#ifdef KEEP_XKB_LOCK_STATUS #include -#endif /* KEEP_XKB_LOCK_STATUS */ #include "WindowMaker.h" #include "window.h" @@ -103,7 +101,9 @@ static void handleKeyPress(XEvent *event); static void handleFocusIn(XEvent *event); static void handleMotionNotify(XEvent *event); static void handleVisibilityNotify(XEvent *event); +#ifdef HAVE_INOTIFY static void handle_inotify_events(void); +#endif static void handle_selection_request(XSelectionRequestEvent *event); static void handle_selection_clear(XSelectionClearEvent *event); static void wdelete_death_handler(WMagicNumber id); @@ -569,11 +569,26 @@ static void handleExtensions(XEvent * event) handleShapeNotify(event); } #endif + if (w_global.xext.xkb.supported && event->type == w_global.xext.xkb.event_base) { + XkbEvent *xkbevent = (XkbEvent *) event; + + if (xkbevent->any.xkb_type == XkbNewKeyboardNotify) { + int j; + WScreen *scr; + + for (j = 0; j < w_global.screen_count; j++) { + scr = wScreenWithNumber(j); + wReadKeybindings(scr, w_global.domain.wmaker->dictionary); + } + } #ifdef KEEP_XKB_LOCK_STATUS - if (wPreferences.modelock && (event->type == w_global.xext.xkb.event_base)) { - handleXkbIndicatorStateNotify((XkbEvent *) event); + else { + if (wPreferences.modelock && (xkbevent->any.xkb_type == XkbIndicatorStateNotify)) { + handleXkbIndicatorStateNotify((XkbEvent *) event); + } + } +#endif /*KEEP_XKB_LOCK_STATUS */ } -#endif /*KEEP_XKB_LOCK_STATUS */ #ifdef USE_RANDR if (w_global.xext.randr.supported && event->type == (w_global.xext.randr.event_base + RRScreenChangeNotify)) { /* From xrandr man page: "Clients must call back into Xlib using @@ -1275,6 +1290,7 @@ static void handleXkbIndicatorStateNotify(XkbEvent *event) WScreen *scr; XkbStateRec staterec; int i; + (void) event; for (i = 0; i < w_global.screen_count; i++) { scr = wScreenWithNumber(i); diff --git a/src/screen.c b/src/screen.c index 3a2fd3b7..009622dd 100644 --- a/src/screen.c +++ b/src/screen.c @@ -32,9 +32,7 @@ #include #include #include -#ifdef KEEP_XKB_LOCK_STATUS #include -#endif /* KEEP_XKB_LOCK_STATUS */ #ifdef USE_RANDR #include #endif @@ -663,9 +661,11 @@ WScreen *wScreenInit(int screen_number) /* Only GroupLock doesn't work correctly in my system since right-alt * can change mode while holding it too - ]d */ - if (w_global.xext.xkb.supported) { - XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask); - } + if (w_global.xext.xkb.supported) + XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask, XkbIndicatorStateNotifyMask|XkbNewKeyboardNotifyMask); +#else + if (w_global.xext.xkb.supported) + XkbSelectEvents(dpy, XkbUseCoreKbd, XkbNewKeyboardNotifyMask, XkbNewKeyboardNotifyMask); #endif /* KEEP_XKB_LOCK_STATUS */ #ifdef USE_RANDR diff --git a/src/startup.c b/src/startup.c index ddaf789f..f74df8f2 100644 --- a/src/startup.c +++ b/src/startup.c @@ -41,9 +41,7 @@ #ifdef USE_XSHAPE #include #endif -#ifdef KEEP_XKB_LOCK_STATUS #include -#endif #ifdef USE_RANDR #include #endif @@ -601,12 +599,15 @@ void StartUp(Bool defaultScreenOnly) w_global.xext.randr.supported = XRRQueryExtension(dpy, &w_global.xext.randr.event_base, &j); #endif -#ifdef KEEP_XKB_LOCK_STATUS w_global.xext.xkb.supported = XkbQueryExtension(dpy, NULL, &w_global.xext.xkb.event_base, NULL, NULL, NULL); +#ifdef KEEP_XKB_LOCK_STATUS if (wPreferences.modelock && !w_global.xext.xkb.supported) { wwarning(_("XKB is not supported. KbdModeLock is automatically disabled.")); wPreferences.modelock = 0; } +#else + if (!w_global.xext.xkb.supported) + wwarning(_("XKB is not supported.")); #endif if (defaultScreenOnly)