i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
i3lock.c (90094B)
   1 /*
   2  * vim:ts=4:sw=4:expandtab
   3  *
   4  * © 2010 Michael Stapelberg
   5  * © 2015 Cassandra Fox
   6  * © 2021 Raymond Li
   7  *
   8  * See LICENSE for licensing information
   9  *
  10  */
  11 #include <config.h>
  12 
  13 #include <pthread.h>
  14 #include <math.h>
  15 
  16 #include <stdio.h>
  17 #include <locale.h>
  18 #include <stdlib.h>
  19 #include <pwd.h>
  20 #include <sys/types.h>
  21 #include <dirent.h>
  22 #include <unistd.h>
  23 #include <stdbool.h>
  24 #include <stdint.h>
  25 #include <xcb/xcb.h>
  26 #include <xcb/xkb.h>
  27 #include <xcb/xproto.h>
  28 #include <err.h>
  29 #include <errno.h>
  30 #include <assert.h>
  31 #include <regex.h>
  32 #ifdef __OpenBSD__
  33 #include <bsd_auth.h>
  34 #else
  35 #include <security/pam_appl.h>
  36 #endif
  37 #include <getopt.h>
  38 #include <string.h>
  39 #include <ev.h>
  40 #include <sys/mman.h>
  41 #include <xkbcommon/xkbcommon.h>
  42 #if XKBCOMPOSE == 1
  43 #include <xkbcommon/xkbcommon-compose.h>
  44 #endif
  45 #include <xkbcommon/xkbcommon-x11.h>
  46 #include <cairo.h>
  47 #include <cairo/cairo-xcb.h>
  48 #ifdef HAVE_EXPLICIT_BZERO
  49 #include <strings.h> /* explicit_bzero(3) */
  50 #endif
  51 #include <xcb/xcb_aux.h>
  52 #include <xcb/randr.h>
  53 
  54 #include "i3lock.h"
  55 #include "xcb.h"
  56 #include "cursors.h"
  57 #include "unlock_indicator.h"
  58 #include "randr.h"
  59 #include "dpi.h"
  60 #include "blur.h"
  61 #include "jpg.h"
  62 #include "fonts.h"
  63 
  64 #define TSTAMP_N_SECS(n) (n * 1.0)
  65 #define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n))
  66 #define START_TIMER(timer_obj, timeout, callback) \
  67     timer_obj = start_timer(timer_obj, timeout, callback)
  68 #define STOP_TIMER(timer_obj) \
  69     timer_obj = stop_timer(timer_obj)
  70 
  71 typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents);
  72 static void input_done(void);
  73 
  74 char color[9] = "a3a3a3ff";
  75 
  76 /* options for unlock indicator colors */
  77 char insidevercolor[9] = "006effbf";
  78 char insidewrongcolor[9] = "fa0000bf";
  79 char insidecolor[9] = "000000bf";
  80 char ringvercolor[9] = "3300faff";
  81 char ringwrongcolor[9] = "7d3300ff";
  82 char ringcolor[9] = "337d00ff";
  83 char linecolor[9] = "000000ff";
  84 char verifcolor[9] = "000000ff";
  85 char wrongcolor[9] = "000000ff";
  86 char layoutcolor[9] = "000000ff";
  87 char timecolor[9] = "000000ff";
  88 char datecolor[9] = "000000ff";
  89 char modifcolor[9] = "000000ff";
  90 char keyhlcolor[9] = "33db00ff";
  91 char bshlcolor[9] = "db3300ff";
  92 char separatorcolor[9] = "000000ff";
  93 char greetercolor[9] = "000000ff";
  94 
  95 char verifoutlinecolor[9] = "00000000";
  96 char wrongoutlinecolor[9] = "00000000";
  97 char layoutoutlinecolor[9] = "00000000";
  98 char timeoutlinecolor[9] = "00000000";
  99 char dateoutlinecolor[9] = "00000000";
 100 char greeteroutlinecolor[9] = "00000000";
 101 char modifoutlinecolor[9] = "00000000";
 102 
 103 /* int defining which display the lock indicator should be shown on. If -1, then show on all displays.*/
 104 int screen_number = 0;
 105 
 106 /* default is to use the supplied line color, 1 will be ring color, 2 will be to use the inside color for ver/wrong/etc */
 107 int internal_line_source = 0;
 108 
 109 /* refresh rate in seconds, default to 1s */
 110 float refresh_rate = 1.0;
 111 
 112 bool show_clock = false;
 113 bool slideshow_enabled = false;
 114 bool always_show_clock = false;
 115 bool show_indicator = false;
 116 bool show_modkey_text = true;
 117 
 118 /* there's some issues with compositing - upstream removed support for this, but we'll allow people to supply an arg to enable it */
 119 bool composite = false;
 120 /* time formatter strings for date/time
 121     I picked 32-length char arrays because some people might want really funky time formatters.
 122     Who am I to judge?
 123 */
 124 /*
 125  * 0 = center
 126  * 1 = left
 127  * 2 = right
 128  */
 129 int verif_align = 0;
 130 int wrong_align = 0;
 131 int time_align = 0;
 132 int date_align = 0;
 133 int layout_align = 0;
 134 int modif_align = 0;
 135 int greeter_align = 0;
 136 
 137 char time_format[32] = "%H:%M:%S\0";
 138 char date_format[32] = "%A, %m %Y\0";
 139 
 140 char verif_font[64] = "sans-serif\0";
 141 char wrong_font[64] = "sans-serif\0";
 142 char layout_font[64] = "sans-serif\0";
 143 char time_font[64] = "sans-serif\0";
 144 char date_font[64] = "sans-serif\0";
 145 char greeter_font[64] = "sans-serif\0";
 146 
 147 char* fonts[6] = {
 148     verif_font,
 149     wrong_font,
 150     layout_font,
 151     time_font,
 152     date_font,
 153     greeter_font
 154 };
 155 
 156 char ind_x_expr[32] = "x + (w / 2)\0";
 157 char ind_y_expr[32] = "y + (h / 2)\0";
 158 char time_x_expr[32] = "ix\0";
 159 char time_y_expr[32] = "iy\0";
 160 char date_x_expr[32] = "tx\0";
 161 char date_y_expr[32] = "ty+30\0";
 162 char layout_x_expr[32] = "dx\0";
 163 char layout_y_expr[32] = "dy+30\0";
 164 char status_x_expr[32] = "ix\0";
 165 char status_y_expr[32] = "iy\0";
 166 char modif_x_expr[32] = "ix\0";
 167 char modif_y_expr[32] = "iy+28\0";
 168 char verif_x_expr[32] = "ix\0";
 169 char verif_y_expr[32] = "iy\0";
 170 char wrong_x_expr[32] = "ix\0";
 171 char wrong_y_expr[32] = "iy\0";
 172 char greeter_x_expr[32] = "ix\0";
 173 char greeter_y_expr[32] = "iy\0";
 174 
 175 double time_size = 32.0;
 176 double date_size = 14.0;
 177 double verif_size = 28.0;
 178 double wrong_size = 28.0;
 179 double modifier_size = 14.0;
 180 double layout_size = 14.0;
 181 double circle_radius = 90.0;
 182 double ring_width = 7.0;
 183 double greeter_size = 32.0;
 184 
 185 double timeoutlinewidth = 0;
 186 double dateoutlinewidth = 0;
 187 double verifoutlinewidth = 0;
 188 double wrongoutlinewidth = 0;
 189 double modifieroutlinewidth = 0;
 190 double layoutoutlinewidth = 0;
 191 double greeteroutlinewidth = 0;
 192 
 193 char* verif_text = "verifying…";
 194 char* wrong_text = "wrong!";
 195 char* noinput_text = "no input";
 196 char* lock_text = "locking…";
 197 char* lock_failed_text = "lock failed!";
 198 int   keylayout_mode = -1;
 199 char* layout_text = NULL;
 200 char* greeter_text = "";
 201 
 202 /* opts for blurring */
 203 bool blur = false;
 204 bool step_blur = false;
 205 int blur_sigma = 5;
 206 
 207 /* do not verify password */
 208 bool no_verify = false;
 209 
 210 uint32_t last_resolution[2];
 211 xcb_window_t win;
 212 static xcb_cursor_t cursor;
 213 #ifndef __OpenBSD__
 214 static pam_handle_t *pam_handle;
 215 static bool pam_cleanup;
 216 #endif
 217 int input_position = 0;
 218 /* Holds the password you enter (in UTF-8). */
 219 static char password[512];
 220 static bool beep = false;
 221 bool debug_mode = false;
 222 bool unlock_indicator = true;
 223 char *modifier_string = NULL;
 224 static bool dont_fork = false;
 225 struct ev_loop *main_loop;
 226 static struct ev_timer *clear_auth_wrong_timeout;
 227 static struct ev_timer *clear_indicator_timeout;
 228 static struct ev_timer *discard_passwd_timeout;
 229 extern unlock_state_t unlock_state;
 230 extern auth_state_t auth_state;
 231 int failed_attempts = 0;
 232 bool show_failed_attempts = false;
 233 bool retry_verification = false;
 234 
 235 static struct xkb_state *xkb_state;
 236 static struct xkb_context *xkb_context;
 237 static struct xkb_keymap *xkb_keymap;
 238 #if XKBCOMPOSE == 1
 239 static struct xkb_compose_table *xkb_compose_table;
 240 static struct xkb_compose_state *xkb_compose_state;
 241 #endif
 242 static uint8_t xkb_base_event;
 243 static uint8_t xkb_base_error;
 244 static int randr_base = -1;
 245 
 246 char *image_path = NULL;
 247 char *image_raw_format = NULL;
 248 char *slideshow_path = NULL;
 249 
 250 cairo_surface_t *img = NULL;
 251 char *img_slideshow[256];
 252 cairo_surface_t *blur_bg_img = NULL;
 253 int slideshow_image_count = 0;
 254 int slideshow_interval = 10;
 255 bool slideshow_random_selection = false;
 256 
 257 background_type_t bg_type = NONE;
 258 
 259 bool ignore_empty_password = false;
 260 bool skip_repeated_empty_password = false;
 261 bool pass_media_keys = false;
 262 bool pass_screen_keys = false;
 263 bool pass_power_keys = false;
 264 bool pass_volume_keys = false;
 265 
 266 bool hotkeys = false;
 267 char* cmd_brightness_up = NULL;
 268 char* cmd_brightness_down = NULL;
 269 
 270 char* cmd_media_play = NULL;
 271 char* cmd_media_pause = NULL;
 272 char* cmd_media_stop = NULL;
 273 char* cmd_media_next = NULL;
 274 char* cmd_media_prev = NULL;
 275 
 276 char* cmd_audio_mute = NULL;
 277 char* cmd_volume_up = NULL;
 278 char* cmd_volume_down = NULL;
 279 char* cmd_mic_mute = NULL;
 280 
 281 char* cmd_power_down = NULL;
 282 char* cmd_power_off = NULL;
 283 char* cmd_power_sleep = NULL;
 284 
 285 // for the rendering thread, so we can clean it up
 286 pthread_t draw_thread;
 287 // main thread still sometimes calls redraw()
 288 // allow you to disable. handy if you use bar with lots of crap.
 289 bool redraw_thread = false;
 290 
 291 // experimental bar stuff
 292 #define BAR_VERT 0
 293 #define BAR_FLAT 1
 294 #define BAR_DEFAULT 0
 295 #define BAR_REVERSED 1
 296 #define BAR_BIDIRECTIONAL 2
 297 #define MAX_BAR_COUNT 65535
 298 #define MIN_BAR_COUNT 1
 299 
 300 bool bar_enabled = false;
 301 double *bar_heights = NULL;
 302 double bar_step = 15;
 303 double bar_base_height = 25;
 304 double bar_periodic_step = 15;
 305 double max_bar_height = 25;
 306 int bar_count = 10;
 307 int bar_orientation = BAR_FLAT;
 308 
 309 char bar_base_color[9] = "000000ff";
 310 char bar_x_expr[32] = "0";
 311 char bar_y_expr[32] = ""; // empty string on y means use x as offset based on orientation
 312 char bar_width_expr[32] = ""; // empty string means full width based on bar orientation
 313 bool bar_bidirectional = false;
 314 bool bar_reversed = false;
 315 
 316 /* isutf, u8_dec © 2005 Jeff Bezanson, public domain */
 317 #define isutf(c) (((c)&0xC0) != 0x80)
 318 
 319 /*
 320  * Checks if the given path leads to an actual file or something else, e.g. a directory
 321  */
 322 int is_directory(const char *path) {
 323     struct stat path_stat;
 324     stat(path, &path_stat);
 325     return S_ISDIR(path_stat.st_mode);
 326 }
 327 
 328 /*
 329  * Decrements i to point to the previous unicode glyph
 330  *
 331  */
 332 static void u8_dec(char *s, int *i) {
 333     (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i));
 334 }
 335 
 336 /*
 337  * fetches the keylayout name
 338  *      -1 (do not)
 339  * arg: 0 (show full string returned)
 340  *      1 (show the text, sans parenthesis)
 341  *      2 (show just what's in the parenthesis)
 342  *
 343  * credit to the XKB/xcb implementation (no libx11) from https://gist.github.com/bluetech/6061368
 344  * docs are really sparse, so finding some random implementation was nice
 345  */
 346 static char* get_keylayoutname(int mode, xcb_connection_t* conn) {
 347     if (mode < 0 || mode > 2) return NULL;
 348     char *newans = NULL, *newans2 = NULL, *answer = xcb_get_key_group_names(conn);
 349     int substringStart = 0, substringEnd = 0, size = 0;
 350     DEBUG("keylayout answer is: [%s]\n", answer);
 351     switch (mode) {
 352         case 1:
 353             // truncate the string at the first parens
 354             for (int i = 0; answer[i] != '\0'; ++i) {
 355                 if (answer[i] == '(') {
 356                     if (i != 0 && answer[i - 1] == ' ') {
 357                         answer[i - 1] = '\0';
 358                         break;
 359                     } else {
 360                         answer[i] = '\0';
 361                         break;
 362                     }
 363                 }
 364             }
 365             break;
 366         case 2:
 367             for (int i = 0; answer[i] != '\0'; ++i) {
 368                 if (answer[i] == '(') {
 369                     newans = &answer[i + 1];
 370                     substringStart = i + 1;
 371                 } else if (answer[i] == ')' && newans != NULL) {
 372                     answer[i] = '\0';
 373                     substringEnd = i;
 374                     break;
 375                 }
 376             }
 377             if (newans != NULL) {
 378                 size = sizeof(char) * (substringEnd - substringStart + 1);
 379                 newans2 = malloc(size);
 380                 memcpy(newans2, newans, size);
 381                 free(answer);
 382                 answer = newans2;
 383             }
 384             break;
 385         case 0:
 386             // fall through
 387         default:
 388             break;
 389     }
 390     DEBUG("answer after mode parsing: [%s]\n", answer);
 391     // Free symbolic names structures
 392     return answer;
 393 }
 394 
 395 /*
 396  * Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
 397  * Necessary so that we can properly let xkbcommon track the keyboard state and
 398  * translate keypresses to utf-8.
 399  *
 400  */
 401 
 402 static bool load_keymap(void) {
 403     if (xkb_context == NULL) {
 404         if ((xkb_context = xkb_context_new(0)) == NULL) {
 405             fprintf(stderr, "[i3lock] could not create xkbcommon context\n");
 406             return false;
 407         }
 408     }
 409 
 410     xkb_keymap_unref(xkb_keymap);
 411 
 412     int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn);
 413     DEBUG("device = %d\n", device_id);
 414     if ((xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) {
 415         fprintf(stderr, "[i3lock] xkb_x11_keymap_new_from_device failed\n");
 416         return false;
 417     }
 418 
 419     struct xkb_state *new_state =
 420         xkb_x11_state_new_from_device(xkb_keymap, conn, device_id);
 421     if (new_state == NULL) {
 422         fprintf(stderr, "[i3lock] xkb_x11_state_new_from_device failed\n");
 423         return false;
 424     }
 425 
 426     xkb_state_unref(xkb_state);
 427     xkb_state = new_state;
 428 
 429     return true;
 430 }
 431 
 432 #if XKBCOMPOSE == 1
 433 /*
 434  * Loads the XKB compose table from the given locale.
 435  *
 436  */
 437 static bool load_compose_table(const char *locale) {
 438     xkb_compose_table_unref(xkb_compose_table);
 439 
 440     if ((xkb_compose_table = xkb_compose_table_new_from_locale(xkb_context, locale, 0)) == NULL) {
 441         fprintf(stderr, "[i3lock] xkb_compose_table_new_from_locale failed\n");
 442         return false;
 443     }
 444 
 445     struct xkb_compose_state *new_compose_state = xkb_compose_state_new(xkb_compose_table, 0);
 446     if (new_compose_state == NULL) {
 447         fprintf(stderr, "[i3lock] xkb_compose_state_new failed\n");
 448         return false;
 449     }
 450 
 451     xkb_compose_state_unref(xkb_compose_state);
 452     xkb_compose_state = new_compose_state;
 453 
 454     return true;
 455 }
 456 #endif /* XKBCOMPOSE */
 457 
 458 /*
 459  * Clears the memory which stored the password to be a bit safer against
 460  * cold-boot attacks.
 461  *
 462  */
 463 static void clear_password_memory(void) {
 464 #ifdef HAVE_EXPLICIT_BZERO
 465     /* Use explicit_bzero(3) which was explicitly designed not to be
 466      * optimized out by the compiler. */
 467     explicit_bzero(password, strlen(password));
 468 #else
 469     /* A volatile pointer to the password buffer to prevent the compiler from
 470      * optimizing this out. */
 471     volatile char *vpassword = password;
 472     for (size_t c = 0; c < sizeof(password); c++)
 473         /* We store a non-random pattern which consists of the (irrelevant)
 474          * index plus (!) the value of the beep variable. This prevents the
 475          * compiler from optimizing the calls away, since the value of 'beep'
 476          * is not known at compile-time. */
 477         vpassword[c] = c + (int)beep;
 478 #endif
 479 }
 480 
 481 ev_timer *start_timer(ev_timer *timer_obj, ev_tstamp timeout, ev_callback_t callback) {
 482     if (timer_obj) {
 483         ev_timer_stop(main_loop, timer_obj);
 484         ev_timer_set(timer_obj, timeout, 0.);
 485         ev_timer_start(main_loop, timer_obj);
 486     } else {
 487         /* When there is no memory, we just don’t have a timeout. We cannot
 488          * exit() here, since that would effectively unlock the screen. */
 489         timer_obj = calloc(sizeof(struct ev_timer), 1);
 490         if (timer_obj) {
 491             ev_timer_init(timer_obj, callback, timeout, 0.);
 492             ev_timer_start(main_loop, timer_obj);
 493         }
 494     }
 495     return timer_obj;
 496 }
 497 
 498 ev_timer *stop_timer(ev_timer *timer_obj) {
 499     if (timer_obj) {
 500         ev_timer_stop(main_loop, timer_obj);
 501         free(timer_obj);
 502     }
 503     return NULL;
 504 }
 505 
 506 /*
 507  * Neccessary calls after ending input via enter or others
 508  *
 509  */
 510 static void finish_input(void) {
 511     password[input_position] = '\0';
 512     unlock_state = STATE_KEY_PRESSED;
 513     redraw_screen();
 514     input_done();
 515 }
 516 
 517 /*
 518  * Resets auth_state to STATE_AUTH_IDLE 2 seconds after an unsuccessful
 519  * authentication event.
 520  *
 521  */
 522 static void clear_auth_wrong(EV_P_ ev_timer *w, int revents) {
 523     DEBUG("clearing auth wrong\n");
 524     auth_state = STATE_AUTH_IDLE;
 525     redraw_screen();
 526 
 527     /* Clear modifier string. */
 528     if (modifier_string != NULL) {
 529         free(modifier_string);
 530         modifier_string = NULL;
 531     }
 532 
 533     /* Now free this timeout. */
 534     STOP_TIMER(clear_auth_wrong_timeout);
 535 
 536     /* retry with input done during auth verification */
 537     if (retry_verification) {
 538         retry_verification = false;
 539         finish_input();
 540     }
 541 }
 542 
 543 static void clear_indicator_cb(EV_P_ ev_timer *w, int revents) {
 544     clear_indicator();
 545     STOP_TIMER(clear_indicator_timeout);
 546 }
 547 
 548 static void clear_input(void) {
 549     input_position = 0;
 550     clear_password_memory();
 551     password[input_position] = '\0';
 552 }
 553 
 554 static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
 555     clear_input();
 556     STOP_TIMER(discard_passwd_timeout);
 557 }
 558 
 559 static void input_done(void) {
 560     STOP_TIMER(clear_auth_wrong_timeout);
 561     auth_state = STATE_AUTH_VERIFY;
 562     unlock_state = STATE_STARTED;
 563     redraw_screen();
 564 
 565     if (no_verify) {
 566         ev_break(EV_DEFAULT, EVBREAK_ALL);
 567         return;
 568     }
 569 
 570 #ifdef __OpenBSD__
 571     struct passwd *pw;
 572 
 573     if (!(pw = getpwuid(getuid())))
 574         errx(1, "unknown uid %u.", getuid());
 575 
 576     if (auth_userokay(pw->pw_name, NULL, NULL, password) != 0) {
 577         DEBUG("successfully authenticated\n");
 578         clear_password_memory();
 579 
 580         ev_break(EV_DEFAULT, EVBREAK_ALL);
 581         return;
 582     }
 583 #else
 584     if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
 585         DEBUG("successfully authenticated\n");
 586         clear_password_memory();
 587 
 588         /* PAM credentials should be refreshed, this will for example update any kerberos tickets.
 589          * Related to credentials pam_end() needs to be called to cleanup any temporary
 590          * credentials like kerberos /tmp/krb5cc_pam_* files which may of been left behind if the
 591          * refresh of the credentials failed. */
 592         pam_setcred(pam_handle, PAM_REFRESH_CRED);
 593         pam_cleanup = true;
 594 
 595         ev_break(EV_DEFAULT, EVBREAK_ALL);
 596         return;
 597     }
 598 #endif
 599 
 600     if (debug_mode)
 601         fprintf(stderr, "Authentication failure\n");
 602 
 603     /* Get state of Caps and Num lock modifiers, to be displayed in
 604      * STATE_AUTH_WRONG state */
 605     xkb_mod_index_t idx, num_mods;
 606     const char *mod_name;
 607 
 608     num_mods = xkb_keymap_num_mods(xkb_keymap);
 609 
 610     for (idx = 0; idx < num_mods; idx++) {
 611         if (!xkb_state_mod_index_is_active(xkb_state, idx, XKB_STATE_MODS_EFFECTIVE))
 612             continue;
 613 
 614         mod_name = xkb_keymap_mod_get_name(xkb_keymap, idx);
 615         if (mod_name == NULL)
 616             continue;
 617 
 618         /* Replace certain xkb names with nicer, human-readable ones. */
 619         if (strcmp(mod_name, XKB_MOD_NAME_CAPS) == 0)
 620             mod_name = "Caps Lock";
 621         else if (strcmp(mod_name, XKB_MOD_NAME_ALT) == 0)
 622             mod_name = "Alt";
 623         else if (strcmp(mod_name, XKB_MOD_NAME_NUM) == 0)
 624             mod_name = "Num Lock";
 625         else if (strcmp(mod_name, XKB_MOD_NAME_LOGO) == 0)
 626             mod_name = "Super";
 627 
 628         if (show_modkey_text) {
 629             char *tmp;
 630             if (modifier_string == NULL) {
 631                 if (asprintf(&tmp, "%s", mod_name) != -1)
 632                     modifier_string = tmp;
 633             } else if (asprintf(&tmp, "%s, %s", modifier_string, mod_name) != -1) {
 634                 free(modifier_string);
 635                 modifier_string = tmp;
 636             }
 637         }
 638     }
 639 
 640     auth_state = STATE_AUTH_WRONG;
 641     failed_attempts += 1;
 642     clear_input();
 643     if (unlock_indicator)
 644         redraw_screen();
 645 
 646     /* Clear this state after 2 seconds (unless the user enters another
 647      * password during that time). */
 648     ev_now_update(main_loop);
 649     START_TIMER(clear_auth_wrong_timeout, TSTAMP_N_SECS(2), clear_auth_wrong);
 650 
 651     /* Cancel the clear_indicator_timeout, it would hide the unlock indicator
 652      * too early. */
 653     STOP_TIMER(clear_indicator_timeout);
 654 
 655     /* beep on authentication failure, if enabled */
 656     if (beep) {
 657         xcb_bell(conn, 100);
 658         xcb_flush(conn);
 659     }
 660 }
 661 
 662 static void redraw_timeout(EV_P_ ev_timer *w, int revents) {
 663     redraw_screen();
 664     STOP_TIMER(w);
 665 }
 666 
 667 static bool skip_without_validation(void) {
 668     if (input_position != 0)
 669         return false;
 670 
 671     if (skip_repeated_empty_password || ignore_empty_password)
 672         return true;
 673 
 674     return false;
 675 }
 676 
 677 /*
 678  * Handle key presses. Fixes state, then looks up the key symbol for the
 679  * given keycode, then looks up the key symbol (as UCS-2), converts it to
 680  * UTF-8 and stores it in the password array.
 681  *
 682  */
 683 static void handle_key_press(xcb_key_press_event_t *event) {
 684     xkb_keysym_t ksym;
 685     char buffer[128];
 686     int n;
 687     bool ctrl;
 688 #if XKBCOMPOSE == 1
 689     bool composed = false;
 690 #endif
 691 
 692     ksym = xkb_state_key_get_one_sym(xkb_state, event->detail);
 693     ctrl = xkb_state_mod_name_is_active(xkb_state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED);
 694 
 695     /* The buffer will be null-terminated, so n >= 2 for 1 actual character. */
 696     memset(buffer, '\0', sizeof(buffer));
 697 
 698 #if XKBCOMPOSE == 1
 699     if (xkb_compose_state && xkb_compose_state_feed(xkb_compose_state, ksym) == XKB_COMPOSE_FEED_ACCEPTED) {
 700         switch (xkb_compose_state_get_status(xkb_compose_state)) {
 701             case XKB_COMPOSE_NOTHING:
 702                 break;
 703             case XKB_COMPOSE_COMPOSING:
 704                 return;
 705             case XKB_COMPOSE_COMPOSED:
 706                 /* xkb_compose_state_get_utf8 doesn't include the terminating byte in the return value
 707              * as xkb_keysym_to_utf8 does. Adding one makes the variable n consistent. */
 708                 n = xkb_compose_state_get_utf8(xkb_compose_state, buffer, sizeof(buffer)) + 1;
 709                 ksym = xkb_compose_state_get_one_sym(xkb_compose_state);
 710                 composed = true;
 711                 break;
 712             case XKB_COMPOSE_CANCELLED:
 713                 xkb_compose_state_reset(xkb_compose_state);
 714                 return;
 715         }
 716     }
 717 
 718     if (!composed) {
 719         n = xkb_keysym_to_utf8(ksym, buffer, sizeof(buffer));
 720     }
 721 #else
 722     n = xkb_keysym_to_utf8(ksym, buffer, sizeof(buffer));
 723 #endif
 724 
 725     //custom key commands
 726     if (hotkeys) {
 727         switch(ksym) {
 728             case XKB_KEY_XF86MonBrightnessUp:
 729                 if (cmd_brightness_up) {
 730                     system(cmd_brightness_up);
 731                     return;
 732                 }
 733                 break;
 734             case XKB_KEY_XF86MonBrightnessDown:
 735                 if (cmd_brightness_down) {
 736                     system(cmd_brightness_down);
 737                     return;
 738                 }
 739                 break;
 740             case XKB_KEY_XF86AudioPlay:
 741                 if (cmd_media_play) {
 742                     system(cmd_media_play);
 743                     return;
 744                 }
 745                 break;
 746             case XKB_KEY_XF86AudioPause:
 747                 if (cmd_media_pause) {
 748                     system(cmd_media_pause);
 749                     return;
 750                 }
 751                 break;
 752             case XKB_KEY_XF86AudioStop:
 753                 if (cmd_media_stop) {
 754                     system(cmd_media_stop);
 755                     return;
 756                 }
 757                 break;
 758             case XKB_KEY_XF86AudioPrev:
 759                 if (cmd_media_prev) {
 760                     system(cmd_media_prev);
 761                     return;
 762                 }
 763                 break;
 764             case XKB_KEY_XF86AudioNext:
 765                 if (cmd_media_next) {
 766                     system(cmd_media_next);
 767                     return;
 768                 }
 769                 break;
 770             case XKB_KEY_XF86AudioMute:
 771                 if (cmd_audio_mute) {
 772                     system(cmd_audio_mute);
 773                     return;
 774                 }
 775                 break;
 776             case XKB_KEY_XF86AudioLowerVolume:
 777                 if (cmd_volume_down) {
 778                     system(cmd_volume_down);
 779                     return;
 780                 }
 781                 break;
 782             case XKB_KEY_XF86AudioRaiseVolume:
 783                 if (cmd_volume_up) {
 784                     system(cmd_volume_up);
 785                     return;
 786                 }
 787                 break;
 788             case XKB_KEY_XF86AudioMicMute:
 789                 if (cmd_mic_mute) {
 790                     system(cmd_mic_mute);
 791                     return;
 792                 }
 793                 break;
 794             case XKB_KEY_XF86PowerDown:
 795                 if (cmd_power_down) {
 796                     system(cmd_power_down);
 797                     return;
 798                 }
 799                 break;
 800             case XKB_KEY_XF86PowerOff:
 801                 if (cmd_power_off) {
 802                     system(cmd_power_off);
 803                     return;
 804                 }
 805                 break;
 806             case XKB_KEY_XF86Sleep:
 807                 if (cmd_power_sleep) {
 808                     system(cmd_power_sleep);
 809                     return;
 810                 }
 811                 break;
 812         }
 813     }
 814 
 815     // media keys
 816     if (pass_media_keys) {
 817         switch(ksym) {
 818             case XKB_KEY_XF86AudioPlay:
 819             case XKB_KEY_XF86AudioPause:
 820             case XKB_KEY_XF86AudioStop:
 821             case XKB_KEY_XF86AudioPrev:
 822             case XKB_KEY_XF86AudioNext:
 823             case XKB_KEY_XF86AudioMute:
 824             case XKB_KEY_XF86AudioLowerVolume:
 825             case XKB_KEY_XF86AudioRaiseVolume:
 826             case XKB_KEY_XF86AudioMicMute:
 827                 xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
 828                 return;
 829         }
 830     }
 831 
 832     // screen keys
 833     if (pass_screen_keys) {
 834         switch(ksym) {
 835             case XKB_KEY_XF86MonBrightnessUp:
 836             case XKB_KEY_XF86MonBrightnessDown:
 837                 xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
 838                 return;
 839         }
 840     }
 841 
 842     // power keys
 843     if (pass_power_keys) {
 844         switch(ksym) {
 845             case XKB_KEY_XF86PowerDown:
 846             case XKB_KEY_XF86PowerOff:
 847             case XKB_KEY_XF86Sleep:
 848                 xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
 849                 return;
 850         }
 851     }
 852 
 853     // volume keys
 854     if (pass_volume_keys) {
 855         switch(ksym) {
 856             case XKB_KEY_XF86AudioMute:
 857             case XKB_KEY_XF86AudioLowerVolume:
 858             case XKB_KEY_XF86AudioRaiseVolume:
 859                 xcb_send_event(conn, true, screen->root, XCB_EVENT_MASK_BUTTON_PRESS, (char *)event);
 860                 return;
 861         }
 862     }
 863 
 864     // return/enter/etc
 865     switch (ksym) {
 866         case XKB_KEY_j:
 867         case XKB_KEY_m:
 868         case XKB_KEY_Return:
 869         case XKB_KEY_KP_Enter:
 870         case XKB_KEY_XF86ScreenSaver:
 871             if ((ksym == XKB_KEY_j || ksym == XKB_KEY_m) && !ctrl)
 872                 break;
 873 
 874             if (auth_state == STATE_AUTH_WRONG) {
 875                 retry_verification = true;
 876                 return;
 877             }
 878 
 879             if (skip_without_validation()) {
 880                 clear_input();
 881                 return;
 882             }
 883             finish_input();
 884             skip_repeated_empty_password = true;
 885             return;
 886         default:
 887             skip_repeated_empty_password = false;
 888             // A new password is being entered, but a previous one is pending.
 889             // Discard the old one and clear the retry_verification flag.
 890             if (retry_verification) {
 891                 retry_verification = false;
 892                 clear_input();
 893             }
 894     }
 895 
 896     // backspace, esc, delete, etc
 897     switch (ksym) {
 898         case XKB_KEY_u:
 899         case XKB_KEY_Escape:
 900             if ((ksym == XKB_KEY_u && ctrl) ||
 901                 ksym == XKB_KEY_Escape) {
 902                 DEBUG("C-u pressed\n");
 903                 clear_input();
 904                 /* Also hide the unlock indicator */
 905                 if (unlock_indicator)
 906                     clear_indicator();
 907                 return;
 908             }
 909             break;
 910 
 911         case XKB_KEY_Delete:
 912         case XKB_KEY_KP_Delete:
 913             /* Deleting forward doesn’t make sense, as i3lock doesn’t allow you
 914              * to move the cursor when entering a password. We need to eat this
 915              * key press so that it won’t be treated as part of the password,
 916              * see issue #50. */
 917             return;
 918 
 919         case XKB_KEY_h:
 920         case XKB_KEY_BackSpace:
 921             if (ksym == XKB_KEY_h && !ctrl)
 922                 break;
 923 
 924             if (input_position == 0) {
 925                 START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
 926                 unlock_state = STATE_NOTHING_TO_DELETE;
 927                 redraw_screen();
 928                 return;
 929             }
 930 
 931             /* decrement input_position to point to the previous glyph */
 932             u8_dec(password, &input_position);
 933             password[input_position] = '\0';
 934 
 935             /* Hide the unlock indicator after a bit if the password buffer is
 936              * empty. */
 937             START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
 938             unlock_state = STATE_BACKSPACE_ACTIVE;
 939             redraw_screen();
 940             unlock_state = STATE_KEY_PRESSED;
 941             return;
 942     }
 943 
 944     if ((input_position + 8) >= (int)sizeof(password))
 945         return;
 946 
 947 #if 0
 948     /* FIXME: handle all of these? */
 949     printf("is_keypad_key = %d\n", xcb_is_keypad_key(sym));
 950     printf("is_private_keypad_key = %d\n", xcb_is_private_keypad_key(sym));
 951     printf("xcb_is_cursor_key = %d\n", xcb_is_cursor_key(sym));
 952     printf("xcb_is_pf_key = %d\n", xcb_is_pf_key(sym));
 953     printf("xcb_is_function_key = %d\n", xcb_is_function_key(sym));
 954     printf("xcb_is_misc_function_key = %d\n", xcb_is_misc_function_key(sym));
 955     printf("xcb_is_modifier_key = %d\n", xcb_is_modifier_key(sym));
 956 #endif
 957 
 958     if (n < 2)
 959         return;
 960 
 961     /* store it in the password array as UTF-8 */
 962     memcpy(password + input_position, buffer, n - 1);
 963     input_position += n - 1;
 964     DEBUG("current password = %.*s\n", input_position, password);
 965 
 966     if (unlock_indicator) {
 967         unlock_state = STATE_KEY_ACTIVE;
 968         redraw_screen();
 969         unlock_state = STATE_KEY_PRESSED;
 970 
 971         struct ev_timer *timeout = NULL;
 972         START_TIMER(timeout, TSTAMP_N_SECS(0.25), redraw_timeout);
 973         STOP_TIMER(clear_indicator_timeout);
 974     }
 975 
 976     START_TIMER(discard_passwd_timeout, TSTAMP_N_MINS(3), discard_passwd_cb);
 977 }
 978 
 979 /*
 980  * A visibility notify event will be received when the visibility (= can the
 981  * user view the complete window) changes, so for example when a popup overlays
 982  * some area of the i3lock window.
 983  *
 984  * In this case, we raise our window on top so that the popup (or whatever is
 985  * hiding us) gets hidden.
 986  *
 987  */
 988 static void handle_visibility_notify(xcb_connection_t *conn,
 989                                      xcb_visibility_notify_event_t *event) {
 990     if (event->state != XCB_VISIBILITY_UNOBSCURED) {
 991         uint32_t values[] = {XCB_STACK_MODE_ABOVE};
 992         xcb_configure_window(conn, event->window, XCB_CONFIG_WINDOW_STACK_MODE, values);
 993         xcb_flush(conn);
 994     }
 995 }
 996 
 997 /*
 998  * Called when the keyboard mapping changes. We update our symbols.
 999  *
1000  * We ignore errors — if the new keymap cannot be loaded it’s better if the
1001  * screen stays locked and the user intervenes by using killall i3lock.
1002  *
1003  */
1004 static void process_xkb_event(xcb_generic_event_t *gevent) {
1005     union xkb_event {
1006         struct {
1007             uint8_t response_type;
1008             uint8_t xkbType;
1009             uint16_t sequence;
1010             xcb_timestamp_t time;
1011             uint8_t deviceID;
1012         } any;
1013         xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
1014         xcb_xkb_map_notify_event_t map_notify;
1015         xcb_xkb_state_notify_event_t state_notify;
1016     } *event = (union xkb_event *)gevent;
1017 
1018     DEBUG("process_xkb_event for device %d\n", event->any.deviceID);
1019 
1020     if (event->any.deviceID != xkb_x11_get_core_keyboard_device_id(conn))
1021         return;
1022 
1023     /*
1024      * XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap
1025      * updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent
1026      * recompilations.
1027      */
1028     switch (event->any.xkbType) {
1029         case XCB_XKB_NEW_KEYBOARD_NOTIFY:
1030             if (event->new_keyboard_notify.changed & XCB_XKB_NKN_DETAIL_KEYCODES)
1031                 (void)load_keymap();
1032             break;
1033 
1034         case XCB_XKB_MAP_NOTIFY:
1035             (void)load_keymap();
1036             break;
1037 
1038         case XCB_XKB_STATE_NOTIFY:
1039             xkb_state_update_mask(xkb_state,
1040                                   event->state_notify.baseMods,
1041                                   event->state_notify.latchedMods,
1042                                   event->state_notify.lockedMods,
1043                                   event->state_notify.baseGroup,
1044                                   event->state_notify.latchedGroup,
1045                                   event->state_notify.lockedGroup);
1046               if (layout_text != NULL) {
1047                   free(layout_text);
1048                   layout_text = NULL;
1049             }
1050             layout_text = get_keylayoutname(keylayout_mode, conn);
1051             redraw_screen();
1052             break;
1053     }
1054 }
1055 
1056 /*
1057  * Called when the properties on the root window change, e.g. when the screen
1058  * resolution changes. If so we update the window to cover the whole screen
1059  * and also redraw the image, if any.
1060  *
1061  */
1062 static void handle_screen_resize(void) {
1063     xcb_get_geometry_cookie_t geomc;
1064     xcb_get_geometry_reply_t *geom;
1065     geomc = xcb_get_geometry(conn, screen->root);
1066     if ((geom = xcb_get_geometry_reply(conn, geomc, 0)) == NULL)
1067         return;
1068 
1069     if (last_resolution[0] == geom->width &&
1070         last_resolution[1] == geom->height) {
1071         free(geom);
1072         return;
1073     }
1074 
1075     last_resolution[0] = geom->width;
1076     last_resolution[1] = geom->height;
1077 
1078     free(geom);
1079 
1080     redraw_screen();
1081 
1082     uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
1083     xcb_configure_window(conn, win, mask, last_resolution);
1084     xcb_flush(conn);
1085 
1086     randr_query(screen->root);
1087     redraw_screen();
1088 }
1089 
1090 static ssize_t read_raw_image_native(uint32_t *dest, FILE *src, size_t width, size_t height, int pixstride) {
1091     ssize_t count = 0;
1092     for (size_t y = 0; y < height; y++) {
1093         size_t n = fread(&dest[y * pixstride], 1, width * 4, src);
1094         count += n;
1095         if (n < (size_t)(width * 4))
1096             break;
1097     }
1098 
1099     return count;
1100 }
1101 
1102 struct raw_pixel_format {
1103     int bpp;
1104     int red;
1105     int green;
1106     int blue;
1107 };
1108 
1109 static ssize_t read_raw_image_fmt(uint32_t *dest, FILE *src, size_t width, size_t height, int pixstride,
1110                                   struct raw_pixel_format fmt) {
1111     unsigned char *buf = malloc(width * fmt.bpp);
1112     if (buf == NULL)
1113         return -1;
1114 
1115     ssize_t count = 0;
1116     for (size_t y = 0; y < height; y++) {
1117         size_t n = fread(buf, 1, width * fmt.bpp, src);
1118         count += n;
1119         if (n < (size_t)(width * fmt.bpp))
1120             break;
1121 
1122         for (size_t x = 0; x < width; ++x) {
1123             int idx = x * fmt.bpp;
1124             dest[y * pixstride + x] = 0 |
1125                                       (buf[idx + fmt.red]) << 16 |
1126                                       (buf[idx + fmt.green]) << 8 |
1127                                       (buf[idx + fmt.blue]);
1128         }
1129     }
1130 
1131     free(buf);
1132     return count;
1133 }
1134 
1135 // Pre-defind pixel formats (<bytes per pixel>, <red pixel>, <green pixel>, <blue pixel>)
1136 static const struct raw_pixel_format raw_fmt_rgb = {3, 0, 1, 2};
1137 static const struct raw_pixel_format raw_fmt_rgbx = {4, 0, 1, 2};
1138 static const struct raw_pixel_format raw_fmt_xrgb = {4, 1, 2, 3};
1139 static const struct raw_pixel_format raw_fmt_bgr = {3, 2, 1, 0};
1140 static const struct raw_pixel_format raw_fmt_bgrx = {4, 2, 1, 0};
1141 static const struct raw_pixel_format raw_fmt_xbgr = {4, 3, 2, 1};
1142 
1143 static cairo_surface_t *read_raw_image(const char *image_path, const char *image_raw_format) {
1144     cairo_surface_t *img;
1145 
1146 #define RAW_PIXFMT_MAXLEN 6
1147 #define STRINGIFY1(x) #x
1148 #define STRINGIFY(x) STRINGIFY1(x)
1149     /* Parse format as <width>x<height>:<pixfmt> */
1150     char pixfmt[RAW_PIXFMT_MAXLEN + 1];
1151     size_t w, h;
1152     const char *fmt = "%zux%zu:%" STRINGIFY(RAW_PIXFMT_MAXLEN) "s";
1153     if (sscanf(image_raw_format, fmt, &w, &h, pixfmt) != 3) {
1154         fprintf(stderr, "Invalid image format: \"%s\"\n", image_raw_format);
1155         return NULL;
1156     }
1157 #undef RAW_PIXFMT_MAXLEN
1158 #undef STRINGIFY1
1159 #undef STRINGIFY
1160 
1161     /* Create image surface */
1162     img = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
1163     if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
1164         fprintf(stderr, "Could not create surface: %s\n",
1165                 cairo_status_to_string(cairo_surface_status(img)));
1166         return NULL;
1167     }
1168     cairo_surface_flush(img);
1169 
1170     /* Use uint32_t* because cairo uses native endianness */
1171     uint32_t *data = (uint32_t *)cairo_image_surface_get_data(img);
1172     const int pixstride = cairo_image_surface_get_stride(img) / 4;
1173 
1174     FILE *f = fopen(image_path, "r");
1175     if (f == NULL) {
1176         fprintf(stderr, "Could not open image \"%s\": %s\n",
1177                 image_path, strerror(errno));
1178         cairo_surface_destroy(img);
1179         return NULL;
1180     }
1181 
1182     /* Read the image, respecting cairo's stride, according to the pixfmt */
1183     ssize_t size, count;
1184     if (strcmp(pixfmt, "native") == 0) {
1185         /* If the pixfmt is 'native', just read each line directly into the buffer */
1186         size = w * h * 4;
1187         count = read_raw_image_native(data, f, w, h, pixstride);
1188     } else {
1189         const struct raw_pixel_format *fmt = NULL;
1190 
1191         if (strcmp(pixfmt, "rgb") == 0)
1192             fmt = &raw_fmt_rgb;
1193         else if (strcmp(pixfmt, "rgbx") == 0)
1194             fmt = &raw_fmt_rgbx;
1195         else if (strcmp(pixfmt, "xrgb") == 0)
1196             fmt = &raw_fmt_xrgb;
1197         else if (strcmp(pixfmt, "bgr") == 0)
1198             fmt = &raw_fmt_bgr;
1199         else if (strcmp(pixfmt, "bgrx") == 0)
1200             fmt = &raw_fmt_bgrx;
1201         else if (strcmp(pixfmt, "xbgr") == 0)
1202             fmt = &raw_fmt_xbgr;
1203 
1204         if (fmt == NULL) {
1205             fprintf(stderr, "Unknown raw pixel format: %s\n", pixfmt);
1206             fclose(f);
1207             cairo_surface_destroy(img);
1208             return NULL;
1209         }
1210 
1211         size = w * h * fmt->bpp;
1212         count = read_raw_image_fmt(data, f, w, h, pixstride, *fmt);
1213     }
1214 
1215     cairo_surface_mark_dirty(img);
1216 
1217     if (count < size) {
1218         if (count < 0 || ferror(f)) {
1219             fprintf(stderr, "Failed to read image \"%s\": %s\n",
1220                     image_path, strerror(errno));
1221             fclose(f);
1222             cairo_surface_destroy(img);
1223             return NULL;
1224         } else {
1225             /* Print a warning if the file contains less data than expected,
1226              * but don't abort. It's useful to see how the image looks even if it's wrong. */
1227             fprintf(stderr, "Warning: expected to read %zi bytes from \"%s\", read %zi\n",
1228                     size, image_path, count);
1229         }
1230     }
1231 
1232     fclose(f);
1233     return img;
1234 }
1235 
1236 static bool verify_png_image(const char *image_path) {
1237     if (!image_path) {
1238         return false;
1239     }
1240 
1241     /* Check file exists and has correct PNG header */
1242     FILE *png_file = fopen(image_path, "r");
1243     if (png_file == NULL) {
1244         DEBUG("Image file path \"%s\" cannot be opened: %s\n", image_path, strerror(errno));
1245         return false;
1246     }
1247     unsigned char png_header[8];
1248     memset(png_header, '\0', sizeof(png_header));
1249     int bytes_read = fread(png_header, 1, sizeof(png_header), png_file);
1250     fclose(png_file);
1251     if (bytes_read != sizeof(png_header)) {
1252         DEBUG("Could not read PNG header from \"%s\"\n", image_path);
1253         return false;
1254     }
1255 
1256     // Check PNG header according to the specification, available at:
1257     // https://www.w3.org/TR/2003/REC-PNG-20031110/#5PNG-file-signature
1258     static unsigned char PNG_REFERENCE_HEADER[8] = {137, 80, 78, 71, 13, 10, 26, 10};
1259     if (memcmp(PNG_REFERENCE_HEADER, png_header, sizeof(png_header)) != 0) {
1260         DEBUG("File \"%s\" does not start with a PNG header. i3lock currently only supports loading PNG files.\n", image_path);
1261         return false;
1262     }
1263     return true;
1264 }
1265 
1266 #ifndef __OpenBSD__
1267 /*
1268  * Callback function for PAM. We only react on password request callbacks.
1269  *
1270  */
1271 static int conv_callback(int num_msg, const struct pam_message **msg,
1272                          struct pam_response **resp, void *appdata_ptr) {
1273     if (num_msg == 0)
1274         return 1;
1275 
1276     /* PAM expects an array of responses, one for each message */
1277     if ((*resp = calloc(num_msg, sizeof(struct pam_response))) == NULL) {
1278         perror("calloc");
1279         return 1;
1280     }
1281 
1282     for (int c = 0; c < num_msg; c++) {
1283         if (msg[c]->msg_style != PAM_PROMPT_ECHO_OFF &&
1284             msg[c]->msg_style != PAM_PROMPT_ECHO_ON)
1285             continue;
1286 
1287         /* return code is currently not used but should be set to zero */
1288         resp[c]->resp_retcode = 0;
1289         if ((resp[c]->resp = strdup(password)) == NULL) {
1290             perror("strdup");
1291             return 1;
1292         }
1293     }
1294 
1295     return 0;
1296 }
1297 #endif
1298 
1299 /*
1300  * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb.
1301  * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop
1302  *
1303  */
1304 static void xcb_got_event(EV_P_ struct ev_io *w, int revents) {
1305     /* empty, because xcb_prepare_cb and xcb_check_cb are used */
1306 }
1307 
1308 /*
1309  * Flush before blocking (and waiting for new events)
1310  *
1311  */
1312 static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
1313     xcb_flush(conn);
1314 }
1315 
1316 /*
1317  * Try closing logind sleep lock fd passed over from xss-lock, in case we're
1318  * being run from there.
1319  *
1320  */
1321 static void maybe_close_sleep_lock_fd(void) {
1322     const char *sleep_lock_fd = getenv("XSS_SLEEP_LOCK_FD");
1323     char *endptr;
1324     if (sleep_lock_fd && *sleep_lock_fd != 0) {
1325         long int fd = strtol(sleep_lock_fd, &endptr, 10);
1326         if (*endptr == 0) {
1327             close(fd);
1328         }
1329     }
1330 }
1331 
1332 /*
1333  * Instead of polling the X connection socket we leave this to
1334  * xcb_poll_for_event() which knows better than we can ever know.
1335  *
1336  */
1337 static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
1338     xcb_generic_event_t *event;
1339 
1340     if (xcb_connection_has_error(conn))
1341         errx(EXIT_FAILURE, "X11 connection broke, did your server terminate?");
1342 
1343     while ((event = xcb_poll_for_event(conn)) != NULL) {
1344         if (event->response_type == 0) {
1345             xcb_generic_error_t *error = (xcb_generic_error_t *)event;
1346             if (debug_mode)
1347                 fprintf(stderr, "X11 Error received! sequence 0x%x, error_code = %d\n",
1348                         error->sequence, error->error_code);
1349             free(event);
1350             continue;
1351         }
1352 
1353         /* Strip off the highest bit (set if the event is generated) */
1354         int type = (event->response_type & 0x7F);
1355 
1356         switch (type) {
1357             case XCB_KEY_PRESS:
1358                 handle_key_press((xcb_key_press_event_t *)event);
1359                 break;
1360 
1361             case XCB_VISIBILITY_NOTIFY:
1362                 handle_visibility_notify(conn, (xcb_visibility_notify_event_t *)event);
1363                 break;
1364 
1365             case XCB_MAP_NOTIFY:
1366                 maybe_close_sleep_lock_fd();
1367                 if (!dont_fork) {
1368                     /* After the first MapNotify, we never fork again. We don’t
1369                      * expect to get another MapNotify, but better be sure… */
1370                     dont_fork = true;
1371 
1372                     /* In the parent process, we exit */
1373                     if (fork() != 0)
1374                         exit(EXIT_SUCCESS);
1375 
1376                     ev_loop_fork(EV_DEFAULT);
1377                 }
1378                 break;
1379 
1380             case XCB_CONFIGURE_NOTIFY:
1381                 handle_screen_resize();
1382                 break;
1383 
1384             default:
1385                 if (type == xkb_base_event) {
1386                     process_xkb_event(event);
1387                 }
1388                 if (randr_base > -1 &&
1389                     type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
1390                     randr_query(screen->root);
1391                     handle_screen_resize();
1392                 }
1393         }
1394 
1395         free(event);
1396     }
1397 }
1398 
1399 /*
1400  * This function is called from a fork()ed child and will raise the i3lock
1401  * window when the window is obscured, even when the main i3lock process is
1402  * blocked due to the authentication backend.
1403  *
1404  */
1405 static void raise_loop(xcb_window_t window) {
1406     xcb_connection_t *conn;
1407     xcb_generic_event_t *event;
1408     int screens;
1409 
1410     if (xcb_connection_has_error((conn = xcb_connect(NULL, &screens))) > 0)
1411         errx(EXIT_FAILURE, "Cannot open display");
1412 
1413     /* We need to know about the window being obscured or getting destroyed. */
1414     xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK,
1415                                  (uint32_t[]){
1416                                      XCB_EVENT_MASK_VISIBILITY_CHANGE |
1417                                      XCB_EVENT_MASK_STRUCTURE_NOTIFY});
1418     xcb_flush(conn);
1419 
1420     DEBUG("Watching window 0x%08x\n", window);
1421     while ((event = xcb_wait_for_event(conn)) != NULL) {
1422         if (event->response_type == 0) {
1423             xcb_generic_error_t *error = (xcb_generic_error_t *)event;
1424             DEBUG("X11 Error received! sequence 0x%x, error_code = %d\n",
1425                   error->sequence, error->error_code);
1426             free(event);
1427             continue;
1428         }
1429         /* Strip off the highest bit (set if the event is generated) */
1430         int type = (event->response_type & 0x7F);
1431         DEBUG("Read event of type %d\n", type);
1432         switch (type) {
1433             case XCB_VISIBILITY_NOTIFY:
1434                 handle_visibility_notify(conn, (xcb_visibility_notify_event_t *)event);
1435                 break;
1436             case XCB_UNMAP_NOTIFY:
1437                 DEBUG("UnmapNotify for 0x%08x\n", (((xcb_unmap_notify_event_t *)event)->window));
1438                 if (((xcb_unmap_notify_event_t *)event)->window == window)
1439                     exit(EXIT_SUCCESS);
1440                 break;
1441             case XCB_DESTROY_NOTIFY:
1442                 DEBUG("DestroyNotify for 0x%08x\n", (((xcb_destroy_notify_event_t *)event)->window));
1443                 if (((xcb_destroy_notify_event_t *)event)->window == window)
1444                     exit(EXIT_SUCCESS);
1445                 break;
1446             default:
1447                 DEBUG("Unhandled event type %d\n", type);
1448                 break;
1449         }
1450         free(event);
1451     }
1452 }
1453 
1454 /*
1455  * Loads an image from the given path. Handles JPEG and PNG. Returns NULL in case of error.
1456  */
1457 cairo_surface_t* load_image(char* image_path) {
1458     cairo_surface_t *img = NULL;
1459     JPEG_INFO jpg_info;
1460 
1461     if (image_raw_format != NULL && image_path != NULL) {
1462         /* Read image. 'read_raw_image' returns NULL on error,
1463          * so we don't have to handle errors here. */
1464         img = read_raw_image(image_path, image_raw_format);
1465     } else if (verify_png_image(image_path)) {
1466         /* Create a pixmap to render on, fill it with the background color */
1467         img = cairo_image_surface_create_from_png(image_path);
1468     } else if (file_is_jpg(image_path)) {
1469         DEBUG("Image looks like a jpeg, decoding\n");
1470         unsigned char* jpg_data = read_JPEG_file(image_path, &jpg_info);
1471             if (jpg_data != NULL) {
1472                 img = cairo_image_surface_create_for_data(jpg_data,
1473                         CAIRO_FORMAT_ARGB32, jpg_info.width, jpg_info.height,
1474                         jpg_info.stride);
1475             }
1476     }
1477 
1478     /* In case loading failed, we just pretend no -i was specified. */
1479     if (img && cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
1480         fprintf(stderr, "Could not load image \"%s\": %s\n",
1481                 image_path, cairo_status_to_string(cairo_surface_status(img)));
1482         img = NULL;
1483     }
1484 
1485     return img;
1486 }
1487 
1488 /*
1489  * Reads the provided directory and stores the images path in the pointer array
1490  * img_slideshow
1491  */
1492 bool load_slideshow_images(const char *path) {
1493     slideshow_enabled = true;
1494     DIR *d;
1495     struct dirent *dir;
1496     int file_count = 0;
1497     slideshow_image_count = 0;
1498 
1499     DEBUG("Loading slideshow images at \"%s\"\n", path);
1500 
1501     d = opendir(path);
1502     if (d == NULL) {
1503         printf("Could not open directory: %s\n", path);
1504         return false;
1505     }
1506 
1507     regex_t reg;
1508 
1509     if (regcomp(&reg, ".*\\.(jpe?g|png)", REG_EXTENDED)) {
1510         printf("Could not compile regex\n");
1511         return false;
1512     }
1513 
1514     while ((dir = readdir(d)) != NULL) {
1515         if (file_count >= 256) break;
1516         int result = regexec(&reg, dir->d_name, 0, NULL, 0);
1517         if (result) continue;
1518 
1519         char path_to_image[256];
1520         strcpy(path_to_image, path);
1521         strcat(path_to_image, "/");
1522         strcat(path_to_image, dir->d_name);
1523 
1524         img_slideshow[file_count] = strdup(path_to_image);
1525 
1526         if (img_slideshow[file_count] != NULL) {
1527             ++file_count;
1528         }
1529     }
1530 
1531     slideshow_image_count = file_count;
1532     regfree(&reg);
1533     closedir(d);
1534     return true;
1535 }
1536 
1537 int main(int argc, char *argv[]) {
1538     struct passwd *pw;
1539     char *username;
1540 #ifndef __OpenBSD__
1541     int ret;
1542     struct pam_conv conv = {conv_callback, NULL};
1543 #endif
1544     int curs_choice = CURS_NONE;
1545     int o;
1546     int longoptind = 0;
1547     struct option longopts[] = {
1548         {"version", no_argument, NULL, 'v'},
1549         {"nofork", no_argument, NULL, 'n'},
1550         {"beep", no_argument, NULL, 'b'},
1551         {"dpms", no_argument, NULL, 'd'},
1552         {"color", required_argument, NULL, 'c'},
1553         {"pointer", required_argument, NULL, 'p'},
1554         {"debug", no_argument, NULL, 999},
1555         {"help", no_argument, NULL, 'h'},
1556         {"no-unlock-indicator", no_argument, NULL, 'u'},
1557         {"image", required_argument, NULL, 'i'},
1558         {"raw", required_argument, NULL, 998},
1559         {"tiling", no_argument, NULL, 't'},
1560         {"centered", no_argument, NULL, 'C'},
1561         {"fill", no_argument, NULL, 'F'},
1562         {"scale", no_argument, NULL, 'L'},
1563         {"max", no_argument, NULL, 'M'},
1564         {"ignore-empty-password", no_argument, NULL, 'e'},
1565         {"inactivity-timeout", required_argument, NULL, 'I'},
1566         {"show-failed-attempts", no_argument, NULL, 'f'},
1567         {"screen", required_argument, NULL, 'S'},
1568         {"blur", required_argument, NULL, 'B'},
1569 
1570         // options for unlock indicator colors
1571         {"insidever-color", required_argument, NULL, 300},
1572         {"insidewrong-color", required_argument, NULL, 301},
1573         {"inside-color", required_argument, NULL, 302},
1574         {"ringver-color", required_argument, NULL, 303},
1575         {"ringwrong-color", required_argument, NULL, 304},
1576         {"ring-color", required_argument, NULL, 305},
1577         {"line-color", required_argument, NULL, 306},
1578         {"verif-color", required_argument, NULL, 307},
1579         {"wrong-color", required_argument, NULL, 308},
1580         {"layout-color", required_argument, NULL, 309},
1581         {"time-color", required_argument, NULL, 310},
1582         {"date-color", required_argument, NULL, 311},
1583         {"modif-color", required_argument, NULL, 322},
1584         {"keyhl-color", required_argument, NULL, 312},
1585         {"bshl-color", required_argument, NULL, 313},
1586         {"separator-color", required_argument, NULL, 314},
1587         {"greeter-color", required_argument, NULL, 315},
1588 
1589         // text outline colors
1590         {"verifoutline-color", required_argument, NULL, 316},
1591         {"wrongoutline-color", required_argument, NULL, 317},
1592         {"layoutoutline-color", required_argument, NULL, 318},
1593         {"timeoutline-color", required_argument, NULL, 319},
1594         {"dateoutline-color", required_argument, NULL, 320},
1595         {"greeteroutline-color", required_argument, NULL, 321},
1596         {"modifoutline-color", required_argument, NULL, 323},
1597 
1598         {"line-uses-ring", no_argument, NULL, 'r'},
1599         {"line-uses-inside", no_argument, NULL, 's'},
1600 
1601         {"clock", no_argument, NULL, 'k'},
1602         {"force-clock", no_argument, NULL, 400},
1603         {"indicator", no_argument, NULL, 401},
1604         {"radius", required_argument, NULL, 402},
1605         {"ring-width", required_argument, NULL, 403},
1606 
1607         // alignment
1608         {"time-align", required_argument, NULL, 500},
1609         {"date-align", required_argument, NULL, 501},
1610         {"verif-align", required_argument, NULL, 502},
1611         {"wrong-align", required_argument, NULL, 503},
1612         {"layout-align", required_argument, NULL, 504},
1613         {"modif-align", required_argument, NULL, 505},
1614         {"greeter-align", required_argument, NULL, 506},
1615 
1616         // string stuff
1617         {"time-str", required_argument, NULL, 510},
1618         {"date-str", required_argument, NULL, 511},
1619         {"verif-text", required_argument, NULL, 512},
1620         {"wrong-text", required_argument, NULL, 513},
1621         {"keylayout", required_argument, NULL, 514},
1622         {"noinput-text", required_argument, NULL, 515},
1623         {"lock-text", required_argument, NULL, 516},
1624         {"lockfailed-text", required_argument, NULL, 517},
1625         {"greeter-text", required_argument, NULL, 518},
1626         {"no-modkey-text", no_argument, NULL, 519},
1627 
1628         // fonts
1629         {"time-font", required_argument, NULL, 520},
1630         {"date-font", required_argument, NULL, 521},
1631         {"verif-font", required_argument, NULL, 522},
1632         {"wrong-font", required_argument, NULL, 523},
1633         {"layout-font", required_argument, NULL, 524},
1634         {"greeter-font", required_argument, NULL, 525},
1635 
1636         // text size
1637         {"time-size", required_argument, NULL, 530},
1638         {"date-size", required_argument, NULL, 531},
1639         {"verif-size", required_argument, NULL, 532},
1640         {"wrong-size", required_argument, NULL, 533},
1641         {"layout-size", required_argument, NULL, 534},
1642         {"modif-size", required_argument, NULL, 535},
1643         {"greeter-size", required_argument, NULL, 536},
1644 
1645         // text/indicator positioning
1646         {"time-pos", required_argument, NULL, 540},
1647         {"date-pos", required_argument, NULL, 541},
1648         {"verif-pos", required_argument, NULL, 542},
1649         {"wrong-pos", required_argument, NULL, 543},
1650         {"layout-pos", required_argument, NULL, 544},
1651         {"status-pos", required_argument, NULL, 545},
1652         {"modif-pos", required_argument, NULL, 546},
1653         {"ind-pos", required_argument, NULL, 547},
1654         {"greeter-pos", required_argument, NULL, 548},
1655 
1656         // text outline width
1657         {"timeoutline-width", required_argument, NULL, 560},
1658         {"dateoutline-width", required_argument, NULL, 561},
1659         {"verifoutline-width", required_argument, NULL, 562},
1660         {"wrongoutline-width", required_argument, NULL, 563},
1661         {"modifieroutline-width", required_argument, NULL, 564},
1662         {"layoutoutline-width", required_argument, NULL, 565},
1663         {"greeteroutline-width", required_argument, NULL, 566},
1664 
1665         // pass keys
1666         {"pass-media-keys", no_argument, NULL, 601},
1667         {"pass-screen-keys", no_argument, NULL, 602},
1668         {"pass-power-keys", no_argument, NULL, 603},
1669         {"pass-volume-keys", no_argument, NULL, 604},
1670 
1671         // custom commands for pass keys
1672         {"custom-key-commands", no_argument, NULL, 610},
1673         {"cmd-brightness-up", required_argument, NULL, 620},
1674         {"cmd-brightness-down", required_argument, NULL, 621},
1675 
1676         {"cmd-media-play", required_argument, NULL, 630},
1677         {"cmd-media-pause", required_argument, NULL, 631},
1678         {"cmd-media-stop", required_argument, NULL, 632},
1679         {"cmd-media-next", required_argument, NULL, 633},
1680         {"cmd-media-prev", required_argument, NULL, 634},
1681 
1682         {"cmd-audio-mute", required_argument, NULL, 640},
1683         {"cmd-volume-up", required_argument, NULL, 641},
1684         {"cmd-volume-down", required_argument, NULL, 642},
1685         {"cmd-mic-mute", required_argument, NULL, 643},
1686 
1687         {"cmd-power-down", required_argument, NULL, 650},
1688         {"cmd-power-off", required_argument, NULL, 651},
1689         {"cmd-power-sleep", required_argument, NULL, 652},
1690 
1691         // bar indicator stuff
1692         {"bar-indicator", no_argument, NULL, 700},
1693         {"bar-direction", required_argument, NULL, 701},
1694         {"bar-orientation", required_argument, NULL, 703},
1695         {"bar-step", required_argument, NULL, 704},
1696         {"bar-max-height", required_argument, NULL, 705},
1697         {"bar-base-width", required_argument, NULL, 706},
1698         {"bar-color", required_argument, NULL, 707},
1699         {"bar-periodic-step", required_argument, NULL, 708},
1700         {"bar-pos", required_argument, NULL, 709},
1701         {"bar-count", required_argument, NULL, 710},
1702         {"bar-total-width", required_argument, NULL, 711},
1703 
1704         // misc.
1705         {"redraw-thread", no_argument, NULL, 900},
1706         {"refresh-rate", required_argument, NULL, 901},
1707         {"composite", no_argument, NULL, 902},
1708         {"no-verify", no_argument, NULL, 905},
1709 
1710         // slideshow options
1711         {"slideshow-interval", required_argument, NULL, 903},
1712         {"slideshow-random-selection", no_argument, NULL, 904},
1713 
1714         {NULL, no_argument, NULL, 0}};
1715 
1716     if ((pw = getpwuid(getuid())) == NULL)
1717         err(EXIT_FAILURE, "getpwuid() failed");
1718     if ((username = pw->pw_name) == NULL)
1719         errx(EXIT_FAILURE, "pw->pw_name is NULL.");
1720     if (getenv("WAYLAND_DISPLAY") != NULL)
1721         errx(EXIT_FAILURE, "i3lock is a program for X11 and does not work on Wayland. Try https://github.com/swaywm/swaylock instead");
1722 
1723     char *optstring = "hvnbdc:p:ui:tCFLMeI:frsS:kB:m";
1724     char *arg = NULL;
1725     int opt = 0;
1726     char padded[9] = "ffffffff"; \
1727 
1728 #define parse_color(acolor)\
1729     arg = optarg;\
1730     if (arg[0] == '#') arg++;\
1731     if (strlen(arg) == 6) {\
1732       /* If 6 digits given, assume RGB and pad 0xff for alpha */\
1733       strncpy( padded, arg, 6 );\
1734       arg = padded;\
1735     }\
1736     if (strlen(arg) != 8 || sscanf(arg, "%08[0-9a-fA-F]", acolor) != 1)\
1737         errx(1, #acolor " is invalid, color must be given in 3 or 4-byte format: rrggbb[aa]\n");
1738 
1739 #define parse_outline_width(awidth)\
1740     arg = optarg;\
1741     if (sscanf(arg, "%lf", &awidth) != 1)\
1742         errx(1, #awidth " must be a number\n");\
1743     if (awidth < 0) {\
1744         fprintf(stderr, #awidth " must be a positive double; ignoring...\n");\
1745         awidth = 0;\
1746     }
1747 
1748     while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) {
1749         switch (o) {
1750             case 'v':
1751                 errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg, © 2015 Cassandra Fox, © 2021 Raymond Li");
1752             case 'n':
1753                 dont_fork = true;
1754                 break;
1755             case 'b':
1756                 beep = true;
1757                 break;
1758             case 'd':
1759                 fprintf(stderr, "DPMS support has been removed from i3lock. Please see the manpage i3lock(1).\n");
1760                 break;
1761             case 'I': {
1762                 fprintf(stderr, "Inactivity timeout only makes sense with DPMS, which was removed. Please see the manpage i3lock(1).\n");
1763                 break;
1764             }
1765             case 'u':
1766                 unlock_indicator = false;
1767                 break;
1768             case 'i':
1769                 image_path = strdup(optarg);
1770                 break;
1771             case 't':
1772                 if(bg_type != NONE) {
1773                     errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used.");
1774                 }
1775                 bg_type = TILE;
1776                 break;
1777             case 'C':
1778                 if(bg_type != NONE) {
1779                     errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used.");
1780                 }
1781                 bg_type = CENTER;
1782                 break;
1783             case 'F':
1784                 if(bg_type != NONE) {
1785                     errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used.");
1786                 }
1787                 bg_type = FILL;
1788                 break;
1789             case 'L':
1790                 if(bg_type != NONE) {
1791                     errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used.");
1792                 }
1793                 bg_type = SCALE;
1794                 break;
1795             case 'M':
1796                 if(bg_type != NONE) {
1797                     errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used.");
1798                 }
1799                 bg_type = MAX;
1800                 break;
1801             case 'p':
1802                 if (!strcmp(optarg, "win")) {
1803                     curs_choice = CURS_WIN;
1804                 } else if (!strcmp(optarg, "default")) {
1805                     curs_choice = CURS_DEFAULT;
1806                 } else {
1807                     errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".");
1808                 }
1809                 break;
1810             case 'e':
1811                 ignore_empty_password = true;
1812                 break;
1813             case 'f':
1814                 show_failed_attempts = true;
1815                 break;
1816             case 'r':
1817                 if (internal_line_source != 0) {
1818                   errx(EXIT_FAILURE, "i3lock-color: Options line-uses-ring and line-uses-inside conflict.");
1819                 }
1820                 internal_line_source = 1; //sets the line drawn inside to use the inside color when drawn
1821                 break;
1822             case 's':
1823                 if (internal_line_source != 0) {
1824                   errx(EXIT_FAILURE, "i3lock-color: Options line-uses-ring and line-uses-inside conflict.");
1825                 }
1826                 internal_line_source = 2;
1827                 break;
1828             case 'S':
1829                 screen_number = atoi(optarg);
1830                 break;
1831 
1832             case 'k':
1833                 show_clock = true;
1834                 break;
1835             case 'B':
1836                 blur = true;
1837                 blur_sigma = atoi(optarg);
1838                 break;
1839 
1840             // Begin colors
1841             case 'c':
1842                 parse_color(color);
1843                 break;
1844             case 300:
1845                 parse_color(insidevercolor);
1846                 break;
1847             case 301:
1848                 parse_color(insidewrongcolor);
1849                 break;
1850             case 302:
1851                 parse_color(insidecolor);
1852                 break;
1853             case 303:
1854                 parse_color(ringvercolor);
1855                 break;
1856             case 304:
1857                 parse_color(ringwrongcolor);
1858                 break;
1859             case 305:
1860                 parse_color(ringcolor);
1861                 break;
1862             case 306:
1863                 parse_color(linecolor);
1864                 break;
1865             case 307:
1866                 parse_color(verifcolor);
1867                 break;
1868             case 308:
1869                 parse_color(wrongcolor);
1870                 break;
1871             case 309:
1872                 parse_color(layoutcolor);
1873                 break;
1874             case 310:
1875                 parse_color(timecolor);
1876                 break;
1877             case 311:
1878                 parse_color(datecolor);
1879                 break;
1880             case 312:
1881                 parse_color(keyhlcolor);
1882                 break;
1883             case 313:
1884                 parse_color(bshlcolor);
1885                 break;
1886             case 314:
1887                 parse_color(separatorcolor);
1888                 break;
1889             case 315:
1890                 parse_color(greetercolor);
1891                 break;
1892             case  316:
1893                 parse_color(verifoutlinecolor);
1894                 break;
1895             case  317:
1896                 parse_color(wrongoutlinecolor);
1897                 break;
1898             case  318:
1899                 parse_color(layoutoutlinecolor);
1900                 break;
1901             case  319:
1902                 parse_color(timeoutlinecolor);
1903                 break;
1904             case  320:
1905                 parse_color(dateoutlinecolor);
1906                 break;
1907             case  321:
1908                 parse_color(greeteroutlinecolor);
1909                 break;
1910             case  322:
1911                 parse_color(modifcolor);
1912                 break;
1913             case  323:
1914                 parse_color(modifoutlinecolor);
1915                 break;
1916 
1917 
1918             // General indicator opts
1919             case 400:
1920                 show_clock = true;
1921                 always_show_clock = true;
1922                 break;
1923             case 401:
1924                 show_indicator = true;
1925                 break;
1926             case 402:
1927                 arg = optarg;
1928                 if (sscanf(arg, "%lf", &circle_radius) != 1)
1929                     errx(1, "radius must be a number\n");
1930                 if (circle_radius < 1) {
1931                     fprintf(stderr, "radius must be a positive integer; ignoring...\n");
1932                     circle_radius = 90.0;
1933                 }
1934                 break;
1935             case 403:
1936                 arg = optarg;
1937                 if (sscanf(arg, "%lf", &ring_width) != 1)
1938                     errx(1, "ring-width must be a number\n");
1939                 if (ring_width < 1.0) {
1940                     fprintf(stderr, "ring-width must be a positive float; ignoring...\n");
1941                     ring_width = 7.0;
1942                 }
1943                 break;
1944 
1945             // Alignment stuff
1946             case 500:
1947                 opt = atoi(optarg);
1948                 if (opt < 0 || opt > 2) opt = 0;
1949                 time_align = opt;
1950                 break;
1951             case 501:
1952                 opt = atoi(optarg);
1953                 if (opt < 0 || opt > 2) opt = 0;
1954                 date_align = opt;
1955                 break;
1956             case 502:
1957                 opt = atoi(optarg);
1958                 if (opt < 0 || opt > 2) opt = 0;
1959                 verif_align = opt;
1960                 break;
1961             case 503:
1962                 opt = atoi(optarg);
1963                 if (opt < 0 || opt > 2) opt = 0;
1964                 wrong_align = opt;
1965                 break;
1966             case 504:
1967                 opt = atoi(optarg);
1968                 if (opt < 0 || opt > 2) opt = 0;
1969                 layout_align = opt;
1970                 break;
1971             case 505:
1972                 opt = atoi(optarg);
1973                 if (opt < 0 || opt > 2) opt = 0;
1974                 modif_align = opt;
1975                 break;
1976             case 506:
1977                 opt = atoi(optarg);
1978                 if (opt < 0 || opt > 2) opt = 0;
1979                 greeter_align = opt;
1980                 break;
1981 
1982             // String stuff
1983             case 510:
1984                 if (strlen(optarg) > 31) {
1985                     errx(1, "time format string can be at most 31 characters\n");
1986                 }
1987                 strcpy(time_format,optarg);
1988                 break;
1989             case 511:
1990                 if (strlen(optarg) > 31) {
1991                     errx(1, "time format string can be at most 31 characters\n");
1992                 }
1993                 strcpy(date_format,optarg);
1994                 break;
1995             case 512:
1996                 verif_text = optarg;
1997                 break;
1998             case 513:
1999                 wrong_text = optarg;
2000                 break;
2001             case 514:
2002                 // if layout is NULL, do nothing
2003                 // if not NULL, attempt to display stuff
2004                 // need to code some sane defaults for it
2005                 keylayout_mode = atoi(optarg);
2006                 break;
2007             case 515:
2008                 noinput_text = optarg;
2009                 break;
2010             case 516:
2011                 lock_text = optarg;
2012                 break;
2013             case 517:
2014                 lock_failed_text = optarg;
2015                 break;
2016             case 518:
2017                 greeter_text = optarg;
2018                 break;
2019             case 519:
2020                 show_modkey_text = false;
2021                 break;
2022 
2023             // Font stuff
2024             case 520:
2025                 if (strlen(optarg) > 63) {
2026                     errx(1, "time font string can be at most 63 characters\n");
2027                 }
2028                 strcpy(fonts[TIME_FONT],optarg);
2029                 break;
2030             case 521:
2031                 if (strlen(optarg) > 63) {
2032                     errx(1, "date font string can be at most 63 characters\n");
2033                 }
2034                 strcpy(fonts[DATE_FONT],optarg);
2035                 break;
2036             case 522:
2037                 if (strlen(optarg) > 63) {
2038                     errx(1, "verif font string can be at most 63 "
2039                             "characters\n");
2040                 }
2041                 strcpy(fonts[VERIF_FONT],optarg);
2042                 break;
2043             case 523:
2044                 if (strlen(optarg) > 63) {
2045                     errx(1, "wrong font string can be at most 63 "
2046                             "characters\n");
2047                 }
2048                 strcpy(fonts[WRONG_FONT],optarg);
2049                 break;
2050             case 524:
2051                 if (strlen(optarg) > 63) {
2052                     errx(1, "layout font string can be at most 63 characters\n");
2053                 }
2054                 strcpy(fonts[LAYOUT_FONT],optarg);
2055                 break;
2056             case 525:
2057                 if (strlen(optarg) > 63) {
2058                     errx(1, "greeter font string can be at most 63 characters\n");
2059                 }
2060                 strcpy(fonts[GREETER_FONT],optarg);
2061                 break;
2062 
2063             // Text size
2064             case 530:
2065                 arg = optarg;
2066                 if (sscanf(arg, "%lf", &time_size) != 1)
2067                     errx(1, "timesize must be a number\n");
2068                 if (time_size < 1)
2069                     errx(1, "timesize must be larger than 0\n");
2070                 break;
2071             case 531:
2072                 arg = optarg;
2073                 if (sscanf(arg, "%lf", &date_size) != 1)
2074                     errx(1, "datesize must be a number\n");
2075                 if (date_size < 1)
2076                     errx(1, "datesize must be larger than 0\n");
2077                 break;
2078             case 532:
2079                 arg = optarg;
2080                 if (sscanf(arg, "%lf", &verif_size) != 1)
2081                     errx(1, "verifsize must be a number\n");
2082                 if (verif_size < 1) {
2083                     fprintf(stderr, "verifsize must be a positive integer; ignoring...\n");
2084                     verif_size = 28.0;
2085                 }
2086                 break;
2087             case 533:
2088                 arg = optarg;
2089                 if (sscanf(arg, "%lf", &wrong_size) != 1)
2090                     errx(1, "wrongsize must be a number\n");
2091                 if (wrong_size < 1) {
2092                     fprintf(stderr, "wrongsize must be a positive integer; ignoring...\n");
2093                     wrong_size = 28.0;
2094                 }
2095                 break;
2096             case 534:
2097                 arg = optarg;
2098                 if (sscanf(arg, "%lf", &layout_size) != 1)
2099                     errx(1, "layoutsize must be a number\n");
2100                 if (date_size < 1)
2101                     errx(1, "layoutsize must be larger than 0\n");
2102                 break;
2103             case 535:
2104                 arg = optarg;
2105                 if (sscanf(arg, "%lf", &modifier_size) != 1)
2106                     errx(1, "modsize must be a number\n");
2107                 if (modifier_size < 1) {
2108                     fprintf(stderr, "modsize must be a positive integer; ignoring...\n");
2109                     modifier_size = 14.0;
2110                 }
2111                 break;
2112             case 536:
2113                 arg = optarg;
2114                 if (sscanf(arg, "%lf", &greeter_size) != 1)
2115                     errx(1, "greetersize must be a number\n");
2116                 if (greeter_size < 1) {
2117                     fprintf(stderr, "greetersize must be a positive integer; ignoring...\n");
2118                     greeter_size = 14.0;
2119                 }
2120                 break;
2121 
2122             // Positions
2123             case 540:
2124                 //read in to time_x_expr and time_y_expr
2125                 if (strlen(optarg) > 31) {
2126                     // this is overly restrictive since both the x and y string buffers have size 32, but it's easier to check.
2127                     errx(1, "time position string can be at most 31 characters\n");
2128                 }
2129                 arg = optarg;
2130                 if (sscanf(arg, "%30[^:]:%30[^:]", time_x_expr, time_y_expr) != 2) {
2131                     errx(1, "timepos must be of the form x:y\n");
2132                 }
2133                 break;
2134             case 541:
2135                 //read in to date_x_expr and date_y_expr
2136                 if (strlen(optarg) > 31) {
2137                     // this is overly restrictive since both the x and y string buffers have size 32, but it's easier to check.
2138                     errx(1, "date position string can be at most 31 characters\n");
2139                 }
2140                 arg = optarg;
2141                 if (sscanf(arg, "%30[^:]:%30[^:]", date_x_expr, date_y_expr) != 2) {
2142                     errx(1, "datepos must be of the form x:y\n");
2143                 }
2144                 break;
2145             case 542:
2146                 // read in to time_x_expr and time_y_expr
2147                 if (strlen(optarg) > 31) {
2148                     errx(1, "verif position string can be at most 31 characters\n");
2149                 }
2150                 arg = optarg;
2151                 if (sscanf(arg, "%30[^:]:%30[^:]", verif_x_expr, verif_y_expr) != 2) {
2152                     errx(1, "verifpos must be of the form x:y\n");
2153                 }
2154                 break;
2155             case 543:
2156                 if (strlen(optarg) > 31) {
2157                     errx(1, "\"wrong\" text position string can be at most 31 characters\n");
2158                 }
2159                 arg = optarg;
2160                 if (sscanf(arg, "%30[^:]:%30[^:]", wrong_x_expr, wrong_y_expr) != 2) {
2161                     errx(1, "wrongpos must be of the form x:y\n");
2162                 }
2163                 break;
2164             case 544:
2165                 if (strlen(optarg) > 31) {
2166                     errx(1, "layout position string can be at most 31 characters\n");
2167                 }
2168                 arg = optarg;
2169                 if (sscanf(arg, "%30[^:]:%30[^:]", layout_x_expr, layout_y_expr) != 2) {
2170                     errx(1, "layoutpos must be of the form x:y\n");
2171                 }
2172                 break;
2173             case 545:
2174                 if (strlen(optarg) > 31) {
2175                     // this is overly restrictive since both the x and y string buffers have size 32, but it's easier to check.
2176                     errx(1, "status position string can be at most 31 characters\n");
2177                 }
2178                 arg = optarg;
2179                 if (sscanf(arg, "%30[^:]:%30[^:]", status_x_expr, status_y_expr) != 2) {
2180                     errx(1, "statuspos must be of the form x:y\n");
2181                 }
2182                 break;
2183             case 546:
2184                 if (strlen(optarg) > 31) {
2185                     // this is overly restrictive since both the x and y string buffers have size 32, but it's easier to check.
2186                     errx(1, "modif position string can be at most 31 characters\n");
2187                 }
2188                 arg = optarg;
2189                 if (sscanf(arg, "%30[^:]:%30[^:]", modif_x_expr, modif_y_expr) != 2) {
2190                     errx(1, "modifpos must be of the form x:y\n");
2191                 }
2192                 break;
2193             case 547:
2194                 if (strlen(optarg) > 31) {
2195                     // this is overly restrictive since both the x and y string buffers have size 32, but it's easier to check.
2196                     errx(1, "indicator position string can be at most 31 characters\n");
2197                 }
2198                 arg = optarg;
2199                 if (sscanf(arg, "%30[^:]:%30[^:]", ind_x_expr, ind_y_expr) != 2) {
2200                     errx(1, "indpos must be of the form x:y\n");
2201                 }
2202                 break;
2203             case 548:
2204                 if (strlen(optarg) > 31) {
2205                     // this is overly restrictive since both the x and y string buffers have size 32, but it's easier to check.
2206                     errx(1, "greeter position string can be at most 31 characters\n");
2207                 }
2208                 arg = optarg;
2209                 if (sscanf(arg, "%30[^:]:%30[^:]", greeter_x_expr, greeter_y_expr) != 2) {
2210                     errx(1, "greeterpos must be of the form x:y\n");
2211                 }
2212                 break;
2213 
2214             // text outline width
2215             case 560:
2216                 parse_outline_width(timeoutlinewidth);
2217                 break;
2218             case 561:
2219                 parse_outline_width(dateoutlinewidth);
2220                 break;
2221             case 562:
2222                 parse_outline_width(verifoutlinewidth);
2223                 break;
2224             case 563:
2225                 parse_outline_width(wrongoutlinewidth);
2226                 break;
2227             case 564:
2228                 parse_outline_width(modifieroutlinewidth);
2229                 break;
2230             case 565:
2231                 parse_outline_width(layoutoutlinewidth);
2232                 break;
2233             case 566:
2234                 parse_outline_width(greeteroutlinewidth);
2235                 break;
2236 
2237 
2238             // Pass keys
2239             case 601:
2240                 pass_media_keys = true;
2241                 break;
2242             case 602:
2243                 pass_screen_keys = true;
2244                 break;
2245             case 603:
2246                 pass_power_keys = true;
2247                 break;
2248             case 604:
2249                 pass_volume_keys = true;
2250                 break;
2251 
2252             //custom key commands
2253             case 610:
2254                 hotkeys = true;
2255                 break;
2256             case 620:
2257                 cmd_brightness_up = optarg;
2258                 break;
2259             case 621:
2260                 cmd_brightness_down = optarg;
2261                 break;
2262 
2263             case 630:
2264                 cmd_media_play = optarg;
2265                 break;
2266             case 631:
2267                 cmd_media_pause = optarg;
2268                 break;
2269             case 632:
2270                 cmd_media_stop = optarg;
2271                 break;
2272             case 633:
2273                 cmd_media_next = optarg;
2274                 break;
2275             case 634:
2276                 cmd_media_prev = optarg;
2277                 break;
2278 
2279             case 640:
2280                 cmd_audio_mute = optarg;
2281                 break;
2282             case 641:
2283                 cmd_volume_up = optarg;
2284                 break;
2285             case 642:
2286                 cmd_volume_down = optarg;
2287                 break;
2288             case 643:
2289                 cmd_mic_mute = optarg;
2290                 break;
2291 
2292             case 650:
2293                 cmd_power_down = optarg;
2294                 break;
2295             case 651:
2296                 cmd_power_off = optarg;
2297                 break;
2298             case 652:
2299                 cmd_power_sleep = optarg;
2300                 break;
2301 
2302             // Bar indicator
2303             case 700:
2304                 bar_enabled = true;
2305                 break;
2306             case 701:
2307                 opt = atoi(optarg);
2308                 switch(opt) {
2309                     case BAR_REVERSED:
2310                         bar_reversed = true;
2311                         break;
2312                     case BAR_BIDIRECTIONAL:
2313                         bar_bidirectional = true;
2314                         break;
2315                     case BAR_DEFAULT:
2316                     default:
2317                         break;
2318                 }
2319                 break;
2320             case 703:
2321                 arg = optarg;
2322                 if (strcmp(arg, "vertical") == 0)
2323                     bar_orientation = BAR_VERT;
2324                 else if (strcmp(arg, "horizontal") == 0)
2325                     bar_orientation = BAR_FLAT;
2326                 else
2327                     errx(1, "bar orientation must be \"vertical\" or \"horizontal\"\n");
2328                 break;
2329             case 704:
2330                 bar_step = atoi(optarg);
2331                 if (bar_step < 1) bar_step = 15;
2332                 break;
2333             case 705:
2334                 max_bar_height = atoi(optarg);
2335                 if (max_bar_height < 1) max_bar_height = 25;
2336                 break;
2337             case 706:
2338                 bar_base_height = atoi(optarg);
2339                 if (bar_base_height < 1) bar_base_height = 25;
2340                 break;
2341             case 707:
2342                 parse_color(bar_base_color);
2343                 break;
2344             case 708:
2345                 opt = atoi(optarg);
2346                 if (opt > 0)
2347                     bar_periodic_step = opt;
2348                 break;
2349             case 709:
2350                 arg = optarg;
2351                 if (sscanf(arg, "%31[^:]:%31[^:]", bar_x_expr, bar_y_expr) < 1) {
2352                     errx(1, "bar-position must be a single number or of the form x:y with a max length of 31\n");
2353                 }
2354                 break;
2355             case 710:
2356                 bar_count = atoi(optarg);
2357                 if (bar_count > MAX_BAR_COUNT || bar_count < MIN_BAR_COUNT) {
2358                     errx(1, "bar-count must be between %d and %d\n", MIN_BAR_COUNT, MAX_BAR_COUNT);
2359                 }
2360                 break;
2361             case 711:
2362                 arg = optarg;
2363                 if (sscanf(arg, "%31s", bar_width_expr) != 1) {
2364                     errx(1, "missing argument for bar-total-width\n");
2365                 }
2366                 break;
2367 
2368             // Misc
2369             case 900:
2370                 redraw_thread = true;
2371                 break;
2372             case 901:
2373                 arg = optarg;
2374                 refresh_rate = strtof(arg, NULL);
2375                 if (refresh_rate < 0.0) {
2376                     fprintf(stderr, "The given refresh rate of %fs is less than zero seconds and was ignored.\n", refresh_rate);
2377                     refresh_rate = 1.0;
2378                 }
2379                 break;
2380             case 902:
2381                 composite = true;
2382                 break;
2383             case 903:
2384                 slideshow_interval = atoi(optarg);
2385 
2386                 if (slideshow_interval < 0) {
2387                     slideshow_interval = 10;
2388                 }
2389                 break;
2390             case 904:
2391                 slideshow_random_selection = true;
2392                 break;
2393             case 905:
2394                 no_verify = true;
2395                 break;
2396             case 998:
2397                 image_raw_format = strdup(optarg);
2398                 break;
2399             case 999:
2400                 debug_mode = true;
2401                 break;
2402             default:
2403                 errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
2404                                    " [-i image.png] [-t] [-e] [-f]\n"
2405                                    "Please see the manpage for a full list of arguments.");
2406         }
2407     }
2408 
2409     /* We need (relatively) random numbers for highlighting a random part of
2410      * the unlock indicator upon keypresses. */
2411     srand(time(NULL));
2412 
2413 #ifndef __OpenBSD__
2414     /* Initialize PAM */
2415     if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
2416         errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
2417 
2418     if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
2419         errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
2420 #endif
2421 
2422 /* Using mlock() as non-super-user seems only possible in Linux.
2423  * Users of other operating systems should use encrypted swap/no swap
2424  * (or remove the ifdef and run i3lock as super-user).
2425  * Alas, swap is encrypted by default on OpenBSD so swapping out
2426  * is not necessarily an issue. */
2427 #if defined(__linux__)
2428     /* Lock the area where we store the password in memory, we don’t want it to
2429      * be swapped to disk. Since Linux 2.6.9, this does not require any
2430      * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */
2431     if (mlock(password, sizeof(password)) != 0)
2432         err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK");
2433 #endif
2434 
2435     /* Double checking that connection is good and operatable with xcb */
2436     int screennr;
2437     if ((conn = xcb_connect(NULL, &screennr)) == NULL ||
2438         xcb_connection_has_error(conn))
2439             errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");
2440 
2441     if (xkb_x11_setup_xkb_extension(conn,
2442                                     XKB_X11_MIN_MAJOR_XKB_VERSION,
2443                                     XKB_X11_MIN_MINOR_XKB_VERSION,
2444                                     0,
2445                                     NULL,
2446                                     NULL,
2447                                     &xkb_base_event,
2448                                     &xkb_base_error) != 1)
2449         errx(EXIT_FAILURE, "Could not setup XKB extension.");
2450 
2451     layout_text = get_keylayoutname(keylayout_mode, conn);
2452     if (layout_text)
2453         show_clock = true;
2454     static const xcb_xkb_map_part_t required_map_parts =
2455         (XCB_XKB_MAP_PART_KEY_TYPES |
2456          XCB_XKB_MAP_PART_KEY_SYMS |
2457          XCB_XKB_MAP_PART_MODIFIER_MAP |
2458          XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
2459          XCB_XKB_MAP_PART_KEY_ACTIONS |
2460          XCB_XKB_MAP_PART_VIRTUAL_MODS |
2461          XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
2462 
2463     static const xcb_xkb_event_type_t required_events =
2464         (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
2465          XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
2466          XCB_XKB_EVENT_TYPE_STATE_NOTIFY);
2467 
2468     xcb_xkb_select_events(
2469         conn,
2470         xkb_x11_get_core_keyboard_device_id(conn),
2471         required_events,
2472         0,
2473         required_events,
2474         required_map_parts,
2475         required_map_parts,
2476         0);
2477 
2478     /* When we cannot initially load the keymap, we better exit */
2479     if (!load_keymap())
2480         errx(EXIT_FAILURE, "Could not load keymap");
2481 
2482 
2483     const char *locale = getenv("LC_ALL");
2484     if (!locale || !*locale)
2485         locale = getenv("LC_TIME");
2486     if (!locale || !*locale)
2487         locale = getenv("LC_CTYPE");
2488     if (!locale || !*locale)
2489         locale = getenv("LANG");
2490     if (!locale || !*locale) {
2491         if (debug_mode)
2492             fprintf(stderr, "Can't detect your locale, fallback to C\n");
2493         locale = "C";
2494     }
2495 
2496     setlocale(LC_ALL, locale);
2497 
2498 #if XKBCOMPOSE == 1
2499     load_compose_table(locale);
2500 #endif
2501 
2502 
2503     screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
2504 
2505     init_dpi();
2506 
2507     randr_init(&randr_base, screen->root);
2508     randr_query(screen->root);
2509 
2510     last_resolution[0] = screen->width_in_pixels;
2511     last_resolution[1] = screen->height_in_pixels;
2512 
2513     if (bar_enabled) {
2514         bar_heights = (double*) calloc(bar_count, sizeof(double));
2515     }
2516 
2517     xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK,
2518                                  (uint32_t[]){XCB_EVENT_MASK_STRUCTURE_NOTIFY});
2519 
2520     init_colors_once();
2521     if (image_path != NULL) {
2522         if (!is_directory(image_path)) {
2523             img = load_image(image_path);
2524         } else {
2525             /* Path to a directory is provided -> use slideshow mode */
2526             slideshow_path = strdup(image_path);
2527             if (!load_slideshow_images(slideshow_path)) exit(EXIT_FAILURE);
2528             img = load_image(img_slideshow[0]);
2529         }
2530 
2531         free(image_path);
2532     }
2533 
2534     free(image_raw_format);
2535 
2536     if (blur) {
2537         xcb_pixmap_t bg_pixmap = capture_bg_pixmap(conn, screen, last_resolution);
2538         cairo_surface_t *xcb_img = cairo_xcb_surface_create(conn, bg_pixmap, get_root_visual_type(screen), last_resolution[0], last_resolution[1]);
2539 
2540         blur_bg_img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, last_resolution[0], last_resolution[1]);
2541         cairo_t *ctx = cairo_create(blur_bg_img);
2542 
2543         cairo_set_source_surface(ctx, xcb_img, 0, 0);
2544         cairo_paint(ctx);
2545         blur_image_surface(blur_bg_img, blur_sigma);
2546 
2547         cairo_destroy(ctx);
2548         cairo_surface_destroy(xcb_img);
2549         xcb_free_pixmap(conn, bg_pixmap);
2550     }
2551 
2552     xcb_window_t stolen_focus = find_focused_window(conn, screen->root);
2553 
2554     /* Open the fullscreen window, already with the correct pixmap in place */
2555     win = open_fullscreen_window(conn, screen, color);
2556 
2557     xcb_pixmap_t pixmap = create_bg_pixmap(conn, win, last_resolution, color);
2558     render_lock(last_resolution, pixmap);
2559     xcb_change_window_attributes(conn, win, XCB_CW_BACK_PIXMAP, (uint32_t[]){pixmap});
2560     xcb_free_pixmap(conn, pixmap);
2561 
2562     cursor = create_cursor(conn, screen, win, curs_choice);
2563 
2564     /* Display the "locking…" message while trying to grab the pointer/keyboard. */
2565     auth_state = STATE_AUTH_LOCK;
2566     if (!grab_pointer_and_keyboard(conn, screen, cursor, 1000)) {
2567         DEBUG("stole focus from X11 window 0x%08x\n", stolen_focus);
2568 
2569         /* Set the focus to i3lock, possibly closing context menus which would
2570          * otherwise prevent us from grabbing keyboard/pointer.
2571          *
2572          * We cannot use set_focused_window because _NET_ACTIVE_WINDOW only
2573          * works for managed windows, but i3lock uses an unmanaged window
2574          * (override_redirect=1). */
2575         xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT /* revert_to */, win, XCB_CURRENT_TIME);
2576         if (!grab_pointer_and_keyboard(conn, screen, cursor, 9000)) {
2577             auth_state = STATE_I3LOCK_LOCK_FAILED;
2578             redraw_screen();
2579             sleep(1);
2580             errx(EXIT_FAILURE, "Cannot grab pointer/keyboard");
2581         }
2582     }
2583 
2584     pid_t pid = fork();
2585     /* The pid == -1 case is intentionally ignored here:
2586      * While the child process is useful for preventing other windows from
2587      * popping up while i3lock blocks, it is not critical. */
2588     if (pid == 0) {
2589         /* Child */
2590         close(xcb_get_file_descriptor(conn));
2591         maybe_close_sleep_lock_fd();
2592         raise_loop(win);
2593         exit(EXIT_SUCCESS);
2594     }
2595 
2596     /* Load the keymap again to sync the current modifier state. Since we first
2597      * loaded the keymap, there might have been changes, but starting from now,
2598      * we should get all key presses/releases due to having grabbed the
2599      * keyboard. */
2600     (void)load_keymap();
2601 
2602     /* Initialize the libev event loop. */
2603     main_loop = EV_DEFAULT;
2604     if (main_loop == NULL)
2605         errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?");
2606 
2607     /* Explicitly call the screen redraw in case "locking…" message was displayed */
2608     auth_state = STATE_AUTH_IDLE;
2609     redraw_screen();
2610 
2611     struct ev_io *xcb_watcher = calloc(sizeof(struct ev_io), 1);
2612     struct ev_check *xcb_check = calloc(sizeof(struct ev_check), 1);
2613     struct ev_prepare *xcb_prepare = calloc(sizeof(struct ev_prepare), 1);
2614 
2615     ev_io_init(xcb_watcher, xcb_got_event, xcb_get_file_descriptor(conn), EV_READ);
2616     ev_io_start(main_loop, xcb_watcher);
2617 
2618     ev_check_init(xcb_check, xcb_check_cb);
2619     ev_check_start(main_loop, xcb_check);
2620 
2621     ev_prepare_init(xcb_prepare, xcb_prepare_cb);
2622     ev_prepare_start(main_loop, xcb_prepare);
2623 
2624     /* Invoke the event callback once to catch all the events which were
2625      * received up until now. ev will only pick up new events (when the X11
2626      * file descriptor becomes readable). */
2627     ev_invoke(main_loop, xcb_check, 0);
2628 
2629     if (show_clock || bar_enabled || slideshow_enabled) {
2630         if (redraw_thread) {
2631             struct timespec ts;
2632             double s;
2633             double ns = modf(refresh_rate, &s);
2634             ts.tv_sec = (time_t) s;
2635             ts.tv_nsec = ns * NANOSECONDS_IN_SECOND;
2636             (void) pthread_create(&draw_thread, NULL, start_time_redraw_tick_pthread, (void*) &ts);
2637         } else {
2638             start_time_redraw_tick(main_loop);
2639         }
2640     }
2641     ev_loop(main_loop, 0);
2642 
2643 #ifndef __OpenBSD__
2644     if (pam_cleanup) {
2645         pam_end(pam_handle, PAM_SUCCESS);
2646     }
2647 #endif
2648 
2649     if (stolen_focus == XCB_NONE) {
2650         return 0;
2651     }
2652 
2653     DEBUG("restoring focus to X11 window 0x%08x\n", stolen_focus);
2654     xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
2655     xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME);
2656     xcb_destroy_window(conn, win);
2657     set_focused_window(conn, screen->root, stolen_focus);
2658     xcb_aux_sync(conn);
2659 
2660     return 0;
2661 }