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:
parent
cf6cc134b8
commit
3f5a0f0024
@ -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)
|
||||
|
3
debian/control
vendored
3
debian/control
vendored
@ -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,
|
||||
|
@ -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)
|
||||
|
||||
|
@ -43,6 +43,9 @@
|
||||
#include <xcb/xcb_event.h>
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XKBlib.h>
|
||||
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
199
i3bar/src/xcb.c
199
i3bar/src/xcb.c
@ -8,6 +8,7 @@
|
||||
*
|
||||
*/
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xkb.h>
|
||||
#include <xcb/xproto.h>
|
||||
#include <xcb/xcb_aux.h>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <xcb/randr.h>
|
||||
|
||||
extern int randr_base;
|
||||
extern int xkb_base;
|
||||
|
||||
/**
|
||||
* Adds the given sequence to the list of events which are ignored.
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <xcb/xcb_keysyms.h>
|
||||
#include <xcb/xkb.h>
|
||||
|
||||
#include <X11/XKBlib.h>
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user