+ free(event);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ char *username;
+ char *image_path = NULL;
+ int ret;
+ struct pam_conv conv = {conv_callback, NULL};
+ int curs_choice = CURS_NONE;
+ int o;
+ int optind = 0;
+ struct option longopts[] = {
+ {"version", no_argument, NULL, 'v'},
+ {"nofork", no_argument, NULL, 'n'},
+ {"beep", no_argument, NULL, 'b'},
+ {"dpms", no_argument, NULL, 'd'},
+ {"color", required_argument, NULL, 'c'},
+ {"pointer", required_argument, NULL , 'p'},
+ {"debug", no_argument, NULL, 0},
+ {"help", no_argument, NULL, 'h'},
+ {"no-unlock-indicator", no_argument, NULL, 'u'},
+ {"image", required_argument, NULL, 'i'},
+ {"tiling", no_argument, NULL, 't'},
+ {"ignore-empty-password", no_argument, NULL, 'e'},
+ {NULL, no_argument, NULL, 0}
+ };
+
+ if ((username = getenv("USER")) == NULL)
+ errx(1, "USER environment variable not set, please set it.\n");
+
+ while ((o = getopt_long(argc, argv, "hvnbdc:p:ui:te", longopts, &optind)) != -1) {
+ switch (o) {
+ case 'v':
+ errx(EXIT_SUCCESS, "version " VERSION " © 2010-2012 Michael Stapelberg");
+ case 'n':
+ dont_fork = true;
+ break;
+ case 'b':
+ beep = true;
+ break;
+ case 'd':
+ dpms = true;
+ break;
+ case 'c': {
+ char *arg = optarg;
+
+ /* Skip # if present */
+ if (arg[0] == '#')
+ arg++;
+
+ if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1)
+ errx(1, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");
+
+ break;
+ }
+ case 'u':
+ unlock_indicator = false;
+ break;
+ case 'i':
+ image_path = strdup(optarg);
+ break;
+ case 't':
+ tile = true;
+ break;
+ case 'p':
+ if (!strcmp(optarg, "win")) {
+ curs_choice = CURS_WIN;
+ } else if (!strcmp(optarg, "default")) {
+ curs_choice = CURS_DEFAULT;
+ } else {
+ errx(1, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n");
+ }
+ break;
+ case 'e':
+ ignore_empty_password = true;
+ break;
+ case 0:
+ if (strcmp(longopts[optind].name, "debug") == 0)
+ debug_mode = true;
+ break;
+ default:
+ errx(1, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
+ " [-i image.png] [-t] [-e]"
+ );
+ }
+ }
+
+ /* We need (relatively) random numbers for highlighting a random part of
+ * the unlock indicator upon keypresses. */
+ srand(time(NULL));
+
+ /* Initialize PAM */
+ ret = pam_start("i3lock", username, &conv, &pam_handle);
+ if (ret != PAM_SUCCESS)
+ errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
+
+/* 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). */
+#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
+
+ /* Initialize connection to X11 */
+ if ((display = XOpenDisplay(NULL)) == NULL)
+ errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");
+ XSetEventQueueOwner(display, XCBOwnsEventQueue);
+ conn = XGetXCBConnection(display);
+
+ /* Double checking that connection is good and operatable with xcb */
+ if (xcb_connection_has_error(conn))
+ errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");
+
+ /* When we cannot initially load the keymap, we better exit */
+ if (!load_keymap())
+ errx(EXIT_FAILURE, "Could not load keymap");
+
+ xinerama_init();
+ xinerama_query_screens();
+
+ /* if DPMS is enabled, check if the X server really supports it */
+ if (dpms) {
+ xcb_dpms_capable_cookie_t dpmsc = xcb_dpms_capable(conn);
+ xcb_dpms_capable_reply_t *dpmsr;
+ if ((dpmsr = xcb_dpms_capable_reply(conn, dpmsc, NULL))) {
+ if (!dpmsr->capable) {
+ if (debug_mode)
+ fprintf(stderr, "Disabling DPMS, X server not DPMS capable\n");
+ dpms = false;
+ }
+ free(dpmsr);
+ }
+ }