From c2baa4702667db0b20e8e0e9de33894702711a3f Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sun, 16 Aug 2026 16:16:44 +0900 Subject: [PATCH] fix(xim): follow keyboard layout changes kinit() sets up the XKB extension, after which the server stops sending core MappingNotify to this client, so the refresh branch never fired and strans kept its startup keymap; setxkbmap after launch left every XIM key resolved against the old layout. Select XKB NewKeyboardNotify and MapNotify (with the map parts, or MapNotify is never delivered) and rebuild the keymap on those events instead. --- Makefile | 4 ++-- tests/Makefile | 4 ++-- xim/xim.c | 24 ++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 63ea71c..fc4a521 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,8 @@ CFLAGS ?= -O2 -g WARN_CFLAGS = -Wall -Wextra IBUS_CFLAGS = $(shell $(PKG_CONFIG) --cflags dbus-1 xkbcommon) IBUS_LIBS = $(shell $(PKG_CONFIG) --libs dbus-1 xkbcommon) -XIM_CFLAGS = $(shell $(PKG_CONFIG) --cflags xcb-imdkit xkbcommon-x11) -XIM_LIBS = $(shell $(PKG_CONFIG) --libs xcb-imdkit xkbcommon-x11) +XIM_CFLAGS = $(shell $(PKG_CONFIG) --cflags xcb-imdkit xcb-xkb xkbcommon-x11) +XIM_LIBS = $(shell $(PKG_CONFIG) --libs xcb-imdkit xcb-xkb xkbcommon-x11) TEXT_CFLAGS = $(shell $(PKG_CONFIG) --cflags pangocairo cairo) TEXT_LIBS = $(shell $(PKG_CONFIG) --libs pangocairo cairo) POPUP_CFLAGS = $(shell $(PKG_CONFIG) --cflags xcb-randr) diff --git a/tests/Makefile b/tests/Makefile index aa4b8be..53a1c13 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -18,8 +18,8 @@ IBUS_CLIENT_CFLAGS = $(shell $(PKG_CONFIG) --cflags ibus-1.0) IBUS_CLIENT_LIBS = $(shell $(PKG_CONFIG) --libs ibus-1.0) X11_CFLAGS = $(shell $(PKG_CONFIG) --cflags x11) X11_LIBS = $(shell $(PKG_CONFIG) --libs x11) -XIM_CFLAGS = $(shell $(PKG_CONFIG) --cflags xcb-imdkit xkbcommon-x11) -XIM_LIBS = $(shell $(PKG_CONFIG) --libs xcb-imdkit xkbcommon-x11) +XIM_CFLAGS = $(shell $(PKG_CONFIG) --cflags xcb-imdkit xcb-xkb xkbcommon-x11) +XIM_LIBS = $(shell $(PKG_CONFIG) --libs xcb-imdkit xcb-xkb xkbcommon-x11) UNIT_LDLIBS = -lthread -lbio $(TEXT_LIBS) $(IBUS_LIBS) $(XIM_LIBS) PROG = unit_test diff --git a/xim/xim.c b/xim/xim.c index 977da11..dc90091 100644 --- a/xim/xim.c +++ b/xim/xim.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ enum static xcb_connection_t *conn; static xcb_im_t *xim; static struct xkb_state *kstate; +static uint8_t xkbevent; static xcb_window_t rootwin; static Ic *ics; static Ic *preowner; @@ -55,6 +57,7 @@ ximlog(char *msg) fprint(2, "strans: xim: %s\n", msg); } +/* Reads the server's keymap; XKB-aware clients get XKB events, not MappingNotify. */ static int kinit(void) { @@ -70,7 +73,7 @@ kinit(void) context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if(context == nil || !xkb_x11_setup_xkb_extension(conn, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, - XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nil, nil, nil, nil)) + XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, nil, nil, &xkbevent, nil)) goto out; device = xkb_x11_get_core_keyboard_device_id(conn); if(device < 0) @@ -93,6 +96,22 @@ out: return ok; } +static void +kwatch(void) +{ + u16int events, parts; + + events = XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY | + XCB_XKB_EVENT_TYPE_MAP_NOTIFY; + parts = XCB_XKB_MAP_PART_KEY_TYPES | XCB_XKB_MAP_PART_KEY_SYMS | + XCB_XKB_MAP_PART_MODIFIER_MAP | + XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS | + XCB_XKB_MAP_PART_KEY_ACTIONS | XCB_XKB_MAP_PART_VIRTUAL_MODS | + XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP; + xcb_xkb_select_events(conn, XCB_XKB_ID_USE_CORE_KBD, events, 0, + events, parts, parts, nil); +} + static xcb_screen_t* getscreen(int scr) { @@ -472,6 +491,7 @@ ximinit(void) ximlog("cannot read keyboard mapping"); return -1; } + kwatch(); win = xcb_generate_id(conn); xcb_create_window(conn, XCB_COPY_FROM_PARENT, win, screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, @@ -511,7 +531,7 @@ ximthread(void *arg) break; while((ev = xcb_poll_for_event(conn)) != nil){ type = ev->response_type & ~0x80; - if(type == XCB_MAPPING_NOTIFY){ + if(type == xkbevent){ if(kinit() < 0) ximlog("cannot refresh keyboard mapping"); }else