summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <michael@stapelberg.de>2013-11-10 20:40:52 +0100
committerMichael Stapelberg <michael@stapelberg.de>2013-11-10 20:43:08 +0100
commitac8bbad523c45085061b77ce1bcbc0381306ce8b (patch)
tree7316182d096c3078c4e48a8bd49f0e8d72199faf
parentd7fd058f0c31f7e20fedc0b8c7f5afd90f521ae8 (diff)
Re-raise i3lock when obscured in a separate process
This is cleaner than commit a305e62 (running authentication in a separate process) because we don’t lose the feature that X11 will buffer KeyPresses for us while the process blocks on PAM. See http://cr.i3wm.org/patch/305 for the amount of code (and new known bugs) that would have to be introduced to make a305e62 work.
-rw-r--r--i3lock.c73
1 files changed, 71 insertions, 2 deletions
diff --git a/i3lock.c b/i3lock.c
index 74e15f2..533a28d 100644
--- a/i3lock.c
+++ b/i3lock.c
@@ -364,7 +364,8 @@ static void handle_key_press(xcb_key_press_event_t *event) {
* hiding us) gets hidden.
*
*/
-static void handle_visibility_notify(xcb_visibility_notify_event_t *event) {
+static void handle_visibility_notify(xcb_connection_t *conn,
+ xcb_visibility_notify_event_t *event) {
if (event->state != XCB_VISIBILITY_UNOBSCURED) {
uint32_t values[] = { XCB_STACK_MODE_ABOVE };
xcb_configure_window(conn, event->window, XCB_CONFIG_WINDOW_STACK_MODE, values);
@@ -501,7 +502,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
break;
case XCB_VISIBILITY_NOTIFY:
- handle_visibility_notify((xcb_visibility_notify_event_t*)event);
+ handle_visibility_notify(conn, (xcb_visibility_notify_event_t*)event);
break;
case XCB_MAP_NOTIFY:
@@ -531,6 +532,63 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
}
}
+/*
+ * This function is called from a fork()ed child and will raise the i3lock
+ * window when the window is obscured, even when the main i3lock process is
+ * blocked due to PAM.
+ *
+ */
+static void raise_loop(xcb_window_t window) {
+ xcb_connection_t *conn;
+ xcb_generic_event_t *event;
+ int screens;
+
+ if ((conn = xcb_connect(NULL, &screens)) == NULL ||
+ xcb_connection_has_error(conn))
+ errx(EXIT_FAILURE, "Cannot open display\n");
+
+ /* We need to know about the window being obscured or getting destroyed. */
+ xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK,
+ (uint32_t[]){
+ XCB_EVENT_MASK_VISIBILITY_CHANGE |
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY
+ });
+ xcb_flush(conn);
+
+ DEBUG("Watching window 0x%08x\n", window);
+ while ((event = xcb_wait_for_event(conn)) != NULL) {
+ if (event->response_type == 0) {
+ xcb_generic_error_t *error = (xcb_generic_error_t*)event;
+ DEBUG("X11 Error received! sequence 0x%x, error_code = %d\n",
+ error->sequence, error->error_code);
+ free(event);
+ continue;
+ }
+ /* Strip off the highest bit (set if the event is generated) */
+ int type = (event->response_type & 0x7F);
+ DEBUG("Read event of type %d\n", type);
+ switch (type) {
+ case XCB_VISIBILITY_NOTIFY:
+ handle_visibility_notify(conn, (xcb_visibility_notify_event_t*)event);
+ break;
+ case XCB_UNMAP_NOTIFY:
+ DEBUG("UnmapNotify for 0x%08x\n", (((xcb_unmap_notify_event_t*)event)->window));
+ if (((xcb_unmap_notify_event_t*)event)->window == window)
+ exit(EXIT_SUCCESS);
+ break;
+ case XCB_DESTROY_NOTIFY:
+ DEBUG("DestroyNotify for 0x%08x\n", (((xcb_destroy_notify_event_t*)event)->window));
+ if (((xcb_destroy_notify_event_t*)event)->window == window)
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ DEBUG("Unhandled event type %d\n", type);
+ break;
+ }
+ free(event);
+ }
+}
+
int main(int argc, char *argv[]) {
char *username;
char *image_path = NULL;
@@ -692,6 +750,17 @@ int main(int argc, char *argv[]) {
win = open_fullscreen_window(conn, screen, color, bg_pixmap);
xcb_free_pixmap(conn, bg_pixmap);
+ pid_t pid = fork();
+ /* The pid == -1 case is intentionally ignored here:
+ * While the child process is useful for preventing other windows from
+ * popping up while i3lock blocks, it is not critical. */
+ if (pid == 0) {
+ /* Child */
+ close(xcb_get_file_descriptor(conn));
+ raise_loop(win);
+ exit(EXIT_SUCCESS);
+ }
+
cursor = create_cursor(conn, screen, win, curs_choice);
grab_pointer_and_keyboard(conn, screen, cursor);