From dfcb1f9359a70ff29a39471bd27c61232c65f126 Mon Sep 17 00:00:00 2001 From: Pandora Date: Fri, 8 Dec 2017 15:06:08 -0500 Subject: [PATCH] remove deps on libx11; move to a pure xcb solution for keylayout --- Makefile.am | 6 +-- configure.ac | 2 - i3lock.c | 73 +++++++++++++----------------------- xcb.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ xcb.h | 18 +++++++++ 5 files changed, 149 insertions(+), 54 deletions(-) diff --git a/Makefile.am b/Makefile.am index db32126..7fd4e6a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,8 +21,7 @@ i3lock_CFLAGS = \ $(XCB_UTIL_CFLAGS) \ $(XKBCOMMON_CFLAGS) \ $(CAIRO_CFLAGS) \ - $(CODE_COVERAGE_CFLAGS) \ - $(X11_CFLAGS) + $(CODE_COVERAGE_CFLAGS) i3lock_CPPFLAGS = \ $(AM_CPPFLAGS) \ @@ -34,8 +33,7 @@ i3lock_LDADD = \ $(XCB_UTIL_LIBS) \ $(XKBCOMMON_LIBS) \ $(CAIRO_LIBS) \ - $(CODE_COVERAGE_LDFLAGS) \ - $(X11_LIBS) + $(CODE_COVERAGE_LDFLAGS) i3lock_SOURCES = \ cursors.h \ diff --git a/configure.ac b/configure.ac index 63a7617..1c62878 100644 --- a/configure.ac +++ b/configure.ac @@ -87,8 +87,6 @@ PKG_CHECK_MODULES([XCB_IMAGE], [xcb-image]) PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom]) PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon xkbcommon-x11]) PKG_CHECK_MODULES([CAIRO], [cairo]) -PKG_CHECK_MODULES([X11], [x11]) - # Checks for programs. AC_PROG_AWK diff --git a/i3lock.c b/i3lock.c index 74772be..0e304b7 100644 --- a/i3lock.c +++ b/i3lock.c @@ -45,7 +45,6 @@ #endif #include #include -#include #include "i3lock.h" #include "xcb.h" @@ -132,6 +131,7 @@ double ring_width = 7.0; char* verif_text = "verifying…"; char* wrong_text = "wrong!"; +int keylayout_mode = -1; char* layout_text = NULL; /* opts for blurring */ @@ -219,51 +219,23 @@ void u8_dec(char *s, int *i) { } /* - * Loads the XKB keymap from the X11 server and feeds it to xkbcommon. - * Necessary so that we can properly let xkbcommon track the keyboard state and - * translate keypresses to utf-8. + * fetches the keylayout name + * -1 (do not) * arg: 0 (show full string returned) * 1 (show the text, sans parenthesis) * 2 (show just what's in the parenthesis) + * + * credit to the XKB/xcb implementation (no libx11) from https://gist.github.com/bluetech/6061368 + * docs are really sparse, so finding some random implementation was nice */ - -char* get_keylayoutname(int mode) { - - Display *display; - XkbDescPtr keyboard; - XkbStateRec state; - char* answer; - char* newans = NULL; - int res, i; - - display = XkbOpenDisplay(getenv("DISPLAY"), NULL, NULL, NULL, NULL, &res); - if(!display) { - DEBUG("X server unreachable\n"); - return NULL; - } - - keyboard = XkbAllocKeyboard(); - - if (XkbGetNames(display, XkbGroupNamesMask, keyboard) != Success ) { - DEBUG("Error obtaining symbolic names"); - XCloseDisplay(display); - XkbFreeClientMap(keyboard, 0, true); - return NULL; - } - - if(XkbGetState(display, XkbUseCoreKbd, &state) != Success) { - DEBUG("Error getting keyboard state"); - XCloseDisplay(display); - XkbFreeClientMap(keyboard, 0, true); - return NULL; - } - - answer = XGetAtomName(display, keyboard->names->groups[state.group]); +char* get_keylayoutname(int mode, xcb_connection_t* conn) { + if (mode < 0 || mode > 2) return NULL; + char* newans = NULL, *answer = xcb_get_key_group_names(conn); DEBUG("keylayout answer is: [%s]\n", answer); switch (mode) { case 1: // truncate the string at the first parens - for(i = 0; answer[i] != '\0'; ++i) { + for(int i = 0; answer[i] != '\0'; ++i) { if (answer[i] == '(') { if (i != 0 && answer[i - 1] == ' ') { answer[i - 1] = '\0'; @@ -276,7 +248,7 @@ char* get_keylayoutname(int mode) { } break; case 2: - for(i = 0; answer[i] != '\0'; ++i) { + for(int i = 0; answer[i] != '\0'; ++i) { if (answer[i] == '(') { newans = &answer[i + 1]; } else if (answer[i] == ')' && newans != NULL) { @@ -292,15 +264,17 @@ char* get_keylayoutname(int mode) { default: break; } - // note: this is called in option parsing, so this debug() may not trigger unless --debug is the first option DEBUG("answer after mode parsing: [%s]\n", answer); // Free symbolic names structures - XkbFreeClientMap(keyboard, 0, true); - XCloseDisplay(display); - display = NULL; return answer; } +/* + * Loads the XKB keymap from the X11 server and feeds it to xkbcommon. + * Necessary so that we can properly let xkbcommon track the keyboard state and + * translate keypresses to utf-8. + */ + static bool load_keymap(void) { if (xkb_context == NULL) { if ((xkb_context = xkb_context_new(0)) == NULL) { @@ -1337,9 +1311,7 @@ int main(int argc, char *argv[]) { // if layout is NULL, do nothing // if not NULL, attempt to display stuff // need to code some sane defaults for it - layout_text = get_keylayoutname(atoi(optarg)); - if (layout_text) - show_clock = true; + keylayout_mode = atoi(optarg); } else if (strcmp(longopts[longoptind].name, "timestr") == 0) { //read in to timestr @@ -1645,8 +1617,10 @@ int main(int argc, char *argv[]) { int screennr; if ((conn = xcb_connect(NULL, &screennr)) == NULL || xcb_connection_has_error(conn)) - errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?"); + errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?"); + + if (xkb_x11_setup_xkb_extension(conn, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, @@ -1656,7 +1630,10 @@ int main(int argc, char *argv[]) { &xkb_base_event, &xkb_base_error) != 1) errx(EXIT_FAILURE, "Could not setup XKB extension."); - + + layout_text = get_keylayoutname(keylayout_mode, conn); + if (layout_text) + show_clock = true; static const xcb_xkb_map_part_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES | XCB_XKB_MAP_PART_KEY_SYMS | diff --git a/xcb.c b/xcb.c index d36ceac..a78d6c4 100644 --- a/xcb.c +++ b/xcb.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -23,10 +26,13 @@ #include #include "cursors.h" +#include "i3lock.h" +#include "xcb.h" #include "unlock_indicator.h" extern auth_state_t auth_state; extern bool composite; +extern bool debug_mode; xcb_connection_t *conn; xcb_screen_t *screen; @@ -427,3 +433,101 @@ xcb_pixmap_t capture_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int3 xcb_free_gc(conn, gc); return bg_pixmap; } + +static char * get_atom_name(xcb_connection_t* conn, xcb_atom_t atom) { + xcb_get_atom_name_reply_t *reply = NULL; + char *name; + int length; + char* answer = NULL; + + if (atom == 0) + return ""; + + xcb_get_atom_name_cookie_t cookie; + xcb_generic_error_t *error = NULL; + + cookie = xcb_get_atom_name(conn, atom); + + reply = xcb_get_atom_name_reply(conn, cookie, &error); + if (!reply || error) + return ""; + + length = xcb_get_atom_name_name_length(reply); + name = xcb_get_atom_name_name(reply); + + answer = malloc(sizeof(char) * (length + 1)); + strncpy(answer, name, length); + answer[length] = '\0'; + free(error); + free(reply); + return answer; +} + + +char* xcb_get_key_group_names(xcb_connection_t *conn) { + uint8_t xkb_base_event; + uint8_t xkb_base_error; + 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."); + + + xcb_xkb_get_names_reply_t *reply = NULL; + + + xcb_generic_error_t *error = NULL; + xcb_xkb_get_names_cookie_t cookie; + + cookie = xcb_xkb_get_names(conn, + XCB_XKB_ID_USE_CORE_KBD, + all_name_details); + + reply = xcb_xkb_get_names_reply(conn, cookie, &error); + if (!reply || error) + errx(1, "couldn't get reply for get_names"); + + xcb_xkb_get_names_value_list_t list; + + void *buffer; + + buffer = xcb_xkb_get_names_value_list(reply); + xcb_xkb_get_names_value_list_unpack(buffer, + reply->nTypes, + reply->indicators, + reply->virtualMods, + reply->groupNames, + reply->nKeys, + reply->nKeyAliases, + reply->nRadioGroups, + reply->which, + &list); + + /* dump group names. */ + + int length; + xcb_atom_t *iter; + char* answer = NULL; + length = xcb_xkb_get_names_value_list_groups_length(reply, &list); + iter = xcb_xkb_get_names_value_list_groups(&list); + + for (int i = 0; i < length; i++) { + xcb_atom_t group_name = *iter; + char* name = get_atom_name(conn, group_name); + DEBUG("group_name %d: %s\n", i, name); + if (i == 0) { + answer = name; + } else { + free(name); + } + iter++; + } + free(reply); + free(error); + return answer; +} diff --git a/xcb.h b/xcb.h index b80a242..a219aae 100644 --- a/xcb.h +++ b/xcb.h @@ -3,6 +3,23 @@ #include +#define all_name_details \ + (XCB_XKB_NAME_DETAIL_KEYCODES | \ + XCB_XKB_NAME_DETAIL_GEOMETRY | \ + XCB_XKB_NAME_DETAIL_SYMBOLS | \ + XCB_XKB_NAME_DETAIL_PHYS_SYMBOLS | \ + XCB_XKB_NAME_DETAIL_TYPES | \ + XCB_XKB_NAME_DETAIL_COMPAT | \ + XCB_XKB_NAME_DETAIL_KEY_TYPE_NAMES | \ + XCB_XKB_NAME_DETAIL_KT_LEVEL_NAMES | \ + XCB_XKB_NAME_DETAIL_INDICATOR_NAMES | \ + XCB_XKB_NAME_DETAIL_KEY_NAMES | \ + XCB_XKB_NAME_DETAIL_KEY_ALIASES | \ + XCB_XKB_NAME_DETAIL_VIRTUAL_MOD_NAMES | \ + XCB_XKB_NAME_DETAIL_GROUP_NAMES | \ + XCB_XKB_NAME_DETAIL_RG_NAMES) + + extern xcb_connection_t *conn; extern xcb_screen_t *screen; @@ -14,5 +31,6 @@ xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_win xcb_window_t find_focused_window(xcb_connection_t *conn, const xcb_window_t root); void set_focused_window(xcb_connection_t *conn, const xcb_window_t root, const xcb_window_t window); xcb_pixmap_t capture_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32_t* resolution); +char* xcb_get_key_group_names(xcb_connection_t *conn); #endif