protocol: add screensaver interface

Add the screensaver interface to the desktop-shell protocol file. Also
add stubs for it in the compositor, and make wscreensaver to bind to the
screensaver interface. Wscreensaver gets a new option --demo to retain
the current behaviour as a regular wayland client.

When a screensaver application starts, it should bind to the screensaver
interface, enumerate all outputs, create a surface per output, and
register those surfaces via screensaver::set_surface request. Then it
continues with the usual animation loop, waiting for frame events. The
compositor will decide, when the given screensaver surfaces are
displayed. A screensaver application should respond to outputs coming
and going away by creating and destroying surfaces.

The compositor is supposed to activate a screensaver by exec'ing it, and
stop the screensaver by killing the client process. Only one client may
be bound to the screensaver interface at a time. If there already is a
client, the compositor could either kill it first, or not exec a new
one.

Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
diff --git a/compositor/shell.c b/compositor/shell.c
index 22004f9..395d545 100644
--- a/compositor/shell.c
+++ b/compositor/shell.c
@@ -54,6 +54,8 @@
 
 	struct wl_list backgrounds;
 	struct wl_list panels;
+
+	struct wl_resource *screensaver;
 };
 
 enum shell_surface_type {
@@ -933,6 +935,54 @@
 	wl_resource_destroy(resource, 0);
 }
 
+static void
+screensaver_set_surface(struct wl_client *client,
+			struct wl_resource *resource,
+			struct wl_resource *shell_surface_resource,
+			struct wl_resource *output_resource)
+{
+	struct wl_shell *shell = resource->data;
+	struct shell_surface *surface = shell_surface_resource->data;
+	struct wlsc_output *output = output_resource->data;
+
+	/* TODO */
+}
+
+static const struct screensaver_interface screensaver_implementation = {
+	screensaver_set_surface
+};
+
+static void
+unbind_screensaver(struct wl_resource *resource)
+{
+	struct wl_shell *shell = resource->data;
+
+	shell->screensaver = NULL;
+	free(resource);
+}
+
+static void
+bind_screensaver(struct wl_client *client,
+		 void *data, uint32_t version, uint32_t id)
+{
+	struct wl_shell *shell = data;
+	struct wl_resource *resource;
+
+	resource = wl_client_add_object(client, &screensaver_interface,
+					&screensaver_implementation,
+					id, shell);
+
+	if (shell->screensaver == NULL) {
+		resource->destroy = unbind_screensaver;
+		shell->screensaver = resource;
+		return;
+	}
+
+	wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+			       "interface object already bound");
+	wl_resource_destroy(resource, 0);
+}
+
 int
 shell_init(struct wlsc_compositor *ec);
 
@@ -966,6 +1016,10 @@
 				  shell, bind_desktop_shell) == NULL)
 		return -1;
 
+	if (wl_display_add_global(ec->wl_display, &screensaver_interface,
+				  shell, bind_screensaver) == NULL)
+		return -1;
+
 	if (launch_desktop_shell_process(shell) != 0)
 		return -1;