-CFLAGS = -Wall -g $(shell pkg-config --cflags libffi)
-LDLIBS = $(shell pkg-config --libs libffi)
+CFLAGS += -Wall -g $(shell pkg-config --cflags libffi libdrm)
+LDLIBS += $(shell pkg-config --libs libffi libdrm)
all : wayland client
-wayland_objs = wayland.o event-loop.o hash.o
+wayland_objs = wayland.o event-loop.o hash.o compositor.o
wayland : $(wayland_objs)
gcc -o $@ $(wayland_objs) $(LDLIBS)
+libwayland_objs = wayland-client.o
+
+libwayland.so : $(libwayland_objs)
+ gcc -o $@ $(libwayland_objs) -shared
+
client_objs = client.o
+client : CFLAGS += $(shell pkg-config --cflags cairo)
+client : LDLIBS += $(shell pkg-config --libs cairo)
-client : $(client_objs)
- gcc -o $@ $(client_objs)
+client : $(client_objs) libwayland.so
+ gcc -o $@ -L. -lwayland $(LDLIBS) $(client_objs)
clean :
- rm client wayland *.o
\ No newline at end of file
+ rm -f client wayland *.o libwayland.so
\ No newline at end of file
safe mode xservers, graphics text console. From gdm, we could also
launch a rdp session, solid ice sessions.
+All surface commands (copy, attach, map=set quads) are buffered until
+the client sends a commit command, which executes everything
+atomically...
+
ISSUES:
changing screen resolution, adding monitors.
+
RMI
+The wayland protocol is a async object oriented protocol. All
+requests are method invocations on some object. The request include
+an object id that uniquely identifies an object on the server. Each
+object implements an interface and the requests include an opcode that
+identifies which method in the interface to invoke.
+
+The server sends back events to the client, each event is emitted from
+an object. Events can be error conditions. The event includes the
+object id and the event opcode, from which the client can determine
+the type of event. Events are generated both in repsonse to a request
+(in which case the requet and the event constitutes a round trip) or
+spontanously when the server state changes.
+
the get_interface method is called on an object to get an object
handle that implements the specified interface.
\ No newline at end of file
-#include <stdlib.h>
#include <stdint.h>
-#include <stddef.h>
#include <stdio.h>
-#include <errno.h>
+#include <stdlib.h>
#include <string.h>
+#include <i915_drm.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <ctype.h>
+#include <math.h>
+#include <cairo.h>
+
+#include "wayland-client.h"
+static const char gem_device[] = "/dev/dri/card0";
static const char socket_name[] = "\0wayland";
-struct method {
- const char *name;
- uint32_t opcode;
-};
-
-static const struct method display_methods[] = {
- { "get_interface", 0 },
- { "create_surface", 1 },
- { NULL }
-};
-
-static const struct method surface_methods[] = {
- { "get_interface", 0 },
- { "post", 1 },
- { NULL }
-};
-
-struct interface {
- const char *name;
- const struct method *methods;
-};
-
-static const struct interface interfaces[] = {
- { "display", display_methods },
- { "surface", surface_methods },
- { NULL },
-};
-
-int send_request(int sock, const char *buffer, int buffer_len)
+static uint32_t name_cairo_surface(int fd, cairo_surface_t *surface)
{
- const struct method *methods;
- char interface[32], method[32];
- uint32_t request[3], id, new_id;
- int i;
-
- if (sscanf(buffer, "%d/%32[^:]:%32s %d\n",
- &id, interface, method, &new_id) != 4) {
- printf("invalid input, expected <id>/<interface>:<method>\n");
- return -1;
- }
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ struct drm_i915_gem_pwrite pwrite;
+ int32_t width, height, stride;
+
+ width = cairo_image_surface_get_width(surface);
+ height = cairo_image_surface_get_height(surface);
+ stride = cairo_image_surface_get_stride(surface);
- printf("got object id %d, interface \"%s\", name \"%s\"\n",
- id, interface, method);
+ memset(&create, 0, sizeof(create));
+ create.size = height * stride;
- for (i = 0; interfaces[i].name != NULL; i++) {
- if (strcmp(interfaces[i].name, interface) == 0)
- break;
+ if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+ fprintf(stderr, "gem create failed: %m\n");
+ return 0;
}
- if (interfaces[i].name == NULL) {
- printf("unknown interface \"%s\"\n", interface);
- return -1;
+
+ pwrite.handle = create.handle;
+ pwrite.offset = 0;
+ pwrite.size = height * stride;
+ pwrite.data_ptr = (uint64_t) (uintptr_t)
+ cairo_image_surface_get_data(surface);
+ if (ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite) < 0) {
+ fprintf(stderr, "gem pwrite failed: %m\n");
+ return 0;
}
- methods = interfaces[i].methods;
- for (i = 0; methods[i].name != NULL; i++) {
- if (strcmp(methods[i].name, method) == 0)
- break;
+ flink.handle = create.handle;
+ if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+ fprintf(stderr, "gem flink failed: %m\n");
+ return 0;
}
- if (methods[i].name == NULL) {
- printf("unknown request \"%s\"\n", method);
- return -1;
+#if 0
+ /* We need to hold on to the handle until the server has received
+ * the attach request... we probably need a confirmation event.
+ * I guess the breadcrumb idea will suffice. */
+ struct drm_gem_close close;
+ close.handle = create.handle;
+ if (ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) {
+ fprintf(stderr, "gem close failed: %m\n");
+ return 0;
}
+#endif
- request[0] = id;
- request[1] = methods[i].opcode;
- request[2] = new_id;
+ return flink.name;
+}
+
+static void *
+draw_stuff(int width, int height)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
- return write(sock, request, sizeof request);
+ surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+ width, height);
+
+ cr = cairo_create(surface);
+
+ cairo_arc(cr, width / 2, height / 2, width / 2 - 10, 0, 2 * M_PI);
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ cairo_fill_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 0);
+ cairo_stroke(cr);
+
+ cairo_arc(cr, width / 2, height / 2, width / 4 - 10, 0, 2 * M_PI);
+ cairo_set_source_rgb(cr, 0, 0, 1);
+ cairo_fill_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 0);
+ cairo_stroke(cr);
+
+ cairo_destroy(cr);
+
+ return surface;
}
int main(int argc, char *argv[])
{
- struct sockaddr_un name;
- socklen_t size;
- int sock, len;
- char buffer[256];
+ struct wl_connection *connection;
+ struct wl_display *display;
+ struct wl_surface *surface;
+ int width = 300, height = 300, fd;
+ uint32_t name;
+ cairo_surface_t *s;
+
+ fd = open(gem_device, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "drm open failed: %m\n");
+ return -1;
+ }
- sock = socket(PF_LOCAL, SOCK_STREAM, 0);
- if (sock < 0)
+ connection = wl_connection_create(socket_name);
+ if (connection == NULL) {
+ fprintf(stderr, "failed to create connection: %m\n");
return -1;
+ }
+
+ display = wl_connection_get_display(connection);
- name.sun_family = AF_LOCAL;
- memcpy(name.sun_path, socket_name, sizeof socket_name);
+ surface = wl_display_create_surface(display);
- size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
+ s = draw_stuff(width, height);
+ name = name_cairo_surface(fd, s);
- if (connect (sock, (struct sockaddr *) &name, size) < 0)
+ wl_surface_attach(surface, name, width, height,
+ cairo_image_surface_get_stride(s));
+
+ if (wl_connection_flush(connection) < 0) {
+ fprintf(stderr, "flush error: %m\n");
return -1;
+ }
- while (len = read(STDIN_FILENO, buffer, sizeof buffer), len > 0)
- if (send_request(sock, buffer, len) < 0)
- break;
+ while (1)
+ wl_connection_iterate(connection);
return 0;
}
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <i915_drm.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/fb.h>
+
+#include "wayland.h"
+
+struct lame_compositor {
+ struct wl_compositor base;
+ void *fb;
+ int32_t width, height, stride;
+ int gem_fd;
+};
+
+void notify_surface_create(struct wl_compositor *compositor,
+ struct wl_surface *surface)
+{
+}
+
+void notify_surface_attach(struct wl_compositor *compositor,
+ struct wl_surface *surface, uint32_t name,
+ uint32_t width, uint32_t height, uint32_t stride)
+{
+ struct lame_compositor *lc = (struct lame_compositor *) compositor;
+ struct drm_i915_gem_pread pread;
+ struct drm_gem_open open_arg;
+ struct drm_gem_close close_arg;
+ char *data, *dst;
+ int i, ret, x = 600, y = 200;
+
+ open_arg.name = name;
+ ret = ioctl(lc->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
+ if (ret != 0) {
+ fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, lc->gem_fd);
+ return;
+ }
+
+ data = malloc(open_arg.size);
+ if (data == NULL) {
+ fprintf(stderr, "swap buffers malloc failed\n");
+ return;
+ }
+
+ pread.size = open_arg.size;
+ pread.handle = open_arg.handle;
+ pread.pad = 0;
+ pread.offset = 0;
+ pread.size = stride * height;
+ pread.data_ptr = (long) data;
+
+ if (ioctl(lc->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
+ fprintf(stderr, "gem pread failed");
+ return;
+ }
+
+ dst = lc->fb + lc->stride * y + x * 4;
+ for (i = 0; i < height; i++)
+ memcpy(dst + lc->stride * i, data + stride * i, width * 4);
+
+ close_arg.handle = open_arg.handle;
+ ret = ioctl(lc->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
+ if (ret != 0) {
+ fprintf(stderr, "failed to gem_close name %d: %m\n", name);
+ }
+
+ free(data);
+}
+
+struct wl_compositor_interface interface = {
+ notify_surface_create,
+ notify_surface_attach
+};
+
+static const char fb_device[] = "/dev/fb";
+static const char gem_device[] = "/dev/dri/card0";
+
+struct wl_compositor *
+wl_compositor_create(void)
+{
+ struct lame_compositor *lc;
+ struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+ int fd;
+
+ lc = malloc(sizeof *lc);
+ if (lc == NULL)
+ return NULL;
+
+ lc->base.interface = &interface;
+
+ fd = open(fb_device, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "open %s failed: %m\n", fb_device);
+ return NULL;
+ }
+
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) {
+ fprintf(stderr, "fb get fixed failed\n");
+ return NULL;
+ }
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) {
+ fprintf(stderr, "fb get fixed failed\n");
+ return NULL;
+ }
+
+ lc->stride = fix.line_length;
+ lc->width = var.xres;
+ lc->height = var.yres;
+ lc->fb = mmap(NULL, lc->stride * lc->height,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ close(fd);
+ if (lc->fb == MAP_FAILED) {
+ fprintf(stderr, "fb map failed\n");
+ return NULL;
+ }
+
+ lc->gem_fd = open(gem_device, O_RDWR);
+ if (lc->gem_fd < 0) {
+ fprintf(stderr, "failed to open drm device\n");
+ return NULL;
+ }
+
+ return &lc->base;
+}
return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
}
+int
+wl_event_loop_update_source(struct wl_event_loop *loop,
+ struct wl_event_source *source,
+ uint32_t mask)
+{
+ struct epoll_event ep;
+
+ ep.events = 0;
+ if (mask & WL_EVENT_READABLE)
+ ep.events |= EPOLLIN;
+ if (mask & WL_EVENT_WRITEABLE)
+ ep.events |= EPOLLOUT;
+ ep.data.ptr = source;
+
+ return epoll_ctl(loop->epoll_fd,
+ EPOLL_CTL_MOD, source->fd, &ep);
+}
+
struct wl_event_loop *
wl_event_loop_create(void)
{
struct epoll_event ep[32];
struct wl_event_source *source;
int i, count;
+ uint32_t mask;
count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), -1);
if (count < 0)
for (i = 0; i < count; i++) {
source = ep[i].data.ptr;
- source->func(source->fd, ep[i].events, source->data);
+ mask = 0;
+ if (ep[i].events & EPOLLIN)
+ mask |= WL_EVENT_READABLE;
+ if (ep[i].events & EPOLLOUT)
+ mask |= WL_EVENT_WRITEABLE;
+
+ source->func(source->fd, mask, source->data);
}
return 0;
--- /dev/null
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <sys/poll.h>
+
+static const char socket_name[] = "\0wayland";
+
+struct wl_buffer {
+ char data[4096];
+ int head, tail;
+};
+
+struct wl_connection {
+ int fd;
+ struct wl_buffer in, out;
+ struct wl_display *display;
+ uint32_t id;
+};
+
+struct wl_proxy {
+ struct wl_connection *connection;
+ uint32_t id;
+};
+
+struct wl_display {
+ struct wl_proxy proxy;
+};
+
+struct wl_surface {
+ struct wl_proxy proxy;
+};
+
+struct wl_connection *
+wl_connection_create(const char *address)
+{
+ struct wl_connection *connection;
+ struct wl_display *display;
+ struct sockaddr_un name;
+ socklen_t size;
+ char buffer[256];
+ uint32_t id, length;
+
+ connection = malloc(sizeof *connection);
+ if (connection == NULL)
+ return NULL;
+
+ memset(connection, 0, sizeof *connection);
+ connection->id = 256; /* Need to get our id-range. */
+ connection->fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (connection->fd < 0) {
+ free(connection);
+ return NULL;
+ }
+
+ name.sun_family = AF_LOCAL;
+ memcpy(name.sun_path, address, strlen(address + 1) + 2);
+
+ size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
+
+ if (connect (connection->fd, (struct sockaddr *) &name, size) < 0) {
+ close(connection->fd);
+ free(connection);
+ return NULL;
+ }
+
+ /* FIXME: actually discover advertised objects here. */
+ read(connection->fd, &id, sizeof id);
+ read(connection->fd, &length, sizeof length);
+ read(connection->fd, buffer, (length + 3) & ~3);
+
+ display = malloc(sizeof *display);
+ display->proxy.connection = connection;
+ display->proxy.id = id;
+ connection->display = display;
+
+ return connection;
+}
+
+void
+wl_connection_destroy(struct wl_connection *connection)
+{
+ close(connection->fd);
+ free(connection->display);
+ free(connection);
+}
+
+int
+wl_connection_get_fd(struct wl_connection *connection)
+{
+ return connection->fd;
+}
+
+static void
+handle_event(struct wl_connection *connection)
+{
+ struct wl_buffer *b;
+ uint32_t *p, opcode, size;
+
+ b = &connection->in;
+ p = (uint32_t *) (b->data + b->tail);
+ opcode = p[1] & 0xffff;
+ size = p[1] >> 16;
+ printf("signal from object %d, opcode %d, size %d\n",
+ p[0], opcode, size);
+ b->tail += size;
+}
+
+void
+wl_connection_iterate(struct wl_connection *connection)
+{
+ struct wl_buffer *b;
+ uint32_t *p, opcode, size;
+ int len;
+
+ b = &connection->in;
+ len = read(connection->fd, b->data + b->head, sizeof b->data);
+ b->head += len;
+ while (len > 0) {
+
+ if (b->head - b->tail < 8)
+ break;
+
+ p = (uint32_t *) (b->data + b->tail);
+ opcode = p[1] & 0xffff;
+ size = p[1] >> 16;
+ if (b->head - b->tail < size)
+ break;
+
+ handle_event(connection);
+ }
+
+ if (len < 0) {
+ fprintf(stderr, "read error: %m\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+int
+wl_connection_flush(struct wl_connection *connection)
+{
+ struct wl_buffer *b;
+ int len;
+
+ b = &connection->out;
+ if (b->head == b->tail)
+ return 0;
+
+ len = write(connection->fd, b->data + b->tail, b->head - b->tail);
+ b->tail += len;
+
+ return len;
+};
+
+struct wl_display *
+wl_connection_get_display(struct wl_connection *connection)
+{
+ return connection->display;
+}
+
+#define WL_DISPLAY_CREATE_SURFACE 0
+
+struct wl_surface *
+wl_display_create_surface(struct wl_display *display)
+{
+ struct wl_surface *surface;
+ struct wl_connection *connection;
+ uint32_t request[3];
+
+ surface = malloc(sizeof *surface);
+ if (surface == NULL)
+ return NULL;
+
+ connection = display->proxy.connection;
+ surface->proxy.id = connection->id++;
+ surface->proxy.connection = connection;
+
+ request[0] = display->proxy.id;
+ request[1] = WL_DISPLAY_CREATE_SURFACE | ((sizeof request) << 16);
+ request[2] = surface->proxy.id;
+
+ memcpy(connection->out.data + connection->out.head,
+ request, sizeof request);
+ connection->out.head += sizeof request;
+
+ return surface;
+}
+
+#define WL_SURFACE_ATTACH 0
+
+void wl_surface_attach(struct wl_surface *surface,
+ uint32_t name, int width, int height, int stride)
+{
+ uint32_t request[6];
+ struct wl_connection *connection;
+
+ request[0] = surface->proxy.id;
+ request[1] = WL_SURFACE_ATTACH | ((sizeof request) << 16);
+ request[2] = name;
+ request[3] = width;
+ request[4] = height;
+ request[5] = stride;
+
+ connection = surface->proxy.connection;
+ memcpy(connection->out.data + connection->out.head,
+ request, sizeof request);
+ connection->out.head += sizeof request;
+}
--- /dev/null
+#ifndef _WAYLAND_CLIENT_H
+#define _WAYLAND_CLIENT_H
+
+struct wl_connection;
+struct wl_display;
+struct wl_surface;
+
+struct wl_connection *
+wl_connection_create(const char *address);
+void
+wl_connection_destroy(struct wl_connection *connection);
+int
+wl_connection_get_fd(struct wl_connection *connection);
+void
+wl_connection_iterate(struct wl_connection *connection);
+int
+wl_connection_flush(struct wl_connection *connection);
+
+struct wl_display *
+wl_connection_get_display(struct wl_connection *connection);
+struct wl_surface *
+wl_display_create_surface(struct wl_display *display);
+
+void
+wl_surface_attach(struct wl_surface *surface,
+ uint32_t name, int width, int height, int stride);
+
+#endif
struct wl_region {
};
+struct wl_buffer {
+ char data[4096];
+ int head, tail;
+};
+
struct wl_client {
- char protocol_buffer[4096];
+ struct wl_buffer input, output;
struct wl_event_source *source;
struct wl_display *display;
};
struct wl_object base;
struct wl_event_loop *loop;
struct wl_hash objects;
+
+ struct wl_compositor *compositor;
+ struct wl_compositor_interface *compositor_interface;
};
struct wl_surface {
};
static void
-wl_surface_get_interface(struct wl_client *client,
- struct wl_surface *surface,
- const char *interface, uint32_t id)
+wl_surface_attach(struct wl_client *client,
+ struct wl_surface *surface, uint32_t name,
+ uint32_t width, uint32_t height, uint32_t stride)
{
- /* client sends a new object id, and an interface identifier
- * to name the object that implements the interface */
- printf("surface::get_interface\n");
-}
+ struct wl_compositor_interface *interface;
-static const struct wl_argument get_interface_arguments[] = {
- { WL_ARGUMENT_STRING },
- { WL_ARGUMENT_NEW_ID }
-};
-
-static void
-wl_surface_post(struct wl_client *client,
- struct wl_surface *surface, uint32_t name,
- uint32_t width, uint32_t height, uint32_t stride)
-{
- printf("surface::post\n");
+ interface = client->display->compositor->interface;
+ interface->notify_surface_attach(client->display->compositor,
+ surface, name, width, height, stride);
}
-static const struct wl_argument post_arguments[] = {
+static const struct wl_argument attach_arguments[] = {
{ WL_ARGUMENT_UINT32 },
{ WL_ARGUMENT_UINT32 },
{ WL_ARGUMENT_UINT32 },
};
static const struct wl_method surface_methods[] = {
- { "get_interface", wl_surface_get_interface,
- ARRAY_LENGTH(get_interface_arguments), get_interface_arguments },
- { "post", wl_surface_post,
- ARRAY_LENGTH(post_arguments), post_arguments }
+ { "attach", wl_surface_attach,
+ ARRAY_LENGTH(attach_arguments), attach_arguments }
};
static const struct wl_interface surface_interface = {
wl_surface_create(struct wl_display *display, uint32_t id)
{
struct wl_surface *surface;
+ struct wl_compositor_interface *interface;
surface = malloc(sizeof *surface);
if (surface == NULL)
surface->base.id = id;
surface->base.interface = &surface_interface;
- /* doesn't create any pixel buffers, just the wl_surface
- * object. the client allocates and attaches pixel buffers
- * itself and renders to them, then posts them using
- * wl_window_post. */
- /* add to display list */
+ interface = display->compositor->interface;
+ interface->notify_surface_create(display->compositor, surface);
return surface;
}
static void
wl_client_data(int fd, uint32_t mask, void *data);
+static int
+advertise_object(struct wl_client *client, struct wl_object *object)
+{
+ const struct wl_interface *interface;
+ uint32_t length, *p;
+
+ interface = object->interface;
+ p = (uint32_t *) (client->output.data + client->output.head);
+ length = strlen(interface->name);
+ *p++ = object->id;
+ *p++ = length;
+ memcpy(p, interface->name, length);
+ memset((char *) p + length, 0, -length & 3);
+ client->output.head += 8 + ((length + 3) & ~3);
+
+ wl_event_loop_update_source(client->display->loop, client->source,
+ WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
+
+
+ return 0;
+}
+
struct wl_client *
wl_client_create(struct wl_display *display, int fd)
{
if (client == NULL)
return NULL;
+ memset(client, 0, sizeof *client);
client->display = display;
-
client->source = wl_event_loop_add_fd(display->loop, fd,
- WL_EVENT_READABLE |
WL_EVENT_READABLE,
wl_client_data, client);
- printf("new client: %p\n", client);
-
- /* Send global objects to client in hand shake response, eg:
- *
- * display: 0,
- * glyph_cache: 1
- * some other extension global object: 2
- *
- * etc */
+ advertise_object(client, &display->base);
return client;
}
static void
demarshal(struct wl_client *client, struct wl_object *target,
- const struct wl_method *method, uint32_t *data, int len)
+ const struct wl_method *method, uint32_t *data)
{
ffi_type *types[10];
ffi_cif cif;
case WL_ARGUMENT_UINT32:
types[i + 2] = &ffi_type_uint32;
values[i + 2].uint32 = *p;
- printf("got uint32 (%d)\n", *p);
p++;
break;
case WL_ARGUMENT_STRING:
- printf("got string\n");
types[i + 2] = &ffi_type_pointer;
/* FIXME */
values[i + 2].uint32 = *p++;
if (object->interface != method->arguments[i].data)
printf("wrong object type\n");
values[i + 2].object = object;
- printf("got object (%d)\n", *p);
p++;
break;
case WL_ARGUMENT_NEW_ID:
object = wl_hash_lookup(&client->display->objects, *p);
if (object != NULL)
printf("object already exists (%d)\n", *p);
- printf("got new_id (%d)\n", *p);
p++;
break;
default:
ffi_call(&cif, FFI_FN(method->func), &result, args);
}
+static void
+wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
+{
+ const struct wl_interface *interface;
+ uint32_t *p;
+
+ interface = object->interface;
+
+ p = (void *) client->output.data + client->output.head;
+ p[0] = object->id;
+ p[1] = event | (8 << 16);
+ client->output.head += 8;
+ wl_event_loop_update_source(client->display->loop, client->source,
+ WL_EVENT_READABLE | WL_EVENT_WRITEABLE);
+}
+
+#define WL_DISPLAY_INVALID_OBJECT 0
+#define WL_DISPLAY_INVALID_METHOD 1
+
+static void
+wl_client_process_input(struct wl_client *client)
+{
+ const struct wl_method *method;
+ struct wl_object *object;
+ uint32_t *p, opcode, size;
+
+ while (1) {
+ if (client->input.head - client->input.tail < 2 * sizeof *p)
+ break;
+
+ p = (uint32_t *) (client->input.data + client->input.tail);
+ opcode = p[1] & 0xffff;
+ size = p[1] >> 16;
+ if (client->input.head - client->input.tail < size)
+ break;
+
+ object = wl_hash_lookup(&client->display->objects,
+ p[0]);
+ if (object == NULL) {
+ wl_client_event(client, &client->display->base,
+ WL_DISPLAY_INVALID_OBJECT);
+ client->input.tail += size;
+ continue;
+ }
+
+ if (opcode >= object->interface->method_count) {
+ wl_client_event(client, &client->display->base,
+ WL_DISPLAY_INVALID_METHOD);
+ client->input.tail += size;
+ continue;
+ }
+
+ method = &object->interface->methods[opcode];
+ demarshal(client, object, method, p + 2);
+ client->input.tail += size;
+ }
+}
+
static void
wl_client_data(int fd, uint32_t mask, void *data)
{
struct wl_client *client = data;
- struct wl_object *object;
- const struct wl_method *method;
- char buffer[256];
- uint32_t *p;
int len;
if (mask & WL_EVENT_READABLE) {
- len = read(fd, buffer, sizeof buffer);
- if (len == 0) {
- wl_client_destroy(client);
+ len = read(fd, client->input.data, sizeof client->input.data);
+ if (len > 0) {
+ client->input.head += len;
+ wl_client_process_input(client);
+ } else if (len == 0 && errno == ECONNRESET) {
+ fprintf(stderr,
+ "read from client %p: %m (%d)\n",
+ client, errno);
} else {
- printf("got %d bytes from client %p\n",
- len, client);
- if (len < 2 * sizeof *p)
- /* read more... */
- return;
-
- p = (uint32_t *) buffer;
- object = wl_hash_lookup(&client->display->objects,
- p[0]);
- if (object == NULL) {
- /* send error */
- printf("invalid object\n");
- return;
- }
-
- if (p[1] >= object->interface->method_count) {
- /* send error */
- printf("invalid method\n");
- return;
- }
-
- method = &object->interface->methods[p[1]];
- printf("calling method %s on interface %s\n",
- method->name, object->interface->name);
- demarshal(client, object, method, p + 2, len - 8);
+ wl_client_destroy(client);
}
}
if (mask & WL_EVENT_WRITEABLE) {
+ len = write(fd, client->output.data + client->output.tail,
+ client->output.head - client->output.tail);
+ client->output.tail += len;
+
+ if (client->output.tail == client->output.head)
+ wl_event_loop_update_source(client->display->loop,
+ client->source,
+ WL_EVENT_READABLE);
}
}
-static void
-wl_display_get_interface(struct wl_client *client,
- struct wl_display *display,
- const char *interface, uint32_t id)
-{
- /* client sends a new object id, and an interface identifier
- * to name the object that implements the interface */
- printf("display::get_interface\n");
-}
-
static int
wl_display_create_surface(struct wl_client *client,
struct wl_display *display, uint32_t id)
{
struct wl_surface *surface;
- printf("display::create_surface, client %p, display %p, new_id=%d\n",
- client, display, id);
-
surface = wl_surface_create(display, id);
wl_hash_insert(&display->objects, &surface->base);
+ /* FIXME: garbage collect client resources when client exits. */
+
return 0;
}
};
static const struct wl_method display_methods[] = {
- { "get_interface", wl_display_get_interface,
- ARRAY_LENGTH(get_interface_arguments), get_interface_arguments },
{ "create_surface", wl_display_create_surface,
ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
};
+static const struct wl_event display_events[] = {
+ { "invalid_object" },
+ { "invalid_method" },
+};
+
static const struct wl_interface display_interface = {
- "display", 1, ARRAY_LENGTH(display_methods), display_methods,
+ "display", 1,
+ ARRAY_LENGTH(display_methods), display_methods,
+ ARRAY_LENGTH(display_events), display_events,
};
struct wl_display *
return display;
}
+void
+wl_display_set_compositor(struct wl_display *display,
+ struct wl_compositor *compositor)
+{
+ display->compositor = compositor;
+}
+
void
wl_display_run(struct wl_display *display)
{
if (listen(sock, 1) < 0)
return -1;
- wl_event_loop_add_fd(display->loop, sock, WL_EVENT_READABLE,
+ wl_event_loop_add_fd(display->loop, sock,
+ WL_EVENT_READABLE,
socket_data, display);
return 0;
int main(int argc, char *argv[])
{
struct wl_display *display;
+ struct wl_compositor *compositor;
display = wl_display_create();
exit(EXIT_FAILURE);
}
+ compositor = wl_compositor_create();
+ wl_display_set_compositor(display, compositor);
+
printf("wayland online, display is %p\n", display);
wl_display_run(display);
int fd, uint32_t mask,
wl_event_loop_func_t func,
void *data);
+int wl_event_loop_update_source(struct wl_event_loop *loop,
+ struct wl_event_source *source,
+ uint32_t mask);
+
int wl_event_loop_remove_source(struct wl_event_loop *loop,
struct wl_event_source *source);
int wl_event_loop_wait(struct wl_event_loop *loop);
const struct wl_argument *arguments;
};
+struct wl_event {
+ const char *name;
+};
+
struct wl_interface {
const char *name;
int version;
int method_count;
const struct wl_method *methods;
+ int event_count;
+ const struct wl_event *events;
};
struct wl_object {
uint32_t id;
};
+struct wl_surface;
+struct wl_display;
+
+struct wl_compositor {
+ struct wl_compositor_interface *interface;
+};
+
+struct wl_compositor_interface {
+ void (*notify_surface_create)(struct wl_compositor *compositor,
+ struct wl_surface *surface);
+
+ void (*notify_surface_attach)(struct wl_compositor *compositor,
+ struct wl_surface *surface, uint32_t name,
+ uint32_t width, uint32_t height, uint32_t stride);
+};
+
+struct wl_compositor *wl_compositor_create(void);
+
+void wl_display_set_compositor(struct wl_display *display,
+ struct wl_compositor *compositor);
+
+
#endif