Switch to xcb-xkb and libxkbcommon
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.)
This commit is contained in:
@ -8,6 +8,8 @@
|
||||
*/
|
||||
#include "all.h"
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
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;
|
||||
|
@ -11,9 +11,7 @@
|
||||
*
|
||||
*/
|
||||
#include "all.h"
|
||||
|
||||
/* We need Xlib for XStringToKeysym */
|
||||
#include <X11/Xlib.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
char *current_configpath = NULL;
|
||||
Config config;
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <libsn/sn-monitor.h>
|
||||
|
||||
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:
|
||||
|
@ -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.
|
||||
|
137
src/main.c
137
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);
|
||||
|
||||
|
Reference in New Issue
Block a user