summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2014-01-18 19:40:11 +0100
committerMichael Stapelberg <michael@stapelberg.de>2014-06-21 16:32:18 +0200
commit1b89709ae74374f33d22db2247256cc7936fb12b (patch)
treeba0c1eed53336441d5cebe92c0ebb959de554307
parent7eb43aeabd7a5eb71927520c427debb45eab05f2 (diff)
listen for XKB events instead of the MappingNotify event (Thanks Ran)
-rw-r--r--Makefile4
-rw-r--r--i3lock.c85
2 files changed, 79 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index 26dd723..d91eaf7 100644
--- a/Makefile
+++ b/Makefile
@@ -11,8 +11,8 @@ CFLAGS += -std=c99
CFLAGS += -pipe
CFLAGS += -Wall
CPPFLAGS += -D_GNU_SOURCE
-CFLAGS += $(shell pkg-config --cflags cairo xcb-dpms xcb-xinerama xcb-atom xkbcommon xkbcommon-x11)
-LIBS += $(shell pkg-config --libs cairo xcb-dpms xcb-xinerama xcb-atom xcb-image xkbcommon xkbcommon-x11)
+CFLAGS += $(shell pkg-config --cflags cairo xcb-dpms xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
+LIBS += $(shell pkg-config --libs cairo xcb-dpms xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
LIBS += -lpam
LIBS += -lev
LIBS += -lm
diff --git a/i3lock.c b/i3lock.c
index 4c8668d..012bcbe 100644
--- a/i3lock.c
+++ b/i3lock.c
@@ -13,6 +13,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <xcb/xcb.h>
+#include <xcb/xkb.h>
#include <xcb/dpms.h>
#include <err.h>
#include <assert.h>
@@ -402,11 +403,54 @@ static void handle_visibility_notify(xcb_connection_t *conn,
/*
* Called when the keyboard mapping changes. We update our symbols.
*
+ * We ignore errors — if the new keymap cannot be loaded it’s better if the
+ * screen stays locked and the user intervenes by using killall i3lock.
+ *
*/
-static void handle_mapping_notify(xcb_mapping_notify_event_t *event) {
- /* We ignore errors — if the new keymap cannot be loaded it’s better if the
- * screen stays locked and the user intervenes by using killall i3lock. */
- (void)load_keymap();
+static void process_xkb_event(xcb_generic_event_t *gevent) {
+ union xkb_event {
+ struct {
+ uint8_t response_type;
+ uint8_t xkbType;
+ uint16_t sequence;
+ xcb_timestamp_t time;
+ uint8_t deviceID;
+ } any;
+ xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
+ xcb_xkb_map_notify_event_t map_notify;
+ xcb_xkb_state_notify_event_t state_notify;
+ } *event = (union xkb_event*)gevent;
+
+ DEBUG("process_xkb_event for device %d\n", event->any.deviceID);
+
+ if (event->any.deviceID != xkb_x11_get_core_keyboard_device_id(conn))
+ return;
+
+ /*
+ * XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap
+ * updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent
+ * recompilations.
+ */
+ switch (event->any.xkbType) {
+ case XCB_XKB_NEW_KEYBOARD_NOTIFY:
+ if (event->new_keyboard_notify.changed & XCB_XKB_NKN_DETAIL_KEYCODES)
+ (void)load_keymap();
+ break;
+
+ case XCB_XKB_MAP_NOTIFY:
+ (void)load_keymap();
+ break;
+
+ case XCB_XKB_STATE_NOTIFY:
+ xkb_state_update_mask(xkb_state,
+ event->state_notify.baseMods,
+ event->state_notify.latchedMods,
+ event->state_notify.lockedMods,
+ event->state_notify.baseGroup,
+ event->state_notify.latchedGroup,
+ event->state_notify.lockedGroup);
+ break;
+ }
}
/*
@@ -512,6 +556,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
/* Strip off the highest bit (set if the event is generated) */
int type = (event->response_type & 0x7F);
+
switch (type) {
case XCB_KEY_PRESS:
handle_key_press((xcb_key_press_event_t*)event);
@@ -546,13 +591,13 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
}
break;
- case XCB_MAPPING_NOTIFY:
- handle_mapping_notify((xcb_mapping_notify_event_t*)event);
- break;
-
case XCB_CONFIGURE_NOTIFY:
handle_screen_resize();
break;
+
+ default:
+ if (type == xkb_base_event)
+ process_xkb_event(event);
}
free(event);
@@ -745,6 +790,30 @@ int main(int argc, char *argv[]) {
&xkb_base_error) != 1)
errx(EXIT_FAILURE, "Could not setup XKB extension.");
+ static const xcb_xkb_map_part_t required_map_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);
+
+ static const xcb_xkb_event_type_t required_events =
+ (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
+ XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY);
+
+ xcb_xkb_select_events(
+ conn,
+ xkb_x11_get_core_keyboard_device_id(conn),
+ required_events,
+ 0,
+ required_events,
+ required_map_parts,
+ required_map_parts,
+ 0);
+
/* When we cannot initially load the keymap, we better exit */
if (!load_keymap())
errx(EXIT_FAILURE, "Could not load keymap");