]> git.sur5r.net Git - i3/i3lock/blobdiff - i3lock.c
Switch to autotools (#163)
[i3/i3lock] / i3lock.c
index 853862566778165189c54d40041c4393d1f26f15..d6f2151671811dcf7641178dd0ec552abb983878 100644 (file)
--- a/i3lock.c
+++ b/i3lock.c
@@ -6,6 +6,8 @@
  * See LICENSE for licensing information
  *
  */
+#include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <pwd.h>
 #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 +88,7 @@ static struct xkb_compose_table *xkb_compose_table;
 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;
@@ -175,7 +180,7 @@ static void clear_password_memory(void) {
     /* A volatile pointer to the password buffer to prevent the compiler from
      * optimizing this out. */
     volatile char *vpassword = password;
-    for (int c = 0; c < sizeof(password); c++)
+    for (size_t c = 0; c < sizeof(password); c++)
         /* We store a non-random pattern which consists of the (irrelevant)
          * index plus (!) the value of the beep variable. This prevents the
          * compiler from optimizing the calls away, since the value of 'beep'
@@ -278,7 +283,8 @@ static void input_done(void) {
         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 +298,8 @@ static void input_done(void) {
         pam_setcred(pam_handle, PAM_REFRESH_CRED);
         pam_end(pam_handle, PAM_SUCCESS);
 
-        exit(0);
+        ev_break(EV_DEFAULT, EVBREAK_ALL);
+        return;
     }
 #endif
 
@@ -481,7 +488,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
             return;
     }
 
-    if ((input_position + 8) >= sizeof(password))
+    if ((input_position + 8) >= (int)sizeof(password))
         return;
 
 #if 0
@@ -617,7 +624,7 @@ void handle_screen_resize(void) {
     xcb_configure_window(conn, win, mask, last_resolution);
     xcb_flush(conn);
 
-    xinerama_query_screens();
+    randr_query(screen->root);
     redraw_screen();
 }
 
@@ -740,8 +747,14 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
                 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);
@@ -841,7 +854,7 @@ int main(int argc, char *argv[]) {
     while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) {
         switch (o) {
             case 'v':
-                errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg");
+                errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg");
             case 'n':
                 dont_fork = true;
                 break;
@@ -984,11 +997,11 @@ int main(int argc, char *argv[]) {
 
     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;
 
@@ -1010,6 +1023,8 @@ int main(int argc, char *argv[]) {
     /* 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);
@@ -1018,7 +1033,23 @@ int main(int argc, char *argv[]) {
 
     /* 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:
@@ -1065,4 +1096,17 @@ int main(int argc, char *argv[]) {
      * 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;
 }