|  | @ -17,14 +17,12 @@ | 
			
		
	
		
		
			
				
					|  |  | #include <err.h> |  |  | #include <err.h> | 
			
		
	
		
		
			
				
					|  |  | #include <assert.h> |  |  | #include <assert.h> | 
			
		
	
		
		
			
				
					|  |  | #include <security/pam_appl.h> |  |  | #include <security/pam_appl.h> | 
			
		
	
		
		
			
				
					|  |  | #include <X11/Xlib-xcb.h> |  |  |  | 
			
		
	
		
		
			
				
					|  |  | #include <getopt.h> |  |  | #include <getopt.h> | 
			
		
	
		
		
			
				
					|  |  | #include <string.h> |  |  | #include <string.h> | 
			
		
	
		
		
			
				
					|  |  | #include <ev.h> |  |  | #include <ev.h> | 
			
		
	
		
		
			
				
					|  |  | #include <sys/mman.h> |  |  | #include <sys/mman.h> | 
			
		
	
		
		
			
				
					|  |  | #include <X11/XKBlib.h> |  |  |  | 
			
		
	
		
		
			
				
					|  |  | #include <X11/extensions/XKBfile.h> |  |  |  | 
			
		
	
		
		
			
				
					|  |  | #include <xkbcommon/xkbcommon.h> |  |  | #include <xkbcommon/xkbcommon.h> | 
			
		
	
		
		
			
				
					|  |  |  |  |  | #include <xkbcommon/xkbcommon-x11.h> | 
			
		
	
		
		
			
				
					|  |  | #include <cairo.h> |  |  | #include <cairo.h> | 
			
		
	
		
		
			
				
					|  |  | #include <cairo/cairo-xcb.h> |  |  | #include <cairo/cairo-xcb.h> | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -44,7 +42,6 @@ | 
			
		
	
		
		
			
				
					|  |  | typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents); |  |  | typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents); | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | /* We need this for libxkbfile */ |  |  | /* We need this for libxkbfile */ | 
			
		
	
		
		
			
				
					|  |  | static Display *display; |  |  |  | 
			
		
	
		
		
			
				
					|  |  | char color[7] = "ffffff"; |  |  | char color[7] = "ffffff"; | 
			
		
	
		
		
			
				
					|  |  | int inactivity_timeout = 30; |  |  | int inactivity_timeout = 30; | 
			
		
	
		
		
			
				
					|  |  | uint32_t last_resolution[2]; |  |  | uint32_t last_resolution[2]; | 
			
		
	
	
		
		
			
				
					|  | @ -70,6 +67,8 @@ extern pam_state_t pam_state; | 
			
		
	
		
		
			
				
					|  |  | static struct xkb_state *xkb_state; |  |  | static struct xkb_state *xkb_state; | 
			
		
	
		
		
			
				
					|  |  | static struct xkb_context *xkb_context; |  |  | static struct xkb_context *xkb_context; | 
			
		
	
		
		
			
				
					|  |  | static struct xkb_keymap *xkb_keymap; |  |  | static struct xkb_keymap *xkb_keymap; | 
			
		
	
		
		
			
				
					|  |  |  |  |  | static uint8_t xkb_base_event; | 
			
		
	
		
		
			
				
					|  |  |  |  |  | static uint8_t xkb_base_error; | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | cairo_surface_t *img = NULL; |  |  | cairo_surface_t *img = NULL; | 
			
		
	
		
		
			
				
					|  |  | bool tile = false; |  |  | bool tile = false; | 
			
		
	
	
		
		
			
				
					|  | @ -102,77 +101,44 @@ static void turn_monitors_off(void) { | 
			
		
	
		
		
			
				
					|  |  |  * Necessary so that we can properly let xkbcommon track the keyboard state and |  |  |  * Necessary so that we can properly let xkbcommon track the keyboard state and | 
			
		
	
		
		
			
				
					|  |  |  * translate keypresses to utf-8. |  |  |  * translate keypresses to utf-8. | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  * | 
			
		
	
		
		
			
				
					|  |  |  * Ideally, xkbcommon would ship something like this itself, but as of now |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * (version 0.2.0), it doesn’t. |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * TODO: Once xcb-xkb is enabled by default and released, we should port this |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * code to xcb-xkb. See also https://github.com/xkbcommon/libxkbcommon/issues/1
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  * |  |  |  | 
			
		
	
		
		
			
				
					|  |  |  */ |  |  |  */ | 
			
		
	
		
		
			
				
					|  |  | static bool load_keymap(void) { |  |  | static bool load_keymap(void) { | 
			
		
	
		
		
			
				
					|  |  |     bool ret = false; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     XkbFileInfo result; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     memset(&result, '\0', sizeof(result)); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     result.xkb = XkbGetKeyboard(display, XkbAllMapComponentsMask, XkbUseCoreKbd); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if (result.xkb == NULL) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         fprintf(stderr, "[i3lock] XKB: XkbGetKeyboard failed\n"); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         return false; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     FILE *temp = tmpfile(); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if (temp == NULL) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         fprintf(stderr, "[i3lock] could not create tempfile\n"); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         return false; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     bool ok = XkbWriteXKBKeymap(temp, &result, false, false, NULL, NULL); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if (!ok) { |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         fprintf(stderr, "[i3lock] XkbWriteXKBKeymap failed\n"); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         goto out; |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     rewind(temp); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if (xkb_context == NULL) { |  |  |     if (xkb_context == NULL) { | 
			
		
	
		
		
			
				
					|  |  |         if ((xkb_context = xkb_context_new(0)) == NULL) { |  |  |         if ((xkb_context = xkb_context_new(0)) == NULL) { | 
			
		
	
		
		
			
				
					|  |  |             fprintf(stderr, "[i3lock] could not create xkbcommon context\n"); |  |  |             fprintf(stderr, "[i3lock] could not create xkbcommon context\n"); | 
			
		
	
		
		
			
				
					
					|  |  |             goto out; |  |  |             return false; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |         } |  |  |         } | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |     } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     if (xkb_keymap != NULL) |  |  |     if (xkb_keymap != NULL) | 
			
		
	
		
		
			
				
					|  |  |         xkb_keymap_unref(xkb_keymap); |  |  |         xkb_keymap_unref(xkb_keymap); | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |     if ((xkb_keymap = xkb_keymap_new_from_file(xkb_context, temp, XKB_KEYMAP_FORMAT_TEXT_V1, 0)) == NULL) { |  |  |     int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         fprintf(stderr, "[i3lock] xkb_keymap_new_from_file failed\n"); |  |  |     DEBUG("device = %d\n", device_id); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         goto out; |  |  |     if ((xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |         fprintf(stderr, "[i3lock] xkb_x11_keymap_new_from_device failed\n"); | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         return false; | 
			
		
	
		
		
			
				
					|  |  |     } |  |  |     } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |     struct xkb_state *new_state = xkb_state_new(xkb_keymap); |  |  |     struct xkb_state *new_state = | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |         xkb_x11_state_new_from_device(xkb_keymap, conn, device_id); | 
			
		
	
		
		
			
				
					|  |  |     if (new_state == NULL) { |  |  |     if (new_state == NULL) { | 
			
		
	
		
		
			
				
					
					|  |  |         fprintf(stderr, "[i3lock] xkb_state_new failed\n"); |  |  |         fprintf(stderr, "[i3lock] xkb_x11_state_new_from_device failed\n"); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |         goto out; |  |  |         return false; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |     } |  |  |     } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     /* Get the initial modifier state to be in sync with the X server.
 |  |  |     /* Get the initial modifier state to be in sync with the X server.
 | 
			
		
	
		
		
			
				
					|  |  |      * See https://github.com/xkbcommon/libxkbcommon/issues/1 for why we ignore
 |  |  |      * See https://github.com/xkbcommon/libxkbcommon/issues/1 for why we ignore
 | 
			
		
	
		
		
			
				
					|  |  |      * the base and latched fields. */ |  |  |      * the base and latched fields. */ | 
			
		
	
		
		
			
				
					
					|  |  |     XkbStateRec state_rec; |  |  |     //xkb_state_update_mask(new_state,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     XkbGetState(display, XkbUseCoreKbd, &state_rec); |  |  |     //    0, 0, new_state->components.locked_mods,
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  | 
 |  |  |     //    0, 0, new_state->components.locked_group);
 | 
			
				
				
			
		
	
		
		
			
				
					|  |  |     xkb_state_update_mask(new_state, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         0, 0, state_rec.locked_mods, |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         0, 0, state_rec.locked_group); |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     if (xkb_state != NULL) |  |  |     if (xkb_state != NULL) | 
			
		
	
		
		
			
				
					|  |  |         xkb_state_unref(xkb_state); |  |  |         xkb_state_unref(xkb_state); | 
			
		
	
		
		
			
				
					|  |  |     xkb_state = new_state; |  |  |     xkb_state = new_state; | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |     ret = true; |  |  |     return true; | 
			
				
				
			
		
	
		
		
			
				
					|  |  | out: |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     XkbFreeKeyboard(result.xkb, XkbAllComponentsMask, true); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     fclose(temp); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     return ret; |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					|  |  | } |  |  | } | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  | /*
 |  |  | /*
 | 
			
		
	
	
		
		
			
				
					|  | @ -772,16 +738,22 @@ int main(int argc, char *argv[]) { | 
			
		
	
		
		
			
				
					|  |  |         err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK"); |  |  |         err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK"); | 
			
		
	
		
		
			
				
					|  |  | #endif |  |  | #endif | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     /* Initialize connection to X11 */ |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     if ((display = XOpenDisplay(NULL)) == NULL) |  |  |  | 
			
		
	
		
		
			
				
					|  |  |         errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?"); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     XSetEventQueueOwner(display, XCBOwnsEventQueue); |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     conn = XGetXCBConnection(display); |  |  |  | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  |     /* Double checking that connection is good and operatable with xcb */ |  |  |     /* Double checking that connection is good and operatable with xcb */ | 
			
		
	
		
		
			
				
					
					|  |  |     if (xcb_connection_has_error(conn)) |  |  |     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, | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             0, | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             NULL, | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             NULL, | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             &xkb_base_event, | 
			
		
	
		
		
			
				
					|  |  |  |  |  |             &xkb_base_error) != 1) | 
			
		
	
		
		
			
				
					|  |  |  |  |  |         errx(EXIT_FAILURE, "Could not setup XKB extension."); | 
			
		
	
		
		
			
				
					|  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     /* When we cannot initially load the keymap, we better exit */ |  |  |     /* When we cannot initially load the keymap, we better exit */ | 
			
		
	
		
		
			
				
					|  |  |     if (!load_keymap()) |  |  |     if (!load_keymap()) | 
			
		
	
		
		
			
				
					|  |  |         errx(EXIT_FAILURE, "Could not load keymap"); |  |  |         errx(EXIT_FAILURE, "Could not load keymap"); | 
			
		
	
	
		
		
			
				
					|  | 
 |