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

This commit is contained in:
Pandora 2017-12-08 15:06:08 -05:00
parent 8f7ae46752
commit dfcb1f9359
No known key found for this signature in database
GPG Key ID: 55DB77C2A03E1EF5
5 changed files with 149 additions and 54 deletions

View File

@ -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 \

View File

@ -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

View File

@ -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 |

104
xcb.c
View File

@ -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;
}

18
xcb.h
View File

@ -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