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/clients/Makefile.am b/clients/Makefile.am
index 1fe6ff5..490e403 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -70,7 +70,12 @@
resizor_SOURCES = resizor.c
resizor_LDADD = $(toolkit_libs)
-wscreensaver_SOURCES = wscreensaver.c wscreensaver-glue.c glmatrix.c
+wscreensaver_SOURCES = \
+ wscreensaver.c \
+ desktop-shell-client-protocol.h \
+ desktop-shell-protocol.c \
+ wscreensaver-glue.c \
+ glmatrix.c
wscreensaver_LDADD = $(toolkit_libs) -lGLU
eventdemo_SOURCES = eventdemo.c
diff --git a/clients/wscreensaver.c b/clients/wscreensaver.c
index f00741e..9edaca7 100644
--- a/clients/wscreensaver.c
+++ b/clients/wscreensaver.c
@@ -20,7 +20,7 @@
* OF THIS SOFTWARE.
*/
-#include "config.h"
+#include "../config.h"
#include "wscreensaver.h"
@@ -34,6 +34,7 @@
#include <wayland-client.h>
+#include "desktop-shell-client-protocol.h"
#include "window.h"
extern struct wscreensaver_plugin glmatrix_screensaver;
@@ -45,7 +46,11 @@
const char *progname = NULL;
+static int demo_mode;
+
struct wscreensaver {
+ struct screensaver *interface;
+
struct display *display;
/* per output, if fullscreen mode */
@@ -246,21 +251,51 @@
return NULL;
}
+static void
+global_handler(struct wl_display *display, uint32_t id,
+ const char *interface, uint32_t version, void *data)
+{
+ struct wscreensaver *screensaver = data;
+
+ if (!strcmp(interface, "screensaver")) {
+ screensaver->interface =
+ wl_display_bind(display, id, &screensaver_interface);
+ }
+}
+
+static const GOptionEntry option_entries[] = {
+ { "demo", 0, 0, G_OPTION_ARG_NONE, &demo_mode,
+ "Run as a regular application, not a screensaver.", NULL },
+ { NULL }
+};
+
int main(int argc, char *argv[])
{
struct display *d;
- struct wscreensaver wscr = { 0 };
+ struct wscreensaver screensaver = { 0 };
const char *msg;
init_frand();
- d = display_create(&argc, &argv, NULL);
+ d = display_create(&argc, &argv, option_entries);
if (d == NULL) {
fprintf(stderr, "failed to create display: %m\n");
return EXIT_FAILURE;
}
- msg = init_wscreensaver(&wscr, d);
+ if (!demo_mode) {
+ wl_display_add_global_listener(display_get_display(d),
+ global_handler, &screensaver);
+ wl_display_roundtrip(display_get_display(d));
+ if (!screensaver.interface) {
+ fprintf(stderr,
+ "Server did not offer screensaver interface,"
+ " exiting.\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ msg = init_wscreensaver(&screensaver, d);
if (msg) {
fprintf(stderr, "wscreensaver init failed: %s\n", msg);
return EXIT_FAILURE;
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;
diff --git a/protocol/desktop-shell.xml b/protocol/desktop-shell.xml
index 3c3ead4..c40cf17 100644
--- a/protocol/desktop-shell.xml
+++ b/protocol/desktop-shell.xml
@@ -35,4 +35,17 @@
<event name="prepare_lock_surface"/>
</interface>
+ <!-- Only one client can bind this interface at a time. -->
+ <interface name="screensaver" version="1">
+
+ <!-- Set the surface type as a screensaver for a particular output.
+ A screensaver surface is normally hidden, and only visible after
+ an idle timeout. -->
+ <request name="set_surface">
+ <arg name="surface" type="object" interface="wl_shell_surface"/>
+ <arg name="output" type="object" interface="wl_output"/>
+ </request>
+
+ </interface>
+
</protocol>