window: Add key-repeat to toy toolkit
diff --git a/clients/window.c b/clients/window.c
index aaf2009..1cc7dce 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -212,6 +212,12 @@
 		xkb_mod_mask_t alt_mask;
 		xkb_mod_mask_t shift_mask;
 	} xkb;
+
+	struct task repeat_task;
+	int repeat_timer_fd;
+	uint32_t repeat_sym;
+	uint32_t repeat_key;
+	uint32_t repeat_time;
 };
 
 struct output {
@@ -1826,6 +1832,7 @@
 	const xkb_keysym_t *syms;
 	xkb_keysym_t sym;
 	xkb_mod_mask_t mask;
+	struct itimerspec its;
 
 	input->display->serial = serial;
 	code = key + 8;
@@ -1845,20 +1852,54 @@
 	if (mask & input->xkb.shift_mask)
 		input->modifiers |= MOD_SHIFT_MASK;
 
-	if (num_syms == 1 && syms[0] == XKB_KEY_F5 &&
-	    input->modifiers == MOD_ALT_MASK) {
+	sym = XKB_KEY_NoSymbol;
+	if (num_syms == 1)
+		sym = syms[0];
+
+	if (sym == XKB_KEY_F5 && input->modifiers == MOD_ALT_MASK) {
 		if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
 			window_set_maximized(window,
 					     window->type != TYPE_MAXIMIZED);
 	} else if (window->key_handler) {
-		if (num_syms == 1)
-			sym = syms[0];
-		else
-			sym = XKB_KEY_NoSymbol;
-
 		(*window->key_handler)(window, input, time, key,
 				       sym, state, window->user_data);
 	}
+
+	if (state == WL_KEYBOARD_KEY_STATE_RELEASED &&
+	    key == input->repeat_key) {
+		its.it_interval.tv_sec = 0;
+		its.it_interval.tv_nsec = 0;
+		its.it_value.tv_sec = 0;
+		its.it_value.tv_nsec = 0;
+		timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
+	} else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+		input->repeat_sym = sym;
+		input->repeat_key = key;
+		input->repeat_time = time;
+		its.it_interval.tv_sec = 0;
+		its.it_interval.tv_nsec = 25 * 1000 * 1000;
+		its.it_value.tv_sec = 0;
+		its.it_value.tv_nsec = 400 * 1000 * 1000;
+		timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
+	}
+}
+
+static void
+keyboard_repeat_func(struct task *task, uint32_t events)
+{
+	struct input *input =
+		container_of(task, struct input, repeat_task);
+	struct window *window = input->keyboard_focus;
+	uint64_t exp;
+
+	read(input->repeat_timer_fd, &exp, sizeof (uint64_t));
+
+	if (window->key_handler) {
+		(*window->key_handler)(window, input, input->repeat_time,
+				       input->repeat_key, input->repeat_sym,
+				       WL_KEYBOARD_KEY_STATE_PRESSED,
+				       window->user_data);
+	}
 }
 
 static void
@@ -3228,6 +3269,11 @@
 				    input);
 
 	input->pointer_surface = wl_compositor_create_surface(d->compositor);
+
+	input->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+	input->repeat_task.run = keyboard_repeat_func;
+	display_watch_fd(d, input->repeat_timer_fd,
+			 EPOLLIN, &input->repeat_task);
 }
 
 static void
@@ -3254,6 +3300,7 @@
 
 	wl_list_remove(&input->link);
 	wl_seat_destroy(input->seat);
+	close(input->repeat_timer_fd);
 	free(input);
 }