Hello community, here is the log from the commit of package i3lock for openSUSE:Factory checked in at 2017-11-27 22:18:27 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/i3lock (Old) and /work/SRC/openSUSE:Factory/.i3lock.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "i3lock" Mon Nov 27 22:18:27 2017 rev:13 rq:545890 version:2.10 Changes: -------- --- /work/SRC/openSUSE:Factory/i3lock/i3lock.changes 2017-11-09 14:07:55.168986994 +0100 +++ /work/SRC/openSUSE:Factory/.i3lock.new/i3lock.changes 2017-11-27 22:18:34.242287195 +0100 @@ -1,0 +2,12 @@ +Sun Nov 26 15:52:11 UTC 2017 - [email protected] + +- update to 2.10 + * Only use -lpam when not on OpenBSD + * locale: treat empty string same as unset + * Fix overwrite of getopt optind + * Immediately hide the unlock indicator after ESC / C-u + * Measure wall-clock time instead of CPU time for “locking” indicator. + * SetInputFocus to the i3lock window to force-close context menus + * Use RandR for learning about attached monitors + +------------------------------------------------------------------- Old: ---- i3lock-2.9.1.tar.bz2 New: ---- i3lock-2.10.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ i3lock.spec ++++++ --- /var/tmp/diff_new_pack.pC0YNk/_old 2017-11-27 22:18:34.738269193 +0100 +++ /var/tmp/diff_new_pack.pC0YNk/_new 2017-11-27 22:18:34.742269048 +0100 @@ -20,7 +20,7 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ Name: i3lock -Version: 2.9.1 +Version: 2.10 Release: 0 Summary: Screen Locker for the i3 Window Manager License: BSD-3-Clause ++++++ i3lock-2.9.1.tar.bz2 -> i3lock-2.10.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/CHANGELOG new/i3lock-2.10/CHANGELOG --- old/i3lock-2.9.1/CHANGELOG 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/CHANGELOG 2017-11-25 08:15:59.000000000 +0100 @@ -1,3 +1,13 @@ +2017-11-25 i3lock 2.10 + + • Only use -lpam when not on OpenBSD (Thanks Kaashif) + • locale: treat empty string same as unset (Thanks Ran) + • Fix overwrite of getopt optind (Thanks jakob) + • Immediately hide the unlock indicator after ESC / C-u (Thanks Orestis) + • Measure wall-clock time instead of CPU time for “locking” indicator. + • SetInputFocus to the i3lock window to force-close context menus + • Use RandR for learning about attached monitors + 2017-06-21 i3lock 2.9.1 • Fix version number mechanism (for --version) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/Makefile new/i3lock-2.10/Makefile --- old/i3lock-2.9.1/Makefile 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/Makefile 2017-11-25 08:15:59.000000000 +0100 @@ -15,9 +15,8 @@ CFLAGS += -pipe CFLAGS += -Wall CPPFLAGS += -D_GNU_SOURCE -CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) -LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) -LIBS += -lpam +CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-xinerama xcb-randr xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) +LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-xinerama xcb-randr xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) LIBS += -lev LIBS += -lm @@ -32,10 +31,10 @@ ifeq ($(wildcard .git),) # not in git repository VERSION := $(shell [ -f $(TOPDIR)/I3LOCK_VERSION ] && cat $(TOPDIR)/I3LOCK_VERSION | cut -d '-' -f 1) -I3LOCK_VERSION:="2.9.1 (2017-06-21)" +I3LOCK_VERSION:="2.10 (2017-11-25)" else VERSION:=$(shell git describe --tags --abbrev=0) -I3LOCK_VERSION:="2.9.1 (2017-06-21)" +I3LOCK_VERSION:="2.10 (2017-11-25)" endif CPPFLAGS += -DVERSION=\"${I3LOCK_VERSION}\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/README.md new/i3lock-2.10/README.md --- old/i3lock-2.9.1/README.md 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/README.md 2017-11-25 08:15:59.000000000 +0100 @@ -26,6 +26,7 @@ - libpam-dev - libcairo-dev - libxcb-xinerama +- libxcb-randr - libev - libx11-dev - libx11-xcb-dev diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/i3lock.c new/i3lock-2.10/i3lock.c --- old/i3lock-2.9.1/i3lock.c 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/i3lock.c 2017-11-25 08:15:59.000000000 +0100 @@ -35,12 +35,14 @@ #ifdef __OpenBSD__ #include <strings.h> /* explicit_bzero(3) */ #endif +#include <xcb/xcb_aux.h> +#include <xcb/randr.h> #include "i3lock.h" #include "xcb.h" #include "cursors.h" #include "unlock_indicator.h" -#include "xinerama.h" +#include "randr.h" #define TSTAMP_N_SECS(n) (n * 1.0) #define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n)) @@ -84,6 +86,7 @@ static struct xkb_compose_state *xkb_compose_state; static uint8_t xkb_base_event; static uint8_t xkb_base_error; +static int randr_base = -1; cairo_surface_t *img = NULL; bool tile = false; @@ -278,7 +281,8 @@ DEBUG("successfully authenticated\n"); clear_password_memory(); - exit(0); + ev_break(EV_DEFAULT, EVBREAK_ALL); + return; } #else if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) { @@ -292,7 +296,8 @@ pam_setcred(pam_handle, PAM_REFRESH_CRED); pam_end(pam_handle, PAM_SUCCESS); - exit(0); + ev_break(EV_DEFAULT, EVBREAK_ALL); + return; } #endif @@ -445,14 +450,9 @@ ksym == XKB_KEY_Escape) { DEBUG("C-u pressed\n"); clear_input(); - /* Hide the unlock indicator after a bit if the password buffer is - * empty. */ - if (unlock_indicator) { - START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb); - unlock_state = STATE_BACKSPACE_ACTIVE; - redraw_screen(); - unlock_state = STATE_KEY_PRESSED; - } + /* Also hide the unlock indicator */ + if (unlock_indicator) + clear_indicator(); return; } break; @@ -622,7 +622,7 @@ xcb_configure_window(conn, win, mask, last_resolution); xcb_flush(conn); - xinerama_query_screens(); + randr_query(screen->root); redraw_screen(); } @@ -745,8 +745,14 @@ break; default: - if (type == xkb_base_event) + if (type == xkb_base_event) { process_xkb_event(event); + } + if (randr_base > -1 && + type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { + randr_query(screen->root); + handle_screen_resize(); + } } free(event); @@ -819,7 +825,7 @@ #endif int curs_choice = CURS_NONE; int o; - int optind = 0; + int longoptind = 0; struct option longopts[] = { {"version", no_argument, NULL, 'v'}, {"nofork", no_argument, NULL, 'n'}, @@ -843,7 +849,7 @@ errx(EXIT_FAILURE, "pw->pw_name is NULL.\n"); char *optstring = "hvnbdc:p:ui:teI:f"; - while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) { + while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg"); @@ -894,7 +900,7 @@ ignore_empty_password = true; break; case 0: - if (strcmp(longopts[optind].name, "debug") == 0) + if (strcmp(longopts[longoptind].name, "debug") == 0) debug_mode = true; break; case 'f': @@ -977,11 +983,11 @@ errx(EXIT_FAILURE, "Could not load keymap"); const char *locale = getenv("LC_ALL"); - if (!locale) + if (!locale || !*locale) locale = getenv("LC_CTYPE"); - if (!locale) + if (!locale || !*locale) locale = getenv("LANG"); - if (!locale) { + if (!locale || !*locale) { if (debug_mode) fprintf(stderr, "Can't detect your locale, fallback to C\n"); locale = "C"; @@ -989,11 +995,11 @@ load_compose_table(locale); - xinerama_init(); - xinerama_query_screens(); - screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; + randr_init(&randr_base, screen->root); + randr_query(screen->root); + last_resolution[0] = screen->width_in_pixels; last_resolution[1] = screen->height_in_pixels; @@ -1015,6 +1021,8 @@ /* Pixmap on which the image is rendered to (if any) */ xcb_pixmap_t bg_pixmap = draw_image(last_resolution); + xcb_window_t stolen_focus = find_focused_window(conn, screen->root); + /* Open the fullscreen window, already with the correct pixmap in place */ win = open_fullscreen_window(conn, screen, color, bg_pixmap); xcb_free_pixmap(conn, bg_pixmap); @@ -1023,7 +1031,23 @@ /* Display the "locking…" message while trying to grab the pointer/keyboard. */ auth_state = STATE_AUTH_LOCK; - grab_pointer_and_keyboard(conn, screen, cursor); + if (!grab_pointer_and_keyboard(conn, screen, cursor, 1000)) { + DEBUG("stole focus from X11 window 0x%08x\n", stolen_focus); + + /* Set the focus to i3lock, possibly closing context menus which would + * otherwise prevent us from grabbing keyboard/pointer. + * + * We cannot use set_focused_window because _NET_ACTIVE_WINDOW only + * works for managed windows, but i3lock uses an unmanaged window + * (override_redirect=1). */ + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT /* revert_to */, win, XCB_CURRENT_TIME); + if (!grab_pointer_and_keyboard(conn, screen, cursor, 9000)) { + auth_state = STATE_I3LOCK_LOCK_FAILED; + redraw_screen(); + sleep(1); + errx(EXIT_FAILURE, "Cannot grab pointer/keyboard"); + } + } pid_t pid = fork(); /* The pid == -1 case is intentionally ignored here: @@ -1070,4 +1094,17 @@ * file descriptor becomes readable). */ ev_invoke(main_loop, xcb_check, 0); ev_loop(main_loop, 0); + + if (stolen_focus == XCB_NONE) { + return 0; + } + + DEBUG("restoring focus to X11 window 0x%08x\n", stolen_focus); + xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); + xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME); + xcb_destroy_window(conn, win); + set_focused_window(conn, screen->root, stolen_focus); + xcb_aux_sync(conn); + + return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/randr.c new/i3lock-2.10/randr.c --- old/i3lock-2.9.1/randr.c 1970-01-01 01:00:00.000000000 +0100 +++ new/i3lock-2.10/randr.c 2017-11-25 08:15:59.000000000 +0100 @@ -0,0 +1,297 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * © 2010 Michael Stapelberg + * + * See LICENSE for licensing information + * + */ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <xcb/xcb.h> +#include <xcb/xinerama.h> +#include <xcb/randr.h> + +#include "i3lock.h" +#include "xcb.h" +#include "randr.h" + +/* Number of Xinerama screens which are currently present. */ +int xr_screens = 0; + +/* The resolutions of the currently present Xinerama screens. */ +Rect *xr_resolutions = NULL; + +static bool xinerama_active; +static bool has_randr = false; +static bool has_randr_1_5 = false; +extern bool debug_mode; + +void _xinerama_init(void); + +void randr_init(int *event_base, xcb_window_t root) { + const xcb_query_extension_reply_t *extreply; + + extreply = xcb_get_extension_data(conn, &xcb_randr_id); + if (!extreply->present) { + DEBUG("RandR is not present, falling back to Xinerama.\n"); + _xinerama_init(); + return; + } + + xcb_generic_error_t *err; + xcb_randr_query_version_reply_t *randr_version = + xcb_randr_query_version_reply( + conn, xcb_randr_query_version(conn, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION), &err); + if (err != NULL) { + DEBUG("Could not query RandR version: X11 error code %d\n", err->error_code); + _xinerama_init(); + return; + } + + has_randr = true; + + has_randr_1_5 = (randr_version->major_version >= 1) && + (randr_version->minor_version >= 5); + + free(randr_version); + + if (event_base != NULL) + *event_base = extreply->first_event; + + xcb_randr_select_input(conn, root, + XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | + XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | + XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); + + xcb_flush(conn); +} + +void _xinerama_init(void) { + if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) { + DEBUG("Xinerama extension not found, disabling.\n"); + return; + } + + xcb_xinerama_is_active_cookie_t cookie; + xcb_xinerama_is_active_reply_t *reply; + + cookie = xcb_xinerama_is_active(conn); + reply = xcb_xinerama_is_active_reply(conn, cookie, NULL); + if (!reply) + return; + + if (!reply->state) { + free(reply); + return; + } + + xinerama_active = true; + free(reply); +} + +/* + * randr_query_outputs_15 uses RandR ≥ 1.5 to update outputs. + * + */ +static bool _randr_query_monitors_15(xcb_window_t root) { +#if XCB_RANDR_MINOR_VERSION < 5 + return false; +#else + /* RandR 1.5 available at compile-time, i.e. libxcb is new enough */ + if (!has_randr_1_5) { + return false; + } + /* RandR 1.5 available at run-time (supported by the server) */ + DEBUG("Querying monitors using RandR 1.5\n"); + xcb_generic_error_t *err; + xcb_randr_get_monitors_reply_t *monitors = + xcb_randr_get_monitors_reply( + conn, xcb_randr_get_monitors(conn, root, true), &err); + if (err != NULL) { + DEBUG("Could not get RandR monitors: X11 error code %d\n", err->error_code); + free(err); + /* Fall back to RandR ≤ 1.4 */ + return false; + } + + int screens = xcb_randr_get_monitors_monitors_length(monitors); + DEBUG("%d RandR monitors found (timestamp %d)\n", + screens, monitors->timestamp); + + Rect *resolutions = malloc(screens * sizeof(Rect)); + /* No memory? Just keep on using the old information. */ + if (!resolutions) { + free(monitors); + return true; + } + + xcb_randr_monitor_info_iterator_t iter; + int screen; + for (iter = xcb_randr_get_monitors_monitors_iterator(monitors), screen = 0; + iter.rem; + xcb_randr_monitor_info_next(&iter), screen++) { + const xcb_randr_monitor_info_t *monitor_info = iter.data; + + resolutions[screen].x = monitor_info->x; + resolutions[screen].y = monitor_info->y; + resolutions[screen].width = monitor_info->width; + resolutions[screen].height = monitor_info->height; + DEBUG("found RandR monitor: %d x %d at %d x %d\n", + monitor_info->width, monitor_info->height, + monitor_info->x, monitor_info->y); + } + free(xr_resolutions); + xr_resolutions = resolutions; + xr_screens = screens; + + free(monitors); + return true; +#endif +} + +/* + * randr_query_outputs_14 uses RandR ≤ 1.4 to update outputs. + * + */ +static bool _randr_query_outputs_14(xcb_window_t root) { + if (!has_randr) { + return false; + } + DEBUG("Querying outputs using RandR ≤ 1.4\n"); + + /* Get screen resources (primary output, crtcs, outputs, modes) */ + xcb_randr_get_screen_resources_current_cookie_t rcookie; + rcookie = xcb_randr_get_screen_resources_current(conn, root); + + xcb_randr_get_screen_resources_current_reply_t *res = + xcb_randr_get_screen_resources_current_reply(conn, rcookie, NULL); + if (res == NULL) { + DEBUG("Could not query screen resources.\n"); + return false; + } + + /* timestamp of the configuration so that we get consistent replies to all + * requests (if the configuration changes between our different calls) */ + const xcb_timestamp_t cts = res->config_timestamp; + + const int len = xcb_randr_get_screen_resources_current_outputs_length(res); + + /* an output is VGA-1, LVDS-1, etc. (usually physical video outputs) */ + xcb_randr_output_t *randr_outputs = xcb_randr_get_screen_resources_current_outputs(res); + + /* Request information for each output */ + xcb_randr_get_output_info_cookie_t ocookie[len]; + for (int i = 0; i < len; i++) { + ocookie[i] = xcb_randr_get_output_info(conn, randr_outputs[i], cts); + } + Rect *resolutions = malloc(len * sizeof(Rect)); + /* No memory? Just keep on using the old information. */ + if (!resolutions) { + free(res); + return true; + } + + /* Loop through all outputs available for this X11 screen */ + int screen = 0; + + for (int i = 0; i < len; i++) { + xcb_randr_get_output_info_reply_t *output; + + if ((output = xcb_randr_get_output_info_reply(conn, ocookie[i], NULL)) == NULL) { + continue; + } + + if (output->crtc == XCB_NONE) { + free(output); + continue; + } + + xcb_randr_get_crtc_info_cookie_t icookie; + xcb_randr_get_crtc_info_reply_t *crtc; + icookie = xcb_randr_get_crtc_info(conn, output->crtc, cts); + if ((crtc = xcb_randr_get_crtc_info_reply(conn, icookie, NULL)) == NULL) { + DEBUG("Skipping output: could not get CRTC (0x%08x)\n", output->crtc); + free(output); + continue; + } + + resolutions[screen].x = crtc->x; + resolutions[screen].y = crtc->y; + resolutions[screen].width = crtc->width; + resolutions[screen].height = crtc->height; + + DEBUG("found RandR output: %d x %d at %d x %d\n", + crtc->width, crtc->height, + crtc->x, crtc->y); + + screen++; + + free(crtc); + + free(output); + } + free(xr_resolutions); + xr_resolutions = resolutions; + xr_screens = screen; + free(res); + return true; +} + +void _xinerama_query_screens(void) { + if (!xinerama_active) { + return; + } + + xcb_xinerama_query_screens_cookie_t cookie; + xcb_xinerama_query_screens_reply_t *reply; + xcb_xinerama_screen_info_t *screen_info; + xcb_generic_error_t *err; + cookie = xcb_xinerama_query_screens_unchecked(conn); + reply = xcb_xinerama_query_screens_reply(conn, cookie, &err); + if (!reply) { + DEBUG("Couldn't get Xinerama screens: X11 error code %d\n", err->error_code); + free(err); + return; + } + screen_info = xcb_xinerama_query_screens_screen_info(reply); + int screens = xcb_xinerama_query_screens_screen_info_length(reply); + + Rect *resolutions = malloc(screens * sizeof(Rect)); + /* No memory? Just keep on using the old information. */ + if (!resolutions) { + free(reply); + return; + } + + for (int screen = 0; screen < xr_screens; screen++) { + resolutions[screen].x = screen_info[screen].x_org; + resolutions[screen].y = screen_info[screen].y_org; + resolutions[screen].width = screen_info[screen].width; + resolutions[screen].height = screen_info[screen].height; + DEBUG("found Xinerama screen: %d x %d at %d x %d\n", + screen_info[screen].width, screen_info[screen].height, + screen_info[screen].x_org, screen_info[screen].y_org); + } + + free(xr_resolutions); + xr_resolutions = resolutions; + xr_screens = screens; + + free(reply); +} + +void randr_query(xcb_window_t root) { + if (_randr_query_monitors_15(root)) { + return; + } + + if (_randr_query_outputs_14(root)) { + return; + } + + _xinerama_query_screens(); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/randr.h new/i3lock-2.10/randr.h --- old/i3lock-2.9.1/randr.h 1970-01-01 01:00:00.000000000 +0100 +++ new/i3lock-2.10/randr.h 2017-11-25 08:15:59.000000000 +0100 @@ -0,0 +1,17 @@ +#ifndef _XINERAMA_H +#define _XINERAMA_H + +typedef struct Rect { + int16_t x; + int16_t y; + uint16_t width; + uint16_t height; +} Rect; + +extern int xr_screens; +extern Rect *xr_resolutions; + +void randr_init(int *event_base, xcb_window_t root); +void randr_query(xcb_window_t root); + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/unlock_indicator.c new/i3lock-2.10/unlock_indicator.c --- old/i3lock-2.9.1/unlock_indicator.c 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/unlock_indicator.c 2017-11-25 08:15:59.000000000 +0100 @@ -19,7 +19,7 @@ #include "i3lock.h" #include "xcb.h" #include "unlock_indicator.h" -#include "xinerama.h" +#include "randr.h" #define BUTTON_RADIUS 90 #define BUTTON_SPACE (BUTTON_RADIUS + 5) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/xcb.c new/i3lock-2.10/xcb.c --- old/i3lock-2.9.1/xcb.c 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/xcb.c 2017-11-25 08:15:59.000000000 +0100 @@ -19,6 +19,7 @@ #include <assert.h> #include <err.h> #include <time.h> +#include <sys/time.h> #include "cursors.h" #include "unlock_indicator.h" @@ -162,21 +163,27 @@ } /* - * Repeatedly tries to grab pointer and keyboard (up to 10000 times). + * Repeatedly tries to grab pointer and keyboard (up to the specified number of + * tries). + * + * Returns true if the grab succeeded, false if not. * */ -void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor) { +bool grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor, int tries) { xcb_grab_pointer_cookie_t pcookie; xcb_grab_pointer_reply_t *preply; xcb_grab_keyboard_cookie_t kcookie; xcb_grab_keyboard_reply_t *kreply; - int tries = 10000; + const suseconds_t screen_redraw_timeout = 100000; /* 100ms */ /* Using few variables to trigger a redraw_screen() if too many tries */ bool redrawn = false; - time_t start = clock(); + struct timeval start; + if (gettimeofday(&start, NULL) == -1) { + err(EXIT_FAILURE, "gettimeofday"); + } while (tries-- > 0) { pcookie = xcb_grab_pointer( @@ -199,10 +206,17 @@ /* Make this quite a bit slower */ usleep(50); - /* Measure elapsed time and trigger a screen redraw if elapsed > 250000 */ + struct timeval now; + if (gettimeofday(&now, NULL) == -1) { + err(EXIT_FAILURE, "gettimeofday"); + } + + struct timeval elapsed; + timersub(&now, &start, &elapsed); + if (!redrawn && (tries % 100) == 0 && - (clock() - start) > 250000) { + elapsed.tv_usec >= screen_redraw_timeout) { redraw_screen(); redrawn = true; } @@ -226,23 +240,24 @@ /* Make this quite a bit slower */ usleep(50); - /* Measure elapsed time and trigger a screen redraw if elapsed > 250000 */ + struct timeval now; + if (gettimeofday(&now, NULL) == -1) { + err(EXIT_FAILURE, "gettimeofday"); + } + + struct timeval elapsed; + timersub(&now, &start, &elapsed); + + /* Trigger a screen redraw if 100ms elapsed */ if (!redrawn && (tries % 100) == 0 && - (clock() - start) > 250000) { + elapsed.tv_usec >= screen_redraw_timeout) { redraw_screen(); redrawn = true; } } - /* After trying for 10000 times, i3lock will display an error message - * for 2 sec prior to terminate. */ - if (tries <= 0) { - auth_state = STATE_I3LOCK_LOCK_FAILED; - redraw_screen(); - sleep(1); - errx(EXIT_FAILURE, "Cannot grab pointer/keyboard"); - } + return (tries > 0); } xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_window_t win, int choice) { @@ -307,3 +322,67 @@ return cursor; } + +static xcb_atom_t _NET_ACTIVE_WINDOW = XCB_NONE; +void _init_net_active_window(xcb_connection_t *conn) { + if (_NET_ACTIVE_WINDOW != XCB_NONE) { + /* already initialized */ + return; + } + xcb_generic_error_t *err; + xcb_intern_atom_reply_t *atom_reply = xcb_intern_atom_reply( + conn, + xcb_intern_atom(conn, 0, strlen("_NET_ACTIVE_WINDOW"), "_NET_ACTIVE_WINDOW"), + &err); + if (atom_reply == NULL) { + fprintf(stderr, "X11 Error %d\n", err->error_code); + free(err); + return; + } + _NET_ACTIVE_WINDOW = atom_reply->atom; + free(atom_reply); +} + +xcb_window_t find_focused_window(xcb_connection_t *conn, const xcb_window_t root) { + xcb_window_t result = XCB_NONE; + + _init_net_active_window(conn); + + xcb_get_property_reply_t *prop_reply = xcb_get_property_reply( + conn, + xcb_get_property_unchecked( + conn, false, root, _NET_ACTIVE_WINDOW, XCB_GET_PROPERTY_TYPE_ANY, 0, 1 /* word */), + NULL); + if (prop_reply == NULL) { + goto out; + } + if (xcb_get_property_value_length(prop_reply) == 0) { + goto out_prop; + } + if (prop_reply->type != XCB_ATOM_WINDOW) { + goto out_prop; + } + + result = *((xcb_window_t *)xcb_get_property_value(prop_reply)); + +out_prop: + free(prop_reply); +out: + return result; +} + +void set_focused_window(xcb_connection_t *conn, const xcb_window_t root, const xcb_window_t window) { + xcb_client_message_event_t ev; + memset(&ev, '\0', sizeof(xcb_client_message_event_t)); + + _init_net_active_window(conn); + + ev.response_type = XCB_CLIENT_MESSAGE; + ev.window = window; + ev.type = _NET_ACTIVE_WINDOW; + ev.format = 32; + ev.data.data32[0] = 2; /* 2 = pager */ + + xcb_send_event(conn, false, root, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *)&ev); + xcb_flush(conn); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/xcb.h new/i3lock-2.10/xcb.h --- old/i3lock-2.9.1/xcb.h 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/xcb.h 2017-11-25 08:15:59.000000000 +0100 @@ -9,7 +9,9 @@ xcb_visualtype_t *get_root_visual_type(xcb_screen_t *s); xcb_pixmap_t create_bg_pixmap(xcb_connection_t *conn, xcb_screen_t *scr, u_int32_t *resolution, char *color); xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color, xcb_pixmap_t pixmap); -void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor); +bool grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor, int tries); xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_window_t win, int choice); +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); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/xinerama.c new/i3lock-2.10/xinerama.c --- old/i3lock-2.9.1/xinerama.c 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/xinerama.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,90 +0,0 @@ -/* - * vim:ts=4:sw=4:expandtab - * - * © 2010 Michael Stapelberg - * - * See LICENSE for licensing information - * - */ -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <xcb/xcb.h> -#include <xcb/xinerama.h> - -#include "i3lock.h" -#include "xcb.h" -#include "xinerama.h" - -/* Number of Xinerama screens which are currently present. */ -int xr_screens = 0; - -/* The resolutions of the currently present Xinerama screens. */ -Rect *xr_resolutions; - -static bool xinerama_active; -extern bool debug_mode; - -void xinerama_init(void) { - if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) { - DEBUG("Xinerama extension not found, disabling.\n"); - return; - } - - xcb_xinerama_is_active_cookie_t cookie; - xcb_xinerama_is_active_reply_t *reply; - - cookie = xcb_xinerama_is_active(conn); - reply = xcb_xinerama_is_active_reply(conn, cookie, NULL); - if (!reply) - return; - - if (!reply->state) { - free(reply); - return; - } - - xinerama_active = true; - free(reply); -} - -void xinerama_query_screens(void) { - if (!xinerama_active) - return; - - xcb_xinerama_query_screens_cookie_t cookie; - xcb_xinerama_query_screens_reply_t *reply; - xcb_xinerama_screen_info_t *screen_info; - - cookie = xcb_xinerama_query_screens_unchecked(conn); - reply = xcb_xinerama_query_screens_reply(conn, cookie, NULL); - if (!reply) { - if (debug_mode) - fprintf(stderr, "Couldn't get Xinerama screens\n"); - return; - } - screen_info = xcb_xinerama_query_screens_screen_info(reply); - int screens = xcb_xinerama_query_screens_screen_info_length(reply); - - Rect *resolutions = malloc(screens * sizeof(Rect)); - /* No memory? Just keep on using the old information. */ - if (!resolutions) { - free(reply); - return; - } - xr_resolutions = resolutions; - xr_screens = screens; - - for (int screen = 0; screen < xr_screens; screen++) { - xr_resolutions[screen].x = screen_info[screen].x_org; - xr_resolutions[screen].y = screen_info[screen].y_org; - xr_resolutions[screen].width = screen_info[screen].width; - xr_resolutions[screen].height = screen_info[screen].height; - DEBUG("found Xinerama screen: %d x %d at %d x %d\n", - screen_info[screen].width, screen_info[screen].height, - screen_info[screen].x_org, screen_info[screen].y_org); - } - - free(reply); -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/i3lock-2.9.1/xinerama.h new/i3lock-2.10/xinerama.h --- old/i3lock-2.9.1/xinerama.h 2017-06-21 18:18:26.000000000 +0200 +++ new/i3lock-2.10/xinerama.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,17 +0,0 @@ -#ifndef _XINERAMA_H -#define _XINERAMA_H - -typedef struct Rect { - int16_t x; - int16_t y; - uint16_t width; - uint16_t height; -} Rect; - -extern int xr_screens; -extern Rect *xr_resolutions; - -void xinerama_init(void); -void xinerama_query_screens(void); - -#endif
