+/* The depth of the root screen (used e.g. for creating new pixmaps later) */
+uint8_t root_depth;
+
+/* We hope that XKB is supported and set this to false */
+bool xkb_supported = true;
+
+/*
+ * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb.
+ * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop
+ *
+ */
+static void xcb_got_event(EV_P_ struct ev_io *w, int revents) {
+ /* empty, because xcb_prepare_cb and xcb_check_cb are used */
+}
+
+/*
+ * Flush before blocking (and waiting for new events)
+ *
+ */
+static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
+ xcb_flush(evenths.c);
+}
+
+/*
+ * Instead of polling the X connection socket we leave this to
+ * xcb_poll_for_event() which knows better than we can ever know.
+ *
+ */
+static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
+ xcb_generic_event_t *event;
+
+ while ((event = xcb_poll_for_event(evenths.c)) != NULL) {
+ xcb_event_handle(&evenths, event);
+ free(event);
+ }
+}
+
+/*
+ * 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(global_conn, true);
+ }
+
+ if (ev.state.group == XkbGroup1Index) {
+ DLOG("Mode_switch disabled\n");
+ ungrab_all_keys(global_conn);
+ grab_all_keys(global_conn, false);
+ }
+ }
+
+ if (!mapping_changed)
+ return;
+
+ DLOG("Keyboard mapping changed, updating keybindings\n");
+ xcb_key_symbols_free(keysyms);
+ keysyms = xcb_key_symbols_alloc(global_conn);
+
+ xcb_get_numlock_mask(global_conn);
+
+ ungrab_all_keys(global_conn);
+ DLOG("Re-grabbing...\n");
+ translate_keysyms();
+ grab_all_keys(global_conn, (xkb_current_group == XkbGroup2Index));
+ DLOG("Done\n");
+}
+
+