From 3f5a0f0024b7c77fadea6431e356c0fc060e2986 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 2 Jan 2014 08:40:03 +0100 Subject: [PATCH] Switch to xcb-xkb and libxkbcommon MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This removes our last dependency on Xlib! :) (Okay, an Xlib dependency still comes in through other libraries that we link against, but it’s not us. Our code is simpler by this change and uses one less connection to X11.) --- common.mk | 8 +- debian/control | 3 + i3-config-wizard/i3-config-wizard.mk | 4 +- i3-config-wizard/main.c | 47 ++++++- i3bar/i3bar.mk | 4 +- i3bar/src/xcb.c | 199 +++++++++++---------------- include/handlers.h | 1 + include/i3.h | 1 + src/bindings.c | 6 +- src/config.c | 4 +- src/handlers.c | 40 ++++++ src/i3.mk | 4 +- src/main.c | 137 +++--------------- 13 files changed, 200 insertions(+), 258 deletions(-) diff --git a/common.mk b/common.mk index b086bc85..b9e15a28 100644 --- a/common.mk +++ b/common.mk @@ -92,6 +92,7 @@ else XCB_CFLAGS += $(call cflags_for_lib, xcb-util) XCB_LIBS += $(call ldflags_for_lib, xcb-util) endif +XCB_XKB_LIBS := $(call ldflags_for_lib, xcb-xkb,xcb-xkb) # XCB keyboard stuff XCB_KBD_CFLAGS := $(call cflags_for_lib, xcb-keysyms) @@ -105,9 +106,10 @@ XCB_WM_LIBS := $(call ldflags_for_lib, xcb-icccm,xcb-icccm) XCB_WM_LIBS += $(call ldflags_for_lib, xcb-xinerama,xcb-xinerama) XCB_WM_LIBS += $(call ldflags_for_lib, xcb-randr,xcb-randr) -# Xlib -X11_CFLAGS := $(call cflags_for_lib, x11) -X11_LIBS := $(call ldflags_for_lib, x11,X11) +XKB_COMMON_CFLAGS := $(call cflags_for_lib, xkbcommon,xkbcommon) +XKB_COMMON_LIBS := $(call ldflags_for_lib, xkbcommon,xkbcommon) +XKB_COMMON_X11_CFLAGS := $(call cflags_for_lib, xkbcommon-x11,xkbcommon-x11) +XKB_COMMON_X11_LIBS := $(call ldflags_for_lib, xkbcommon-x11,xkbcommon-x11) # Xcursor XCURSOR_CFLAGS := $(call cflags_for_lib, xcb-cursor) diff --git a/debian/control b/debian/control index b36d5db4..9f6518e0 100644 --- a/debian/control +++ b/debian/control @@ -10,6 +10,9 @@ Build-Depends: debhelper (>= 7.0.50~), libxcb-randr0-dev, libxcb-icccm4-dev, libxcb-cursor-dev, + libxcb-xkb-dev, + libxkbcommon-dev, + libxkbcommon-x11-dev, asciidoc (>= 8.4.4), xmlto, docbook-xml, diff --git a/i3-config-wizard/i3-config-wizard.mk b/i3-config-wizard/i3-config-wizard.mk index e759b4bd..1dab6452 100644 --- a/i3-config-wizard/i3-config-wizard.mk +++ b/i3-config-wizard/i3-config-wizard.mk @@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3-config-wizard i3_config_wizard_SOURCES := $(wildcard i3-config-wizard/*.c) i3_config_wizard_HEADERS := $(wildcard i3-config-wizard/*.h) -i3_config_wizard_CFLAGS = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(X11_CFLAGS) $(PANGO_CFLAGS) -i3_config_wizard_LIBS = $(XCB_LIBS) $(XCB_KBD_LIBS) $(X11_LIBS) $(PANGO_LIBS) +i3_config_wizard_CFLAGS = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(PANGO_CFLAGS) $(XKB_COMMON_CFLAGS) $(XKB_COMMON_X11_CFLAGS) +i3_config_wizard_LIBS = $(XCB_LIBS) $(XCB_KBD_LIBS) $(PANGO_LIBS) $(XKB_COMMON_LIBS) $(XKB_COMMON_X11_LIBS) i3_config_wizard_OBJECTS := $(i3_config_wizard_SOURCES:.c=.o) diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index a76c211e..c09d459d 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -43,6 +43,9 @@ #include #include +#include +#include + #include #include #include @@ -83,7 +86,9 @@ static xcb_pixmap_t pixmap; static xcb_gcontext_t pixmap_gc; static xcb_key_symbols_t *symbols; xcb_window_t root; -Display *dpy; +static struct xkb_keymap *xkb_keymap; +static uint8_t xkb_base_event; +static uint8_t xkb_base_error; static void finish(); @@ -250,12 +255,24 @@ static char *next_state(const cmdp_token *token) { * This reduces a lot of confusion for users who switch keyboard * layouts from qwerty to qwertz or other slight variations of * qwerty (yes, that happens quite often). */ - KeySym sym = XkbKeycodeToKeysym(dpy, keycode, 0, 0); - if (!keysym_used_on_other_key(sym, keycode)) + const xkb_keysym_t *syms; + int num = xkb_keymap_key_get_syms_by_level(xkb_keymap, keycode, 0, 0, &syms); + if (num == 0) + errx(1, "xkb_keymap_key_get_syms_by_level returned no symbols for keycode %d", keycode); + if (!keysym_used_on_other_key(syms[0], keycode)) level = 0; } - KeySym sym = XkbKeycodeToKeysym(dpy, keycode, 0, level); - char *str = XKeysymToString(sym); + + const xkb_keysym_t *syms; + int num = xkb_keymap_key_get_syms_by_level(xkb_keymap, keycode, 0, level, &syms); + if (num == 0) + errx(1, "xkb_keymap_key_get_syms_by_level returned no symbols for keycode %d", keycode); + if (num > 1) + printf("xkb_keymap_key_get_syms_by_level (keycode = %d) returned %d symbolsinstead of 1, using only the first one.\n", keycode, num); + + char str[4096]; + if (xkb_keysym_get_name(syms[0], str, sizeof(str)) == -1) + errx(EXIT_FAILURE, "xkb_keysym_get_name(%u) failed", syms[0]); const char *release = get_string("release"); char *res; char *modrep = (modifiers == NULL ? sstrdup("") : sstrdup(modifiers)); @@ -642,8 +659,14 @@ static void handle_button_press(xcb_button_press_event_t *event) { static void finish() { printf("creating \"%s\"...\n", config_path); - if (!(dpy = XOpenDisplay(NULL))) - errx(1, "Could not connect to X11"); + struct xkb_context *xkb_context; + + if ((xkb_context = xkb_context_new(0)) == NULL) + errx(1, "could not create xkbcommon context"); + + int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn); + if ((xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) + errx(1, "xkb_x11_keymap_new_from_device failed"); FILE *kc_config = fopen(SYSCONFDIR "/i3/config.keycodes", "r"); if (kc_config == NULL) @@ -797,6 +820,16 @@ int main(int argc, char *argv[]) { xcb_connection_has_error(conn)) errx(1, "Cannot open display\n"); + if (xkb_x11_setup_xkb_extension(conn, + XKB_X11_MIN_MAJOR_XKB_VERSION, + XKB_X11_MIN_MINOR_XKB_VERSION, + 0, + NULL, + NULL, + &xkb_base_event, + &xkb_base_error) != 1) + errx(EXIT_FAILURE, "Could not setup XKB extension."); + if (socket_path == NULL) socket_path = root_atom_contents("I3_SOCKET_PATH", conn, screen); diff --git a/i3bar/i3bar.mk b/i3bar/i3bar.mk index 06780250..53227a8e 100644 --- a/i3bar/i3bar.mk +++ b/i3bar/i3bar.mk @@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3bar i3bar_SOURCES := $(wildcard i3bar/src/*.c) i3bar_HEADERS := $(wildcard i3bar/include/*.h) -i3bar_CFLAGS = $(XCB_CFLAGS) $(X11_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS) -i3bar_LIBS = $(XCB_LIBS) $(X11_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) +i3bar_CFLAGS = $(XCB_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS) +i3bar_LIBS = $(XCB_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(XCB_XKB_LIBS) i3bar_OBJECTS := $(i3bar_SOURCES:.c=.o) diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c index 763942af..37a13347 100644 --- a/i3bar/src/xcb.c +++ b/i3bar/src/xcb.c @@ -8,6 +8,7 @@ * */ #include +#include #include #include @@ -63,8 +64,7 @@ static i3Font font; int bar_height; /* These are only relevant for XKB, which we only need for grabbing modifiers */ -Display *xkb_dpy; -int xkb_event_base; +int xkb_base; int mod_pressed = 0; /* Because the statusline is the same on all outputs, we have @@ -854,7 +854,62 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { } while ((event = xcb_poll_for_event(xcb_connection)) != NULL) { - switch (event->response_type & ~0x80) { + int type = (event->response_type & ~0x80); + + if (type == xkb_base && xkb_base > -1) { + DLOG("received an xkb event\n"); + + xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event; + if (state->xkbType == XCB_XKB_STATE_NOTIFY) { + int modstate = state->mods & config.modifier; + +#define DLOGMOD(modmask, status) \ + do { \ + switch (modmask) { \ + case ShiftMask: \ + DLOG("ShiftMask got " #status "!\n"); \ + break; \ + case ControlMask: \ + DLOG("ControlMask got " #status "!\n"); \ + break; \ + case Mod1Mask: \ + DLOG("Mod1Mask got " #status "!\n"); \ + break; \ + case Mod2Mask: \ + DLOG("Mod2Mask got " #status "!\n"); \ + break; \ + case Mod3Mask: \ + DLOG("Mod3Mask got " #status "!\n"); \ + break; \ + case Mod4Mask: \ + DLOG("Mod4Mask got " #status "!\n"); \ + break; \ + case Mod5Mask: \ + DLOG("Mod5Mask got " #status "!\n"); \ + break; \ + } \ + } while (0) + + if (modstate != mod_pressed) { + if (modstate == 0) { + DLOGMOD(config.modifier, released); + if (!activated_mode) + hide_bars(); + } else { + DLOGMOD(config.modifier, pressed); + activated_mode = false; + unhide_bars(); + } + mod_pressed = modstate; + } +#undef DLOGMOD + } + + free(event); + continue; + } + + switch (type) { case XCB_EXPOSE: /* Expose-events happen, when the window needs to be redrawn */ redraw_bars(); @@ -900,76 +955,6 @@ void xcb_chk_cb(struct ev_loop *loop, ev_check *watcher, int revents) { void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { } -/* - * We need to bind to the modifier per XKB. Sadly, XCB does not implement this - * - */ -void xkb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) { - XkbEvent ev; - int modstate = 0; - - DLOG("Got XKB-Event!\n"); - - while (XPending(xkb_dpy)) { - XNextEvent(xkb_dpy, (XEvent *)&ev); - - if (ev.type != xkb_event_base) { - ELOG("No Xkb-Event!\n"); - continue; - } - - if (ev.any.xkb_type != XkbStateNotify) { - ELOG("No State Notify!\n"); - continue; - } - - unsigned int mods = ev.state.mods; - modstate = mods & config.modifier; - } - -#define DLOGMOD(modmask, status) \ - do { \ - switch (modmask) { \ - case ShiftMask: \ - DLOG("ShiftMask got " #status "!\n"); \ - break; \ - case ControlMask: \ - DLOG("ControlMask got " #status "!\n"); \ - break; \ - case Mod1Mask: \ - DLOG("Mod1Mask got " #status "!\n"); \ - break; \ - case Mod2Mask: \ - DLOG("Mod2Mask got " #status "!\n"); \ - break; \ - case Mod3Mask: \ - DLOG("Mod3Mask got " #status "!\n"); \ - break; \ - case Mod4Mask: \ - DLOG("Mod4Mask got " #status "!\n"); \ - break; \ - case Mod5Mask: \ - DLOG("Mod5Mask got " #status "!\n"); \ - break; \ - } \ - } while (0) - - if (modstate != mod_pressed) { - if (modstate == 0) { - DLOGMOD(config.modifier, released); - if (!activated_mode) - hide_bars(); - } else { - DLOGMOD(config.modifier, pressed); - activated_mode = false; - unhide_bars(); - } - mod_pressed = modstate; - } - -#undef DLOGMOD -} - /* * Early initialization of the connection to X11: Everything which does not * depend on 'config'. @@ -1053,44 +1038,23 @@ char *init_xcb_early() { * */ void register_xkb_keyevents() { - if (xkb_dpy == NULL) { - int xkb_major, xkb_minor, xkb_errbase, xkb_err; - xkb_major = XkbMajorVersion; - xkb_minor = XkbMinorVersion; - - xkb_dpy = XkbOpenDisplay(NULL, - &xkb_event_base, - &xkb_errbase, - &xkb_major, - &xkb_minor, - &xkb_err); - - if (xkb_dpy == NULL) { - ELOG("No XKB!\n"); - exit(EXIT_FAILURE); - } - - if (fcntl(ConnectionNumber(xkb_dpy), F_SETFD, FD_CLOEXEC) == -1) { - ELOG("Could not set FD_CLOEXEC on xkbdpy: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - int i1; - if (!XkbQueryExtension(xkb_dpy, &i1, &xkb_event_base, &xkb_errbase, &xkb_major, &xkb_minor)) { - ELOG("XKB not supported by X-server!\n"); - exit(EXIT_FAILURE); - } - - if (!XkbSelectEvents(xkb_dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask)) { - ELOG("Could not grab Key!\n"); - exit(EXIT_FAILURE); - } - - xkb_io = smalloc(sizeof(ev_io)); - ev_io_init(xkb_io, &xkb_io_cb, ConnectionNumber(xkb_dpy), EV_READ); - ev_io_start(main_loop, xkb_io); - XFlush(xkb_dpy); + const xcb_query_extension_reply_t *extreply; + extreply = xcb_get_extension_data(conn, &xcb_xkb_id); + if (!extreply->present) { + ELOG("xkb is not present on this server\n"); + exit(EXIT_FAILURE); } + DLOG("initializing xcb-xkb\n"); + xcb_xkb_use_extension(conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION); + xcb_xkb_select_events(conn, + XCB_XKB_ID_USE_CORE_KBD, + XCB_XKB_EVENT_TYPE_STATE_NOTIFY, + 0, + XCB_XKB_EVENT_TYPE_STATE_NOTIFY, + 0xff, + 0xff, + NULL); + xkb_base = extreply->first_event; } /* @@ -1098,13 +1062,14 @@ void register_xkb_keyevents() { * */ void deregister_xkb_keyevents() { - if (xkb_dpy != NULL) { - ev_io_stop(main_loop, xkb_io); - XCloseDisplay(xkb_dpy); - close(xkb_io->fd); - FREE(xkb_io); - xkb_dpy = NULL; - } + xcb_xkb_select_events(conn, + XCB_XKB_ID_USE_CORE_KBD, + 0, + 0, + 0, + 0xff, + 0xff, + NULL); } /* diff --git a/include/handlers.h b/include/handlers.h index db7d06b5..82f6b982 100644 --- a/include/handlers.h +++ b/include/handlers.h @@ -13,6 +13,7 @@ #include extern int randr_base; +extern int xkb_base; /** * Adds the given sequence to the list of events which are ignored. diff --git a/include/i3.h b/include/i3.h index c70a5c5b..5ca87541 100644 --- a/include/i3.h +++ b/include/i3.h @@ -13,6 +13,7 @@ #include #include +#include #include diff --git a/src/bindings.c b/src/bindings.c index a7039bf2..cd91a398 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -8,6 +8,8 @@ */ #include "all.h" +#include + pid_t command_error_nagbar_pid = -1; /* @@ -263,8 +265,8 @@ void translate_keysyms(void) { continue; /* We need to translate the symbol to a keycode */ - keysym = XStringToKeysym(bind->symbol); - if (keysym == NoSymbol) { + keysym = xkb_keysym_from_name(bind->symbol, XKB_KEYSYM_NO_FLAGS); + if (keysym == XKB_KEY_NoSymbol) { ELOG("Could not translate string to key symbol: \"%s\"\n", bind->symbol); continue; diff --git a/src/config.c b/src/config.c index 781ff6b8..ec084bb1 100644 --- a/src/config.c +++ b/src/config.c @@ -11,9 +11,7 @@ * */ #include "all.h" - -/* We need Xlib for XStringToKeysym */ -#include +#include char *current_configpath = NULL; Config config; diff --git a/src/handlers.c b/src/handlers.c index ba9b1211..80297c79 100644 --- a/src/handlers.c +++ b/src/handlers.c @@ -21,6 +21,8 @@ #include int randr_base = -1; +int xkb_base = -1; +int xkb_current_group; /* After mapping/unmapping windows, a notify event is generated. However, we don’t want it, since it’d trigger an infinite loop of switching between the different windows when @@ -1115,12 +1117,50 @@ static void property_notify(uint8_t state, xcb_window_t window, xcb_atom_t atom) * */ void handle_event(int type, xcb_generic_event_t *event) { + DLOG("event type %d, xkb_base %d\n", type, xkb_base); if (randr_base > -1 && type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { handle_screen_change(event); return; } + if (xkb_base > -1 && type == xkb_base) { + DLOG("xkb event, need to handle it.\n"); + + xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event; + if (state->xkbType == XCB_XKB_MAP_NOTIFY) { + if (event_is_ignored(event->sequence, type)) { + DLOG("Ignoring map notify event for sequence %d.\n", state->sequence); + } else { + DLOG("xkb map notify, sequence %d, time %d\n", state->sequence, state->time); + add_ignore_event(event->sequence, type); + ungrab_all_keys(conn); + translate_keysyms(); + grab_all_keys(conn, false); + } + } else if (state->xkbType == XCB_XKB_STATE_NOTIFY) { + DLOG("xkb state group = %d\n", state->group); + + /* See The XKB Extension: Library Specification, section 14.1 */ + /* We check if the current group (each group contains + * two levels) has been changed. Mode_switch activates + * group XkbGroup2Index */ + if (xkb_current_group == state->group) + return; + xkb_current_group = state->group; + if (state->group == XCB_XKB_GROUP_1) { + DLOG("Mode_switch disabled\n"); + ungrab_all_keys(conn); + grab_all_keys(conn, false); + } else { + DLOG("Mode_switch enabled\n"); + grab_all_keys(conn, false); + } + } + + return; + } + switch (type) { case XCB_KEY_PRESS: case XCB_KEY_RELEASE: diff --git a/src/i3.mk b/src/i3.mk index 0325d82a..f1105a04 100644 --- a/src/i3.mk +++ b/src/i3.mk @@ -5,8 +5,8 @@ CLEAN_TARGETS += clean-i3 i3_SOURCES := $(filter-out $(i3_SOURCES_GENERATED),$(wildcard src/*.c)) i3_HEADERS_CMDPARSER := $(wildcard include/GENERATED_*.h) i3_HEADERS := $(filter-out $(i3_HEADERS_CMDPARSER),$(wildcard include/*.h)) -i3_CFLAGS = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(XCB_WM_CFLAGS) $(X11_CFLAGS) $(XCURSOR_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS) $(PCRE_CFLAGS) $(LIBSN_CFLAGS) -i3_LIBS = $(XCB_LIBS) $(XCB_KBD_LIBS) $(XCB_WM_LIBS) $(X11_LIBS) $(XCURSOR_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(PCRE_LIBS) $(LIBSN_LIBS) -lm -lpthread +i3_CFLAGS = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(XCB_WM_CFLAGS) $(XCURSOR_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS) $(PCRE_CFLAGS) $(LIBSN_CFLAGS) +i3_LIBS = $(XKB_COMMON_LIBS) $(XCB_LIBS) $(XCB_XKB_LIBS) $(XCB_KBD_LIBS) $(XCB_WM_LIBS) $(XCURSOR_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(PCRE_LIBS) $(LIBSN_LIBS) -lm -lpthread # When using clang, we use pre-compiled headers to speed up the build. With # gcc, this actually makes the build slower. diff --git a/src/main.c b/src/main.c index 917ae1cb..ac112446 100644 --- a/src/main.c +++ b/src/main.c @@ -36,10 +36,6 @@ int listen_fds; * temporarily for drag_pointer(). */ static struct ev_check *xcb_check; -static int xkb_event_base; - -int xkb_current_group; - extern Con *focused; char **start_argv; @@ -70,9 +66,6 @@ struct ev_loop *main_loop; xcb_key_symbols_t *keysyms; -/* Those are our connections to X11 for use with libXcursor and XKB */ -Display *xlibdpy, *xkbdpy; - /* Default shmlog size if not set by user. */ const int default_shmlog_size = 25 * 1024 * 1024; @@ -94,7 +87,6 @@ struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignment /* We hope that those are supported and set them to true */ bool xcursor_supported = true; -bool xkb_supported = true; /* This will be set to true when -C is used so that functions can behave * slightly differently. We don’t want i3-nagbar to be started when validating @@ -166,73 +158,6 @@ void main_set_x11_cb(bool enable) { } } -/* - * When using xmodmap to change the keyboard mapping, this event - * is only sent via XKB. Therefore, we need this special handler. - * - */ -static void xkb_got_event(EV_P_ struct ev_io *w, int revents) { - DLOG("Handling XKB event\n"); - XkbEvent ev; - - /* When using xmodmap, every change (!) gets an own event. - * Therefore, we just read all events and only handle the - * mapping_notify once. */ - bool mapping_changed = false; - while (XPending(xkbdpy)) { - XNextEvent(xkbdpy, (XEvent *)&ev); - /* While we should never receive a non-XKB event, - * better do sanity checking */ - if (ev.type != xkb_event_base) - continue; - - if (ev.any.xkb_type == XkbMapNotify) { - mapping_changed = true; - continue; - } - - if (ev.any.xkb_type != XkbStateNotify) { - ELOG("Unknown XKB event received (type %d)\n", ev.any.xkb_type); - continue; - } - - /* See The XKB Extension: Library Specification, section 14.1 */ - /* We check if the current group (each group contains - * two levels) has been changed. Mode_switch activates - * group XkbGroup2Index */ - if (xkb_current_group == ev.state.group) - continue; - - xkb_current_group = ev.state.group; - - if (ev.state.group == XkbGroup2Index) { - DLOG("Mode_switch enabled\n"); - grab_all_keys(conn, true); - } - - if (ev.state.group == XkbGroup1Index) { - DLOG("Mode_switch disabled\n"); - ungrab_all_keys(conn); - grab_all_keys(conn, false); - } - } - - if (!mapping_changed) - return; - - DLOG("Keyboard mapping changed, updating keybindings\n"); - xcb_key_symbols_free(keysyms); - keysyms = xcb_key_symbols_alloc(conn); - - xcb_numlock_mask = aio_get_mod_mask_for(XCB_NUM_LOCK, keysyms); - - ungrab_all_keys(conn); - DLOG("Re-grabbing...\n"); - translate_keysyms(); - grab_all_keys(conn, (xkb_current_group == XkbGroup2Index)); - DLOG("Done\n"); -} - /* * Exit handler which destroys the main_loop. Will trigger cleanup handlers. * @@ -593,21 +518,7 @@ int main(int argc, char *argv[]) { #include "atoms.xmacro" #undef xmacro - /* Initialize the Xlib connection */ - xlibdpy = xkbdpy = XOpenDisplay(NULL); - - /* Try to load the X cursors and initialize the XKB extension */ - if (xlibdpy == NULL) { - ELOG("ERROR: XOpenDisplay() failed, disabling libXcursor/XKB support\n"); - xcursor_supported = false; - xkb_supported = false; - } else if (fcntl(ConnectionNumber(xlibdpy), F_SETFD, FD_CLOEXEC) == -1) { - ELOG("Could not set FD_CLOEXEC on xkbdpy\n"); - return 1; - } else { - xcursor_load_cursors(); - /*init_xkb();*/ - } + xcursor_load_cursors(); /* Set a cursor for the root window (otherwise the root window will show no cursor until the first client is launched). */ @@ -616,27 +527,22 @@ int main(int argc, char *argv[]) { else xcb_set_root_cursor(XCURSOR_CURSOR_POINTER); - if (xkb_supported) { - int errBase, - major = XkbMajorVersion, - minor = XkbMinorVersion; - - if (fcntl(ConnectionNumber(xkbdpy), F_SETFD, FD_CLOEXEC) == -1) { - fprintf(stderr, "Could not set FD_CLOEXEC on xkbdpy\n"); - return 1; - } - - int i1; - if (!XkbQueryExtension(xkbdpy, &i1, &xkb_event_base, &errBase, &major, &minor)) { - fprintf(stderr, "XKB not supported by X-server\n"); - xkb_supported = false; - } - /* end of ugliness */ - - if (xkb_supported && !XkbSelectEvents(xkbdpy, XkbUseCoreKbd, XkbMapNotifyMask | XkbStateNotifyMask, XkbMapNotifyMask | XkbStateNotifyMask)) { - fprintf(stderr, "Could not set XKB event mask\n"); - return 1; - } + const xcb_query_extension_reply_t *extreply; + extreply = xcb_get_extension_data(conn, &xcb_xkb_id); + if (!extreply->present) { + DLOG("xkb is not present on this server\n"); + } else { + DLOG("initializing xcb-xkb\n"); + xcb_xkb_use_extension(conn, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION); + xcb_xkb_select_events(conn, + XCB_XKB_ID_USE_CORE_KBD, + XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY, + 0, + XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY, + 0xff, + 0xff, + NULL); + xkb_base = extreply->first_event; } restore_connect(); @@ -770,21 +676,12 @@ int main(int argc, char *argv[]) { ewmh_update_number_of_desktops(); struct ev_io *xcb_watcher = scalloc(sizeof(struct ev_io)); - struct ev_io *xkb = scalloc(sizeof(struct ev_io)); xcb_check = scalloc(sizeof(struct ev_check)); struct ev_prepare *xcb_prepare = scalloc(sizeof(struct ev_prepare)); ev_io_init(xcb_watcher, xcb_got_event, xcb_get_file_descriptor(conn), EV_READ); ev_io_start(main_loop, xcb_watcher); - if (xkb_supported) { - ev_io_init(xkb, xkb_got_event, ConnectionNumber(xkbdpy), EV_READ); - ev_io_start(main_loop, xkb); - - /* Flush the buffer so that libev can properly get new events */ - XFlush(xkbdpy); - } - ev_check_init(xcb_check, xcb_check_cb); ev_check_start(main_loop, xcb_check); -- 2.39.5