This pulls in a bit of extra infrastructure for discovering adertised objects on the
client side.
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)
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
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)
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
EGLSurface surface;
};
-static int do_screenshot;
-
-static void
-handle_sigusr1(int s)
-{
- do_screenshot = 1;
-}
-
static void
die(const char *msg, ...)
{
}
}
+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;
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)
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);
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
EGLint major, minor, count;
struct egl_compositor *ec;
const char *filename;
+ struct screenshooter *shooter;
ec = malloc(sizeof *ec);
if (ec == NULL)
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);
if (device == NULL)
return NULL;
- device->base.id = id;
device->base.interface = &input_device_interface;
device->display = display;
device->tool = 1;
--- /dev/null
+#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;
+}
#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;
int fd;
uint32_t id;
uint32_t mask;
+ struct wl_list global_list;
wl_display_update_func_t update;
void *update_data;
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)
* 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,
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)
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 *
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;
wl_connection_write(surface->proxy.display->connection,
request, sizeof request);
}
-
wl_display_event_func_t handler,
void *data);
-
struct wl_surface *
wl_display_create_surface(struct wl_display *display);
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
{
/* 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;
+}
--- /dev/null
+#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
#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;
struct wl_list surface_list;
struct wl_list client_list;
uint32_t client_id_range;
+ uint32_t id;
struct wl_list global_list;
return;
}
- while (len > sizeof p) {
+ while (len >= sizeof p) {
wl_connection_copy(connection, p, sizeof p);
opcode = p[1] & 0xffff;
size = p[1] >> 16;
{
struct wl_client *client;
struct wl_object_ref *ref;
+ uint32_t count;
client = malloc(sizeof *client);
if (client == NULL)
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) {
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;
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);
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);
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)
{
#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,
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 {
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);