i3 - improved tiling WM


Authentication in different process

Patch status: needinfo

Patch by Philippe Virouleau

Long description:

Add the possibility to buffer keystrokes when a process is running authentication
Fix #1090.

To apply this patch, use:
curl http://cr.i3wm.org/patch/293/raw.patch | git am

b/i3lock.c

15
@@ -45,6 +45,9 @@ static pam_handle_t *pam_handle;
16
 int input_position = 0;
17
 /* Holds the password you enter (in UTF-8). */
18
 static char password[512];
19
+static xcb_key_press_event_t *buffered_events[512];
20
+static int event_index = 0;
21
+static int replay_index = 0;
22
 static bool beep = false;
23
 bool debug_mode = false;
24
 static bool dpms = false;
25
@@ -187,10 +190,14 @@ static void clear_pam_wrong(EV_P_ ev_timer *w, int revents) {
26
     clear_pam_wrong_timeout = NULL;
27
 }
28
 
29
-static void clear_input(void) {
30
+static void reset_input(void) {
31
     input_position = 0;
32
     clear_password_memory();
33
     password[input_position] = '\0';
34
+}
35
+
36
+static void clear_input(void) {
37
+    reset_input();
38
 
39
     /* Hide the unlock indicator after a bit if the password buffer is
40
      * empty. */
41
@@ -205,7 +212,6 @@ static void auth_failed(void) {
42
         fprintf(stderr, "Authentication failure\n");
43
 
44
     pam_state = STATE_PAM_WRONG;
45
-    clear_input();
46
     redraw_screen();
47
 
48
     /* Clear this state after 2 seconds (unless the user enters another
49
@@ -227,6 +233,9 @@ static void auth_failed(void) {
50
     }
51
 }
52
 
53
+static void handle_key_press(xcb_key_press_event_t *event);
54
+static void handle_key_release(xcb_key_release_event_t *event);
55
+
56
 static void child_cb(EV_P_ ev_child *child_watcher, int revents) {
57
     if (child_watcher->rstatus != 0) {
58
         DEBUG("Authentication successfull\n");
59
@@ -234,7 +243,44 @@ static void child_cb(EV_P_ ev_child *child_watcher, int revents) {
60
 
61
         exit(0);
62
     } else {
63
+        if (replay_index > 0 && replay_index <= event_index) {
64
+            /* Move the remaining events in order to free some space */
65
+            memmove(buffered_events, buffered_events+replay_index,
66
+                (event_index - replay_index + 1) * sizeof(xcb_key_press_event_t *));
67
+            event_index -= replay_index;
68
+            replay_index = 0;
69
+            buffered_events[event_index+1] = NULL;
70
+        }
71
         auth_failed();
72
+        while (replay_index <= event_index && pam_state != STATE_PAM_VERIFY) {
73
+            xcb_key_press_event_t *theEvent = buffered_events[replay_index];
74
+            replay_index++;
75
+            if (theEvent) {
76
+                /* Strip off the highest bit (set if the event is generated) */
77
+                int type = (theEvent->response_type & 0x7F);
78
+                switch (type) {
79
+                    case XCB_KEY_PRESS:
80
+                        handle_key_press((xcb_key_press_event_t*)theEvent);
81
+                        break;
82
+
83
+                    case XCB_KEY_RELEASE:
84
+                        handle_key_release((xcb_key_release_event_t*)theEvent);
85
+
86
+                        /* If this was the backspace or escape key we are back at an
87
+                         * empty input, so turn off the screen if DPMS is enabled */
88
+                        if (dpms && input_position == 0)
89
+                            dpms_turn_off_screen(conn);
90
+
91
+                        break;
92
+                }
93
+            } else {
94
+                /* No more event to replay, reset everything */
95
+                replay_index = 0;
96
+                event_index = 0;
97
+                buffered_events[event_index] = NULL;
98
+                break;
99
+            }
100
+        }
101
     }
102
     ev_child_stop(main_loop, child_watcher);
103
     free(child_watcher);
104
@@ -259,7 +305,8 @@ static void input_done(void) {
105
     if (cpid == 0) {
106
         exit(pam_authenticate(pam_handle, 0) == PAM_SUCCESS);
107
     } else if (cpid > 0) {
108
-        struct ev_child *child_watcher = calloc(sizeof(struct ev_io), 1);
109
+        reset_input();
110
+        struct ev_child *child_watcher = calloc(sizeof(struct ev_child), 1);
111
         ev_child_init(child_watcher, child_cb, cpid, 0);
112
         ev_child_set(child_watcher, cpid, 0);
113
         ev_child_start(EV_DEFAULT_ child_watcher);
114
@@ -518,12 +565,29 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
115
 
116
         /* Strip off the highest bit (set if the event is generated) */
117
         int type = (event->response_type & 0x7F);
118
+        int buffer_size = sizeof(buffered_events)/sizeof(xcb_key_press_event_t *);
119
         switch (type) {
120
             case XCB_KEY_PRESS:
121
+                if (pam_state == STATE_PAM_VERIFY) {
122
+                    if (event_index < buffer_size - 1)
123
+                        buffered_events[event_index++] = (xcb_key_press_event_t*)event;
124
+                    else
125
+                        /* if we can't buffer the event, then free it */
126
+                        break;
127
+                    /* else don't free the event, it will be freed when replayed */
128
+                    continue;
129
+                }
130
                 handle_key_press((xcb_key_press_event_t*)event);
131
                 break;
132
 
133
             case XCB_KEY_RELEASE:
134
+                if (pam_state == STATE_PAM_VERIFY) {
135
+                    if (event_index < buffer_size - 1)
136
+                        buffered_events[event_index++] = (xcb_key_press_event_t*)event;
137
+                    else
138
+                        break;
139
+                    continue;
140
+                }
141
                 handle_key_release((xcb_key_release_event_t*)event);
142
 
143
                 /* If this was the backspace or escape key we are back at an