shell: Use a busy cursor animation for unresponsive surfaces
diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index cceeadf..b767839 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -46,6 +46,9 @@
 	struct unlock_dialog *unlock_dialog;
 	struct task unlock_task;
 	struct wl_list outputs;
+
+	struct window *busy_window;
+	struct widget *busy_widget;
 };
 
 struct surface {
@@ -651,6 +654,64 @@
 	return background;
 }
 
+static const struct wl_callback_listener busy_cursor_listener;
+
+static void
+busy_cursor_frame_callback(void *data,
+			   struct wl_callback *callback, uint32_t time)
+{
+	struct input *input = data;
+	struct display *display = input_get_display(input);
+	struct desktop *desktop = display_get_user_data(display);
+	struct wl_surface *surface;
+	int index;
+
+	if (callback)
+		wl_callback_destroy(callback);
+	if (input_get_focus_widget(input) != desktop->busy_widget)
+		return;
+
+	/* FIXME: Get frame duration and number of frames from cursor. */
+	index = (time / 100) % 8;
+	input_set_pointer_image_index(input, CURSOR_WATCH, index);
+
+	surface = window_get_wl_surface(desktop->busy_window);
+	callback = wl_surface_frame(surface);
+	wl_callback_add_listener(callback, &busy_cursor_listener, input);
+}
+
+static const struct wl_callback_listener busy_cursor_listener = {
+	busy_cursor_frame_callback
+};
+
+static int
+busy_surface_enter_handler(struct widget *widget, struct input *input,
+			   float x, float y, void *data)
+{
+	busy_cursor_frame_callback(input, NULL, 0);
+
+	return CURSOR_WATCH;
+}
+
+static void
+busy_surface_create(struct desktop *desktop)
+{
+	struct wl_surface *s;
+
+	desktop->busy_window = window_create(desktop->display);
+	s = window_get_wl_surface(desktop->busy_window);
+	desktop_shell_set_busy_surface(desktop->shell, s);
+
+	desktop->busy_widget =
+		window_add_widget(desktop->busy_window, desktop);
+	/* We set the allocation to 1x1 at 0,0 so the fake enter event
+	 * at 0,0 will go to this widget. */
+	widget_set_allocation(desktop->busy_widget, 0, 0, 1, 1);
+
+	widget_set_enter_handler(desktop->busy_widget,
+				 busy_surface_enter_handler);
+}
+
 static void
 create_output(struct desktop *desktop, uint32_t id)
 {
@@ -729,6 +790,7 @@
 		return -1;
 	}
 
+	display_set_user_data(desktop.display, &desktop);
 	wl_display_add_global_listener(display_get_display(desktop.display),
 				       global_handler, &desktop);
 
@@ -744,6 +806,8 @@
 		desktop_shell_set_background(desktop.shell, output->output, s);
 	}
 
+	busy_surface_create(&desktop);
+
 	config_file = config_file_path("weston.ini");
 	ret = parse_config_file(config_file,
 				config_sections, ARRAY_LENGTH(config_sections),