Browse Source

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.
master
Michael Stapelberg 11 years ago
parent
commit
ac8bbad523
  1. 73
      i3lock.c

73
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);

Loading…
Cancel
Save