+bool ignore_empty_password = false;
+
+/* isutf, u8_dec © 2005 Jeff Bezanson, public domain */
+#define isutf(c) (((c) & 0xC0) != 0x80)
+
+/*
+ * Decrements i to point to the previous unicode glyph
+ *
+ */
+void u8_dec(char *s, int *i) {
+ (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i));
+}
+
+static void turn_monitors_on(void) {
+ if (dpms)
+ dpms_set_mode(conn, XCB_DPMS_DPMS_MODE_ON);
+}
+
+static void turn_monitors_off(void) {
+ if (dpms)
+ dpms_set_mode(conn, XCB_DPMS_DPMS_MODE_OFF);
+}
+
+/*
+ * Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
+ * Necessary so that we can properly let xkbcommon track the keyboard state and
+ * translate keypresses to utf-8.
+ *
+ * Ideally, xkbcommon would ship something like this itself, but as of now
+ * (version 0.2.0), it doesn’t.
+ *
+ * TODO: Once xcb-xkb is enabled by default and released, we should port this
+ * code to xcb-xkb. See also https://github.com/xkbcommon/libxkbcommon/issues/1
+ *
+ */
+static bool load_keymap(void) {
+ bool ret = false;
+ XkbFileInfo result;
+ memset(&result, '\0', sizeof(result));
+ result.xkb = XkbGetKeyboard(display, XkbAllMapComponentsMask, XkbUseCoreKbd);
+ if (result.xkb == NULL) {
+ fprintf(stderr, "[i3lock] XKB: XkbGetKeyboard failed\n");
+ return false;
+ }
+
+ FILE *temp = tmpfile();
+ if (temp == NULL) {
+ fprintf(stderr, "[i3lock] could not create tempfile\n");
+ return false;
+ }
+
+ bool ok = XkbWriteXKBKeymap(temp, &result, false, false, NULL, NULL);
+ if (!ok) {
+ fprintf(stderr, "[i3lock] XkbWriteXKBKeymap failed\n");
+ goto out;
+ }
+
+ rewind(temp);
+
+ if (xkb_context == NULL) {
+ if ((xkb_context = xkb_context_new(0)) == NULL) {
+ fprintf(stderr, "[i3lock] could not create xkbcommon context\n");
+ goto out;
+ }
+ }
+
+ if (xkb_keymap != NULL)
+ xkb_keymap_unref(xkb_keymap);
+
+ if ((xkb_keymap = xkb_keymap_new_from_file(xkb_context, temp, XKB_KEYMAP_FORMAT_TEXT_V1, 0)) == NULL) {
+ fprintf(stderr, "[i3lock] xkb_keymap_new_from_file failed\n");
+ goto out;
+ }
+
+ struct xkb_state *new_state = xkb_state_new(xkb_keymap);
+ if (new_state == NULL) {
+ fprintf(stderr, "[i3lock] xkb_state_new failed\n");
+ goto out;
+ }
+
+ /* Get the initial modifier state to be in sync with the X server.
+ * See https://github.com/xkbcommon/libxkbcommon/issues/1 for why we ignore
+ * the base and latched fields. */
+ XkbStateRec state_rec;
+ XkbGetState(display, XkbUseCoreKbd, &state_rec);
+
+ xkb_state_update_mask(new_state,
+ 0, 0, state_rec.locked_mods,
+ 0, 0, state_rec.locked_group);
+
+ if (xkb_state != NULL)
+ xkb_state_unref(xkb_state);
+ xkb_state = new_state;
+
+ ret = true;
+out:
+ XkbFreeKeyboard(result.xkb, XkbAllComponentsMask, true);
+ fclose(temp);
+ return ret;
+}