Expose screenshooting as an interface, drop SIGUSR hack.
authorKristian Høgsberg <krh@redhat.com>
Mon, 24 Nov 2008 04:41:08 +0000 (23:41 -0500)
committerNaruto Uzumaki <root@kabuto.bos.redhat.com>
Mon, 24 Nov 2008 05:06:16 +0000 (00:06 -0500)
This pulls in a bit of extra infrastructure for discovering adertised objects on the
client side.

Makefile
egl-compositor.c
input.c
screenshot.c [new file with mode: 0644]
wayland-client.c
wayland-client.h
wayland-util.c [moved from hash.c with 60% similarity]
wayland-util.h [new file with mode: 0644]
wayland.c
wayland.h

index f53e855..3880b07 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ PKG_CONFIG_PATH ?= $(HOME)/install/lib/pkgconfig
 EAGLE_CFLAGS = $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --cflags eagle)
 EAGLE_LDLIBS = $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config --libs eagle)
 
-clients = flower pointer background window
+clients = flower pointer background window screenshot
 compositors = egl-compositor.so glx-compositor.so
 
 all : wayland libwayland.so $(compositors) $(clients)
@@ -14,8 +14,8 @@ wayland_objs =                                        \
        wayland.o                               \
        event-loop.o                            \
        connection.o                            \
-       hash.o                                  \
-       input.o
+       input.o                                 \
+       wayland-util.o
 
 wayland : CFLAGS += $(shell pkg-config --cflags libffi)
 wayland : LDLIBS += $(shell pkg-config --libs libffi) -ldl -rdynamic
@@ -23,7 +23,7 @@ wayland : LDLIBS += $(shell pkg-config --libs libffi) -ldl -rdynamic
 wayland : $(wayland_objs)
        gcc -o $@ $(LDLIBS) $(wayland_objs)
 
-libwayland_objs = wayland-client.o connection.o
+libwayland_objs = wayland-client.o connection.o wayland-util.o
 
 libwayland.so : $(libwayland_objs)
 
@@ -48,6 +48,7 @@ flower_objs = flower.o wayland-glib.o
 pointer_objs = pointer.o wayland-glib.o cairo-util.o
 background_objs = background.o wayland-glib.o
 window_objs = window.o gears.o wayland-glib.o cairo-util.o
+screenshot_objs = screenshot.o wayland-glib.o
 
 $(clients) : CFLAGS += $(shell pkg-config --cflags cairo glib-2.0)
 $(clients) : LDLIBS += $(shell pkg-config --libs cairo glib-2.0) -lrt
index 8c2cfdd..8d723b8 100644 (file)
@@ -43,14 +43,6 @@ struct egl_surface {
        EGLSurface surface;
 };
 
-static int do_screenshot;
-
-static void
-handle_sigusr1(int s)
-{
-       do_screenshot = 1;
-}
-
 static void
 die(const char *msg, ...)
 {
@@ -115,9 +107,15 @@ convert_pixels(png_structp png, png_row_infop row_info, png_bytep data)
        }
 }
 
+struct screenshooter {
+       struct wl_object base;
+       struct egl_compositor *ec;
+};
+
 static void
-screenshot(struct egl_compositor *ec)
+screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
 {
+       struct egl_compositor *ec = shooter->ec;
        png_struct *png;
        png_info *info;
        png_byte **volatile rows = NULL;
@@ -179,6 +177,31 @@ screenshot(struct egl_compositor *ec)
        free(data);
 }
 
+static const struct wl_method screenshooter_methods[] = {
+       { "shoot", screenshooter_shoot, 0, NULL }
+};
+
+static const struct wl_interface screenshooter_interface = {
+       "screenshooter", 1,
+       ARRAY_LENGTH(screenshooter_methods),
+       screenshooter_methods,
+};
+
+static struct screenshooter *
+screenshooter_create(struct egl_compositor *ec)
+{
+       struct screenshooter *shooter;
+
+       shooter = malloc(sizeof *shooter);
+       if (shooter == NULL)
+               return NULL;
+
+       shooter->base.interface = &screenshooter_interface;
+       shooter->ec = ec;
+
+       return shooter;
+};
+
 static struct egl_surface *
 egl_surface_create_from_cairo_surface(cairo_surface_t *surface,
                                      int x, int y, int width, int height)
@@ -387,7 +410,7 @@ overlay_create(int x, int y, int width, int height)
                                             width, height);
 
        cr = cairo_create(surface);
-       cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.7);
+       cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.8);
        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
        cairo_paint(cr);
 
@@ -469,17 +492,6 @@ repaint(void *data)
        draw_surface(ec->pointer);
 
        eglSwapBuffers(ec->display, ec->surface);
-
-       if (do_screenshot) {
-               glFinish();
-               /* FIXME: There's a bug somewhere so that glFinish()
-                * doesn't actually wait for all rendering to finish.
-                * I *think* it's fixed in upstream drm, but for my
-                * kernel I need this sleep now... */
-               sleep(1);
-               screenshot(ec);
-               do_screenshot = 0;
-       }
 }
 
 static void
@@ -637,6 +649,7 @@ wl_compositor_create(struct wl_display *display)
        EGLint major, minor, count;
        struct egl_compositor *ec;
        const char *filename;
+       struct screenshooter *shooter;
 
        ec = malloc(sizeof *ec);
        if (ec == NULL)
@@ -703,7 +716,9 @@ wl_compositor_create(struct wl_display *display)
                return NULL;
        }
 
-       signal(SIGUSR1, handle_sigusr1);
+       shooter = screenshooter_create(ec);
+       wl_display_add_object(display, &shooter->base);
+       wl_display_add_global(display, &shooter->base);
 
        schedule_repaint(ec);
 
diff --git a/input.c b/input.c
index 9df4307..f91b685 100644 (file)
--- a/input.c
+++ b/input.c
@@ -126,7 +126,6 @@ wl_input_device_create(struct wl_display *display,
        if (device == NULL)
                return NULL;
 
-       device->base.id = id;
        device->base.interface = &input_device_interface;
        device->display = display;
        device->tool = 1;
diff --git a/screenshot.c b/screenshot.c
new file mode 100644 (file)
index 0000000..7c69b85
--- /dev/null
@@ -0,0 +1,84 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include "wayland-client.h"
+#include "wayland-glib.h"
+
+/* The screenshooter is a good example of a custom object exposed by
+ * the compositor and serves as a test bed for implementing client
+ * side marshalling outside libwayland.so */
+
+static const char socket_name[] = "\0wayland";
+
+struct screenshooter {
+       uint32_t id;
+       struct wl_display *display;
+};
+
+static struct screenshooter *
+screenshooter_create(struct wl_display *display)
+{
+       struct screenshooter *screenshooter;
+       uint32_t id;
+
+       id = wl_display_get_object_id(display, "screenshooter");
+       if (id == 0) {
+               fprintf(stderr, "server doesn't support screenshooter interface\n");
+               return NULL;
+       }
+
+       screenshooter = malloc(sizeof screenshooter);
+       if (screenshooter == NULL)
+               return NULL;
+
+       screenshooter->id = id;
+       screenshooter->display = display;
+
+       return screenshooter;
+}
+
+#define SCREENSHOOTER_SHOOT 0
+
+static void
+screenshooter_shoot(struct screenshooter *screenshooter)
+{
+       uint32_t request[2];
+
+       request[0] = screenshooter->id;
+       request[1] = SCREENSHOOTER_SHOOT | ((sizeof request) << 16);
+
+       wl_display_write(screenshooter->display,
+                        request, sizeof request);
+}
+
+int main(int argc, char *argv[])
+{
+       struct wl_display *display;
+       GMainLoop *loop;
+       GSource *source;
+       struct screenshooter *s;
+
+       display = wl_display_create(socket_name);
+       if (display == NULL) {
+               fprintf(stderr, "failed to create display: %m\n");
+               return -1;
+       }
+
+       loop = g_main_loop_new(NULL, FALSE);
+       source = wayland_source_new(display);
+       g_source_attach(source, NULL);
+
+       s = screenshooter_create(display);
+       if (s == NULL)
+               exit(-1);
+
+       screenshooter_shoot(s);
+
+       g_main_loop_run(loop);
+
+       return 0;
+}
index 3e9ed42..16e9764 100644 (file)
 #include <sys/poll.h>
 
 #include "connection.h"
+#include "wayland-util.h"
 #include "wayland-client.h"
 
 static const char socket_name[] = "\0wayland";
 
+struct wl_global {
+       uint32_t id;
+       char *interface;
+       struct wl_list link;
+};
+
 struct wl_proxy {
        struct wl_display *display;
        uint32_t id;
@@ -26,6 +33,7 @@ struct wl_display {
        int fd;
        uint32_t id;
        uint32_t mask;
+       struct wl_list global_list;
 
        wl_display_update_func_t update;
        void *update_data;
@@ -56,10 +64,11 @@ WL_EXPORT struct wl_display *
 wl_display_create(const char *address)
 {
        struct wl_display *display;
+       struct wl_global *global;
        struct sockaddr_un name;
        socklen_t size;
        char buffer[256];
-       uint32_t id, length;
+       uint32_t id, length, count, i;
 
        display = malloc(sizeof *display);
        if (display == NULL)
@@ -87,13 +96,28 @@ wl_display_create(const char *address)
         * guess... */
        read(display->fd, &display->id, sizeof display->id);
 
-       /* FIXME: actually discover advertised objects here. */
-       read(display->fd, &id, sizeof id);
-       read(display->fd, &length, sizeof length);
-       read(display->fd, buffer, (length + 3) & ~3);
+       read(display->fd, &count, sizeof count);
+
+       wl_list_init(&display->global_list);
+       for (i = 0; i < count; i++) {
+               /* FIXME: actually discover advertised objects here. */
+               read(display->fd, &id, sizeof id);
+               read(display->fd, &length, sizeof length);
+               read(display->fd, buffer, (length + 3) & ~3);
+
+               global = malloc(sizeof *global);
+               if (global == NULL)
+                       return NULL;
+
+               global->id = id;
+               global->interface = malloc(length + 1);
+               memcpy(global->interface, buffer, length);
+               global->interface[length] = '\0';
+               wl_list_insert(display->global_list.prev, &global->link);
+       }
 
        display->proxy.display = display;
-       display->proxy.id = id;
+       display->proxy.id = wl_display_get_object_id(display, "display");
 
        display->connection = wl_connection_create(display->fd,
                                                   connection_update,
@@ -110,6 +134,24 @@ wl_display_destroy(struct wl_display *display)
        free(display);
 }
 
+WL_EXPORT uint32_t
+wl_display_get_object_id(struct wl_display *display, const char *interface)
+{
+       struct wl_global *global;
+
+       global = container_of(display->global_list.next,
+                             struct wl_global, link);
+       while (&global->link != &display->global_list) {
+               if (strcmp(global->interface, interface) == 0)
+                       return global->id;
+
+               global = container_of(global->link.next,
+                                     struct wl_global, link);
+       }
+
+       return 0;
+}
+
 WL_EXPORT int
 wl_display_get_fd(struct wl_display *display,
                  wl_display_update_func_t update, void *data)
@@ -171,6 +213,18 @@ wl_display_set_event_handler(struct wl_display *display,
        display->event_handler_data = data;
 }
 
+WL_EXPORT uint32_t
+wl_display_allocate_id(struct wl_display *display)
+{
+       return display->id++;
+}
+
+WL_EXPORT void
+wl_display_write(struct wl_display *display, const void *data, size_t count)
+{
+       wl_connection_write(display->connection, data, count);
+}
+
 #define WL_DISPLAY_CREATE_SURFACE 0
 
 WL_EXPORT struct wl_surface *
@@ -183,7 +237,7 @@ wl_display_create_surface(struct wl_display *display)
        if (surface == NULL)
                return NULL;
 
-       surface->proxy.id = display->id++;
+       surface->proxy.id = wl_display_allocate_id(display);
        surface->proxy.display = display;
 
        request[0] = display->proxy.id;
@@ -284,4 +338,3 @@ wl_surface_damage(struct wl_surface *surface,
        wl_connection_write(surface->proxy.display->connection,
                            request, sizeof request);
 }
-
index 138b045..05f19b0 100644 (file)
@@ -32,7 +32,6 @@ void wl_display_set_event_handler(struct wl_display *display,
                                  wl_display_event_func_t handler,
                                  void *data);
 
-
 struct wl_surface *
 wl_display_create_surface(struct wl_display *display);
 
@@ -47,4 +46,15 @@ void wl_surface_copy(struct wl_surface *surface, int32_t dst_x, int32_t dst_y,
 void wl_surface_damage(struct wl_surface *surface,
                       int32_t x, int32_t y, int32_t width, int32_t height);
 
+
+/* These entry points are for client side implementation of custom
+ * objects. */
+
+uint32_t wl_display_get_object_id(struct wl_display *display,
+                                 const char *interface);
+uint32_t wl_display_allocate_id(struct wl_display *display);
+void wl_display_write(struct wl_display *display,
+                     const void *data,
+                     size_t count);
+
 #endif
similarity index 60%
rename from hash.c
rename to wayland-util.c
index 80a1457..e763453 100644 (file)
--- a/hash.c
@@ -43,3 +43,41 @@ wl_hash_delete(struct wl_hash *hash, struct wl_object *object)
 {
        /* writeme */
 }
+
+
+void wl_list_init(struct wl_list *list)
+{
+       list->prev = list;
+       list->next = list;
+}
+
+void
+wl_list_insert(struct wl_list *list, struct wl_list *elm)
+{
+       elm->prev = list;
+       elm->next = list->next;
+       list->next = elm;
+       elm->next->prev = elm;
+}
+
+void
+wl_list_remove(struct wl_list *elm)
+{
+       elm->prev->next = elm->next;
+       elm->next->prev = elm->prev;
+}
+
+int
+wl_list_length(struct wl_list *list)
+{
+       struct wl_list *e;
+       int count;
+
+       e = list->next;
+       while (e != list) {
+               e = e->next;
+               count++;
+       }
+
+       return count;
+}
diff --git a/wayland-util.h b/wayland-util.h
new file mode 100644 (file)
index 0000000..035a4f5
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef WAYLAND_UTIL_H
+#define WAYLAND_UTIL_H
+
+/* GCC visibility */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define WL_EXPORT __attribute__ ((visibility("default")))
+#else
+#define WL_EXPORT
+#endif
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+#define container_of(ptr, type, member) ({                     \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct wl_hash {
+       struct wl_object **objects;
+       uint32_t count, alloc, id;
+};
+
+int wl_hash_insert(struct wl_hash *hash, struct wl_object *object);
+struct wl_object *wl_hash_lookup(struct wl_hash *hash, uint32_t id);
+void wl_hash_delete(struct wl_hash *hash, struct wl_object *object);
+
+struct wl_list {
+       struct wl_list *prev;
+       struct wl_list *next;
+};
+
+void wl_list_init(struct wl_list *list);
+void wl_list_insert(struct wl_list *list, struct wl_list *elm);
+void wl_list_remove(struct wl_list *elm);
+int wl_list_length(struct wl_list *list);
+
+
+#endif
index 5da047e..5639564 100644 (file)
--- a/wayland.c
+++ b/wayland.c
 #include "wayland.h"
 #include "connection.h"
 
-void wl_list_init(struct wl_list *list)
-{
-       list->prev = list;
-       list->next = list;
-}
-
-void
-wl_list_insert(struct wl_list *list, struct wl_list *elm)
-{
-       elm->prev = list;
-       elm->next = list->next;
-       list->next = elm;
-       elm->next->prev = elm;
-}
-
-void
-wl_list_remove(struct wl_list *elm)
-{
-       elm->prev->next = elm->next;
-       elm->next->prev = elm->prev;
-}
-
 struct wl_client {
        struct wl_connection *connection;
        struct wl_event_source *source;
@@ -56,6 +34,7 @@ struct wl_display {
        struct wl_list surface_list;
        struct wl_list client_list;
        uint32_t client_id_range;
+       uint32_t id;
 
        struct wl_list global_list;
 
@@ -359,7 +338,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
                return;
        }
 
-       while (len > sizeof p) {
+       while (len >= sizeof p) {
                wl_connection_copy(connection, p, sizeof p);
                opcode = p[1] & 0xffff;
                size = p[1] >> 16;
@@ -428,6 +407,7 @@ wl_client_create(struct wl_display *display, int fd)
 {
        struct wl_client *client;
        struct wl_object_ref *ref;
+       uint32_t count;
 
        client = malloc(sizeof *client);
        if (client == NULL)
@@ -448,6 +428,10 @@ wl_client_create(struct wl_display *display, int fd)
                            sizeof display->client_id_range);
        display->client_id_range += 256;
 
+       /* Write list of global objects to client. */
+       count = wl_list_length(&display->global_list);
+       wl_connection_write(client->connection, &count, sizeof count);
+       
        ref = container_of(display->global_list.next,
                           struct wl_object_ref, link);
        while (&ref->link != &display->global_list) {
@@ -542,7 +526,7 @@ wl_display_create_input_devices(struct wl_display *display)
        display->pointer = wl_input_device_create(display, path, 1);
 
        if (display->pointer != NULL)
-               wl_hash_insert(&display->objects, display->pointer);
+               wl_display_add_object(display, display->pointer);
 
        display->pointer_x = 100;
        display->pointer_y = 100;
@@ -563,9 +547,6 @@ wl_display_create(void)
                return NULL;
        }
 
-       display->base.id = 0;
-       display->base.interface = &display_interface;
-       wl_hash_insert(&display->objects, &display->base);
        wl_list_init(&display->surface_list);
        wl_list_init(&display->client_list);
        wl_list_init(&display->global_list);
@@ -574,6 +555,9 @@ wl_display_create(void)
 
        display->client_id_range = 256; /* Gah, arbitrary... */
 
+       display->id = 1;
+       display->base.interface = &display_interface;
+       wl_display_add_object(display, &display->base);
        if (wl_display_add_global(display, &display->base)) {
                wl_event_loop_destroy(display->loop);
                free(display);
@@ -583,6 +567,13 @@ wl_display_create(void)
        return display;         
 }
 
+WL_EXPORT void
+wl_display_add_object(struct wl_display *display, struct wl_object *object)
+{
+       object->id = display->id++;
+       wl_hash_insert(&display->objects, object);
+}
+
 WL_EXPORT int
 wl_display_add_global(struct wl_display *display, struct wl_object *object)
 {
index ddfe0d2..d15229f 100644 (file)
--- a/wayland.h
+++ b/wayland.h
@@ -2,28 +2,7 @@
 #define WAYLAND_H
 
 #include <stdint.h>
-
-/* GCC visibility */
-#if defined(__GNUC__) && __GNUC__ >= 4
-#define WL_EXPORT __attribute__ ((visibility("default")))
-#else
-#define WL_EXPORT
-#endif
-
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-
-#define container_of(ptr, type, member) ({                     \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
-
-struct wl_list {
-       struct wl_list *prev;
-       struct wl_list *next;
-};
-
-void wl_list_init(struct wl_list *list);
-void wl_list_insert(struct wl_list *list, struct wl_list *elm);
-void wl_list_remove(struct wl_list *elm);
+#include "wayland-util.h"
 
 enum {
        WL_EVENT_READABLE = 0x01,
@@ -52,15 +31,6 @@ struct wl_event_source *wl_event_loop_add_idle(struct wl_event_loop *loop,
                                               wl_event_loop_idle_func_t func,
                                               void *data);
 
-struct wl_hash {
-       struct wl_object **objects;
-       uint32_t count, alloc, id;
-};
-
-int wl_hash_insert(struct wl_hash *hash, struct wl_object *object);
-struct wl_object *wl_hash_lookup(struct wl_hash *hash, uint32_t id);
-void wl_hash_delete(struct wl_hash *hash, struct wl_object *object);
-
 struct wl_client;
 
 enum {
@@ -122,8 +92,11 @@ void wl_surface_iterator_destroy(struct wl_surface_iterator *iterator);
 struct wl_object *
 wl_input_device_create(struct wl_display *display,
                       const char *path, uint32_t id);
+void
+wl_display_add_object(struct wl_display *display, struct wl_object *object);
 int
 wl_display_add_global(struct wl_display *display, struct wl_object *object);
+
 void
 wl_display_post_relative_event(struct wl_display *display,
                               struct wl_object *source, int dx, int dy);