+ break;
+ case 'e':
+ ignore_empty_password = true;
+ break;
+ case 0:
+ if (strcmp(longopts[optind].name, "debug") == 0)
+ debug_mode = true;
+ break;
+ case 'f':
+ show_failed_attempts = true;
+ break;
+ default:
+ errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
+ " [-i image.png] [-t] [-e] [-I timeout] [-f]");
+ }
+ }
+
+ /* We need (relatively) random numbers for highlighting a random part of
+ * the unlock indicator upon keypresses. */
+ srand(time(NULL));
+
+#ifndef __OpenBSD__
+ /* Initialize PAM */
+ if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
+ errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
+
+ if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
+ errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
+#endif
+
+/* Using mlock() as non-super-user seems only possible in Linux.
+ * Users of other operating systems should use encrypted swap/no swap
+ * (or remove the ifdef and run i3lock as super-user).
+ * Alas, swap is encrypted by default on OpenBSD so swapping out
+ * is not necessarily an issue. */
+#if defined(__linux__)
+ /* Lock the area where we store the password in memory, we don’t want it to
+ * be swapped to disk. Since Linux 2.6.9, this does not require any
+ * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */
+ if (mlock(password, sizeof(password)) != 0)
+ err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK");
+#endif
+
+ /* Double checking that connection is good and operatable with xcb */
+ int screennr;
+ if ((conn = xcb_connect(NULL, &screennr)) == NULL ||
+ xcb_connection_has_error(conn))
+ errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");
+
+ if (xkb_x11_setup_xkb_extension(conn,
+ XKB_X11_MIN_MAJOR_XKB_VERSION,
+ XKB_X11_MIN_MINOR_XKB_VERSION,
+ 0,
+ NULL,
+ NULL,
+ &xkb_base_event,
+ &xkb_base_error) != 1)
+ errx(EXIT_FAILURE, "Could not setup XKB extension.");
+
+ static const xcb_xkb_map_part_t required_map_parts =
+ (XCB_XKB_MAP_PART_KEY_TYPES |
+ XCB_XKB_MAP_PART_KEY_SYMS |
+ XCB_XKB_MAP_PART_MODIFIER_MAP |
+ XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
+ XCB_XKB_MAP_PART_KEY_ACTIONS |
+ XCB_XKB_MAP_PART_VIRTUAL_MODS |
+ XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
+
+ static const xcb_xkb_event_type_t required_events =
+ (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
+ XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY);
+
+ xcb_xkb_select_events(
+ conn,
+ xkb_x11_get_core_keyboard_device_id(conn),
+ required_events,
+ 0,
+ required_events,
+ required_map_parts,
+ required_map_parts,
+ 0);
+
+ /* When we cannot initially load the keymap, we better exit */
+ if (!load_keymap())
+ errx(EXIT_FAILURE, "Could not load keymap");
+
+ const char *locale = getenv("LC_ALL");
+ if (!locale || !*locale)
+ locale = getenv("LC_CTYPE");
+ if (!locale || !*locale)
+ locale = getenv("LANG");
+ if (!locale || !*locale) {
+ if (debug_mode)
+ fprintf(stderr, "Can't detect your locale, fallback to C\n");
+ locale = "C";
+ }
+
+ load_compose_table(locale);
+
+ xinerama_init();
+ xinerama_query_screens();
+
+ screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
+
+ last_resolution[0] = screen->width_in_pixels;
+ last_resolution[1] = screen->height_in_pixels;
+
+ xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK,
+ (uint32_t[]){XCB_EVENT_MASK_STRUCTURE_NOTIFY});
+
+ if (image_path) {
+ /* Create a pixmap to render on, fill it with the background color */
+ img = cairo_image_surface_create_from_png(image_path);
+ /* In case loading failed, we just pretend no -i was specified. */
+ if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
+ fprintf(stderr, "Could not load image \"%s\": %s\n",
+ image_path, cairo_status_to_string(cairo_surface_status(img)));
+ img = NULL;