diff --git a/Makefile b/Makefile index f53e855c..3880b072 100644 --- 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 diff --git a/egl-compositor.c b/egl-compositor.c index 8c2cfdde..8d723b82 100644 --- a/egl-compositor.c +++ b/egl-compositor.c @@ -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 9df43071..f91b6859 100644 --- 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 index 00000000..7c69b858 --- /dev/null +++ b/screenshot.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/wayland-client.c b/wayland-client.c index 3e9ed424..16e97641 100644 --- a/wayland-client.c +++ b/wayland-client.c @@ -11,10 +11,17 @@ #include #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); } - diff --git a/wayland-client.h b/wayland-client.h index 138b0456..05f19b01 100644 --- a/wayland-client.h +++ b/wayland-client.h @@ -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 diff --git a/hash.c b/wayland-util.c similarity index 60% rename from hash.c rename to wayland-util.c index 80a14572..e763453e 100644 --- a/hash.c +++ b/wayland-util.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 index 00000000..035a4f53 --- /dev/null +++ b/wayland-util.h @@ -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 diff --git a/wayland.c b/wayland.c index 5da047e5..56395643 100644 --- a/wayland.c +++ b/wayland.c @@ -13,28 +13,6 @@ #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) { diff --git a/wayland.h b/wayland.h index ddfe0d21..d15229f6 100644 --- a/wayland.h +++ b/wayland.h @@ -2,28 +2,7 @@ #define WAYLAND_H #include - -/* 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);