i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
commit dfcb1f9359a70ff29a39471bd27c61232c65f126
parent 8f7ae46752ff3d701860f685e9241fcb376a3cd3
Author: Pandora <pandora@techfo.xyz>
Date:   Fri,  8 Dec 2017 15:06:08 -0500

remove deps on libx11; move to a pure xcb solution for keylayout

Diffstat:
MMakefile.am | 6++----
Mconfigure.ac | 2--
Mi3lock.c | 73+++++++++++++++++++++++++------------------------------------------------
Mxcb.c | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mxcb.h | 18++++++++++++++++++
5 files changed, 149 insertions(+), 54 deletions(-)
diff --git 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
@@ -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
@@ -45,7 +45,6 @@
 #endif
 #include <xcb/xcb_aux.h>
 #include <xcb/randr.h>
-#include <X11/XKBlib.h>
 
 #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
@@ -12,6 +12,9 @@
 #include <xcb/xcb_atom.h>
 #include <xcb/xcb_aux.h>
 #include <xcb/composite.h>
+#include <xcb/xkb.h>
+#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-x11.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
@@ -23,10 +26,13 @@
 #include <sys/time.h>
 
 #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 "<empty>";
+
+        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 "<invalid>";
+
+    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
@@ -3,6 +3,23 @@
 
 #include <xcb/xcb.h>
 
+#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