summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2011-08-12 15:09:00 -0400
committerKristian Høgsberg <krh@bitplanet.net>2011-08-12 16:25:14 -0400
commit4c260db68c028f05401727d1911582ae8b87cd70 (patch)
tree89d6d7fdfa7e1eb7ee39194a38d6711cde66e6bc /src
parent3733157d55df862ad5a89d1911a0500af67e7e08 (diff)
Rename source subdir from wayland to src
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore4
-rw-r--r--src/Makefile.am63
-rw-r--r--src/connection.c749
-rw-r--r--src/connection.h68
-rw-r--r--src/event-loop.c465
-rw-r--r--src/scanner.c868
-rw-r--r--src/scanner.mk8
-rw-r--r--src/wayland-client.c604
-rw-r--r--src/wayland-client.h90
-rw-r--r--src/wayland-client.pc.in10
-rw-r--r--src/wayland-egl.h68
-rw-r--r--src/wayland-hash.c296
-rw-r--r--src/wayland-server.c933
-rw-r--r--src/wayland-server.h307
-rw-r--r--src/wayland-server.pc.in10
-rw-r--r--src/wayland-shm.c223
-rw-r--r--src/wayland-util.c123
-rw-r--r--src/wayland-util.h152
18 files changed, 5041 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..1813f89
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,4 @@
+wayland-scanner
+wayland-client-protocol.h
+wayland-protocol.c
+wayland-server-protocol.h
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..156ca2e
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,63 @@
+lib_LTLIBRARIES = libwayland-server.la libwayland-client.la
+noinst_LTLIBRARIES = libwayland-util.la
+
+include_HEADERS = \
+ wayland-util.h \
+ wayland-server-protocol.h \
+ wayland-server.h \
+ wayland-client-protocol.h \
+ wayland-client.h \
+ wayland-egl.h
+
+libwayland_util_la_SOURCES = \
+ connection.c \
+ connection.h \
+ wayland-util.c \
+ wayland-util.h \
+ wayland-hash.c
+
+libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt
+libwayland_server_la_SOURCES = \
+ wayland-protocol.c \
+ wayland-server.c \
+ wayland-shm.c \
+ event-loop.c
+
+libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-util.la -lrt
+libwayland_client_la_SOURCES = \
+ wayland-protocol.c \
+ wayland-client.c
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = wayland-client.pc wayland-server.pc
+
+AM_CPPFLAGS = $(FFI_CFLAGS)
+AM_CFLAGS = $(GCC_CFLAGS)
+
+protocoldir = $(top_srcdir)/protocol
+
+if ENABLE_SCANNER
+wayland_scanner = $(top_builddir)/src/wayland-scanner
+else
+wayland_scanner = wayland-scanner
+endif
+
+include $(top_srcdir)/src/scanner.mk
+
+if ENABLE_SCANNER
+bin_PROGRAMS = wayland-scanner
+
+wayland_scanner_SOURCES = \
+ scanner.c
+
+wayland_scanner_LDADD = $(EXPAT_LIBS) libwayland-util.la
+
+$(BUILT_SOURCES) : wayland-scanner
+endif
+
+BUILT_SOURCES = \
+ wayland-server-protocol.h \
+ wayland-client-protocol.h \
+ wayland-protocol.c
+
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/connection.c b/src/connection.c
new file mode 100644
index 0000000..467a2d0
--- /dev/null
+++ b/src/connection.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <ffi.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+
+#include "wayland-util.h"
+#include "connection.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+struct wl_buffer {
+ char data[4096];
+ int head, tail;
+};
+
+#define MASK(i) ((i) & 4095)
+
+struct wl_closure {
+ int count;
+ const struct wl_message *message;
+ ffi_type *types[20];
+ ffi_cif cif;
+ void *args[20];
+ uint32_t buffer[64];
+ uint32_t *start;
+};
+
+struct wl_connection {
+ struct wl_buffer in, out;
+ struct wl_buffer fds_in, fds_out;
+ int fd;
+ void *data;
+ wl_connection_update_func_t update;
+ struct wl_closure receive_closure, send_closure;
+};
+
+union wl_value {
+ uint32_t uint32;
+ char *string;
+ struct wl_object *object;
+ uint32_t new_id;
+ struct wl_array *array;
+};
+
+static void
+wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
+{
+ int head, size;
+
+ head = MASK(b->head);
+ if (head + count <= sizeof b->data) {
+ memcpy(b->data + head, data, count);
+ } else {
+ size = sizeof b->data - head;
+ memcpy(b->data + head, data, size);
+ memcpy(b->data, (const char *) data + size, count - size);
+ }
+
+ b->head += count;
+}
+
+static void
+wl_buffer_put_iov(struct wl_buffer *b, struct iovec *iov, int *count)
+{
+ int head, tail;
+
+ head = MASK(b->head);
+ tail = MASK(b->tail);
+ if (head < tail) {
+ iov[0].iov_base = b->data + head;
+ iov[0].iov_len = tail - head;
+ *count = 1;
+ } else if (tail == 0) {
+ iov[0].iov_base = b->data + head;
+ iov[0].iov_len = sizeof b->data - head;
+ *count = 1;
+ } else {
+ iov[0].iov_base = b->data + head;
+ iov[0].iov_len = sizeof b->data - head;
+ iov[1].iov_base = b->data;
+ iov[1].iov_len = tail;
+ *count = 2;
+ }
+}
+
+static void
+wl_buffer_get_iov(struct wl_buffer *b, struct iovec *iov, int *count)
+{
+ int head, tail;
+
+ head = MASK(b->head);
+ tail = MASK(b->tail);
+ if (tail < head) {
+ iov[0].iov_base = b->data + tail;
+ iov[0].iov_len = head - tail;
+ *count = 1;
+ } else if (head == 0) {
+ iov[0].iov_base = b->data + tail;
+ iov[0].iov_len = sizeof b->data - tail;
+ *count = 1;
+ } else {
+ iov[0].iov_base = b->data + tail;
+ iov[0].iov_len = sizeof b->data - tail;
+ iov[1].iov_base = b->data;
+ iov[1].iov_len = head;
+ *count = 2;
+ }
+}
+
+static void
+wl_buffer_copy(struct wl_buffer *b, void *data, size_t count)
+{
+ int tail, size;
+
+ tail = MASK(b->tail);
+ if (tail + count <= sizeof b->data) {
+ memcpy(data, b->data + tail, count);
+ } else {
+ size = sizeof b->data - tail;
+ memcpy(data, b->data + tail, size);
+ memcpy((char *) data + size, b->data, count - size);
+ }
+}
+
+struct wl_connection *
+wl_connection_create(int fd,
+ wl_connection_update_func_t update,
+ void *data)
+{
+ struct wl_connection *connection;
+
+ connection = malloc(sizeof *connection);
+ if (connection == NULL)
+ return NULL;
+ memset(connection, 0, sizeof *connection);
+ connection->fd = fd;
+ connection->update = update;
+ connection->data = data;
+
+ connection->update(connection,
+ WL_CONNECTION_READABLE,
+ connection->data);
+
+ return connection;
+}
+
+void
+wl_connection_destroy(struct wl_connection *connection)
+{
+ close(connection->fd);
+ free(connection);
+}
+
+void
+wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
+{
+ wl_buffer_copy(&connection->in, data, size);
+}
+
+void
+wl_connection_consume(struct wl_connection *connection, size_t size)
+{
+ connection->in.tail += size;
+}
+
+static void
+build_cmsg(struct wl_buffer *buffer, char *data, int *clen)
+{
+ struct cmsghdr *cmsg;
+ size_t size;
+
+ size = buffer->head - buffer->tail;
+ if (size > 0) {
+ cmsg = (struct cmsghdr *) data;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(size);
+ wl_buffer_copy(buffer, CMSG_DATA(cmsg), size);
+ *clen = cmsg->cmsg_len;
+ } else {
+ *clen = 0;
+ }
+}
+
+static void
+close_fds(struct wl_buffer *buffer)
+{
+ int fds[32], i, count;
+ size_t size;
+
+ size = buffer->head - buffer->tail;
+ if (size == 0)
+ return;
+
+ wl_buffer_copy(buffer, fds, size);
+ count = size / sizeof fds[0];
+ for (i = 0; i < count; i++)
+ close(fds[i]);
+ buffer->tail += size;
+}
+
+static void
+decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
+{
+ struct cmsghdr *cmsg;
+ size_t size;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ size = cmsg->cmsg_len - CMSG_LEN(0);
+ wl_buffer_put(buffer, CMSG_DATA(cmsg), size);
+ }
+ }
+}
+
+int
+wl_connection_data(struct wl_connection *connection, uint32_t mask)
+{
+ struct iovec iov[2];
+ struct msghdr msg;
+ char cmsg[128];
+ int len, count, clen;
+
+ if (mask & WL_CONNECTION_WRITABLE) {
+ wl_buffer_get_iov(&connection->out, iov, &count);
+
+ build_cmsg(&connection->fds_out, cmsg, &clen);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = count;
+ msg.msg_control = cmsg;
+ msg.msg_controllen = clen;
+ msg.msg_flags = 0;
+
+ do {
+ len = sendmsg(connection->fd, &msg, MSG_NOSIGNAL);
+ } while (len < 0 && errno == EINTR);
+
+ if (len == -1 && errno == EPIPE) {
+ return -1;
+ } else if (len < 0) {
+ fprintf(stderr,
+ "write error for connection %p, fd %d: %m\n",
+ connection, connection->fd);
+ return -1;
+ }
+
+ close_fds(&connection->fds_out);
+
+ connection->out.tail += len;
+ if (connection->out.tail == connection->out.head)
+ connection->update(connection,
+ WL_CONNECTION_READABLE,
+ connection->data);
+ }
+
+ if (mask & WL_CONNECTION_READABLE) {
+ wl_buffer_put_iov(&connection->in, iov, &count);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = count;
+ msg.msg_control = cmsg;
+ msg.msg_controllen = sizeof cmsg;
+ msg.msg_flags = 0;
+
+ do {
+ len = recvmsg(connection->fd, &msg, MSG_CMSG_CLOEXEC);
+ } while (len < 0 && errno == EINTR);
+
+ if (len < 0) {
+ fprintf(stderr,
+ "read error from connection %p: %m (%d)\n",
+ connection, errno);
+ return -1;
+ } else if (len == 0) {
+ /* FIXME: Handle this better? */
+ return -1;
+ }
+
+ decode_cmsg(&connection->fds_in, &msg);
+
+ connection->in.head += len;
+ }
+
+ return connection->in.head - connection->in.tail;
+}
+
+void
+wl_connection_write(struct wl_connection *connection,
+ const void *data, size_t count)
+{
+ if (connection->out.head - connection->out.tail +
+ count > ARRAY_LENGTH(connection->out.data))
+ wl_connection_data(connection, WL_CONNECTION_WRITABLE);
+
+ wl_buffer_put(&connection->out, data, count);
+
+ if (connection->out.head - connection->out.tail == count)
+ connection->update(connection,
+ WL_CONNECTION_READABLE |
+ WL_CONNECTION_WRITABLE,
+ connection->data);
+}
+
+static int
+wl_message_size_extra(const struct wl_message *message)
+{
+ int i, extra;
+
+ for (i = 0, extra = 0; message->signature[i]; i++) {
+
+ switch (message->signature[i]) {
+ case 's':
+ case 'o':
+ extra += sizeof (void *);
+ break;
+ case 'a':
+ extra += sizeof (void *) + sizeof (struct wl_array);
+ break;
+ case 'h':
+ extra += sizeof (int);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return extra;
+}
+
+struct wl_closure *
+wl_connection_vmarshal(struct wl_connection *connection,
+ struct wl_object *sender,
+ uint32_t opcode, va_list ap,
+ const struct wl_message *message)
+{
+ struct wl_closure *closure = &connection->send_closure;
+ struct wl_object **objectp, *object;
+ uint32_t length, *p, *start, size;
+ int dup_fd;
+ struct wl_array **arrayp, *array;
+ const char **sp, *s;
+ char *extra;
+ int i, count, fd, extra_size, *fd_ptr;
+
+ extra_size = wl_message_size_extra(message);
+ count = strlen(message->signature) + 2;
+ extra = (char *) closure->buffer;
+ start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)];
+ p = &start[2];
+ for (i = 2; i < count; i++) {
+ switch (message->signature[i - 2]) {
+ case 'u':
+ closure->types[i] = &ffi_type_uint32;
+ closure->args[i] = p;
+ *p++ = va_arg(ap, uint32_t);
+ break;
+ case 'i':
+ closure->types[i] = &ffi_type_sint32;
+ closure->args[i] = p;
+ *p++ = va_arg(ap, int32_t);
+ break;
+ case 's':
+ closure->types[i] = &ffi_type_pointer;
+ closure->args[i] = extra;
+ sp = (const char **) extra;
+ extra += sizeof *sp;
+
+ s = va_arg(ap, const char *);
+ length = s ? strlen(s) + 1: 0;
+ *p++ = length;
+
+ if (length > 0)
+ *sp = (const char *) p;
+ else
+ *sp = NULL;
+
+ memcpy(p, s, length);
+ p += DIV_ROUNDUP(length, sizeof *p);
+ break;
+ case 'o':
+ closure->types[i] = &ffi_type_pointer;
+ closure->args[i] = extra;
+ objectp = (struct wl_object **) extra;
+ extra += sizeof *objectp;
+
+ object = va_arg(ap, struct wl_object *);
+ *objectp = object;
+ *p++ = object ? object->id : 0;
+ break;
+
+ case 'n':
+ closure->types[i] = &ffi_type_uint32;
+ closure->args[i] = p;
+ object = va_arg(ap, struct wl_object *);
+ *p++ = object->id;
+ break;
+
+ case 'a':
+ closure->types[i] = &ffi_type_pointer;
+ closure->args[i] = extra;
+ arrayp = (struct wl_array **) extra;
+ extra += sizeof *arrayp;
+
+ *arrayp = (struct wl_array *) extra;
+ extra += sizeof **arrayp;
+
+ array = va_arg(ap, struct wl_array *);
+ if (array == NULL || array->size == 0) {
+ *p++ = 0;
+ break;
+ }
+ *p++ = array->size;
+ memcpy(p, array->data, array->size);
+
+ (*arrayp)->size = array->size;
+ (*arrayp)->alloc = array->alloc;
+ (*arrayp)->data = p;
+
+ p += DIV_ROUNDUP(array->size, sizeof *p);
+ break;
+
+ case 'h':
+ closure->types[i] = &ffi_type_sint;
+ closure->args[i] = extra;
+ fd_ptr = (int *) extra;
+ extra += sizeof *fd_ptr;
+
+ fd = va_arg(ap, int);
+ dup_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+ if (dup_fd < 0) {
+ fprintf(stderr, "dup failed: %m");
+ abort();
+ }
+ *fd_ptr = dup_fd;
+ wl_buffer_put(&connection->fds_out,
+ &dup_fd, sizeof dup_fd);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+
+ size = (p - start) * sizeof *p;
+ start[0] = sender->id;
+ start[1] = opcode | (size << 16);
+
+ closure->start = start;
+ closure->message = message;
+ closure->count = count;
+
+ return closure;
+}
+
+struct wl_closure *
+wl_connection_demarshal(struct wl_connection *connection,
+ uint32_t size,
+ struct wl_hash_table *objects,
+ const struct wl_message *message)
+{
+ uint32_t *p, *next, *end, length;
+ int *fd;
+ char *extra, **s;
+ int i, count, extra_space;
+ struct wl_object **object;
+ struct wl_array **array;
+ struct wl_closure *closure = &connection->receive_closure;
+
+ count = strlen(message->signature) + 2;
+ if (count > ARRAY_LENGTH(closure->types)) {
+ printf("too many args (%d)\n", count);
+ errno = EINVAL;
+ wl_connection_consume(connection, size);
+ return NULL;
+ }
+
+ extra_space = wl_message_size_extra(message);
+ if (sizeof closure->buffer < size + extra_space) {
+ printf("request too big, should malloc tmp buffer here\n");
+ errno = ENOMEM;
+ wl_connection_consume(connection, size);
+ return NULL;
+ }
+
+ closure->message = message;
+ closure->types[0] = &ffi_type_pointer;
+ closure->types[1] = &ffi_type_pointer;
+
+ wl_connection_copy(connection, closure->buffer, size);
+ p = &closure->buffer[2];
+ end = (uint32_t *) ((char *) p + size);
+ extra = (char *) end;
+ for (i = 2; i < count; i++) {
+ if (p + 1 > end) {
+ printf("message too short, "
+ "object (%d), message %s(%s)\n",
+ *p, message->name, message->signature);
+ errno = EINVAL;
+ goto err;
+ }
+
+ switch (message->signature[i - 2]) {
+ case 'u':
+ closure->types[i] = &ffi_type_uint32;
+ closure->args[i] = p++;
+ break;
+ case 'i':
+ closure->types[i] = &ffi_type_sint32;
+ closure->args[i] = p++;
+ break;
+ case 's':
+ closure->types[i] = &ffi_type_pointer;
+ length = *p++;
+
+ next = p + DIV_ROUNDUP(length, sizeof *p);
+ if (next > end) {
+ printf("message too short, "
+ "object (%d), message %s(%s)\n",
+ *p, message->name, message->signature);
+ errno = EINVAL;
+ goto err;
+ }
+
+ s = (char **) extra;
+ extra += sizeof *s;
+ closure->args[i] = s;
+
+ if (length == 0) {
+ *s = NULL;
+ } else {
+ *s = (char *) p;
+ }
+
+ if (length > 0 && (*s)[length - 1] != '\0') {
+ printf("string not nul-terminated, "
+ "message %s(%s)\n",
+ message->name, message->signature);
+ errno = EINVAL;
+ goto err;
+ }
+ p = next;
+ break;
+ case 'o':
+ closure->types[i] = &ffi_type_pointer;
+ object = (struct wl_object **) extra;
+ extra += sizeof *object;
+ closure->args[i] = object;
+
+ *object = wl_hash_table_lookup(objects, *p);
+ if (*object == NULL && *p != 0) {
+ printf("unknown object (%d), message %s(%s)\n",
+ *p, message->name, message->signature);
+ errno = EINVAL;
+ goto err;
+ }
+
+ p++;
+ break;
+ case 'n':
+ closure->types[i] = &ffi_type_uint32;
+ closure->args[i] = p;
+ object = wl_hash_table_lookup(objects, *p);
+ if (object != NULL) {
+ printf("not a new object (%d), "
+ "message %s(%s)\n",
+ *p, message->name, message->signature);
+ errno = EINVAL;
+ goto err;
+ }
+ p++;
+ break;
+ case 'a':
+ closure->types[i] = &ffi_type_pointer;
+ length = *p++;
+
+ next = p + DIV_ROUNDUP(length, sizeof *p);
+ if (next > end) {
+ printf("message too short, "
+ "object (%d), message %s(%s)\n",
+ *p, message->name, message->signature);
+ errno = EINVAL;
+ goto err;
+ }
+
+ array = (struct wl_array **) extra;
+ extra += sizeof *array;
+ closure->args[i] = array;
+
+ *array = (struct wl_array *) extra;
+ extra += sizeof **array;
+
+ (*array)->size = length;
+ (*array)->alloc = 0;
+ (*array)->data = p;
+ p = next;
+ break;
+ case 'h':
+ closure->types[i] = &ffi_type_sint;
+
+ fd = (int *) extra;
+ extra += sizeof *fd;
+ closure->args[i] = fd;
+
+ wl_buffer_copy(&connection->fds_in, fd, sizeof *fd);
+ connection->fds_in.tail += sizeof *fd;
+ break;
+ default:
+ printf("unknown type\n");
+ assert(0);
+ break;
+ }
+ }
+
+ closure->count = i;
+ ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI,
+ closure->count, &ffi_type_uint32, closure->types);
+
+ wl_connection_consume(connection, size);
+
+ return closure;
+
+ err:
+ closure->count = i;
+ wl_closure_destroy(closure);
+ wl_connection_consume(connection, size);
+
+ return NULL;
+}
+
+void
+wl_closure_invoke(struct wl_closure *closure,
+ struct wl_object *target, void (*func)(void), void *data)
+{
+ int result;
+
+ closure->args[0] = &data;
+ closure->args[1] = &target;
+
+ ffi_call(&closure->cif, func, &result, closure->args);
+}
+
+void
+wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
+{
+ uint32_t size;
+
+ size = closure->start[1] >> 16;
+ wl_connection_write(connection, closure->start, size);
+}
+
+void
+wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send)
+{
+ union wl_value *value;
+ int i;
+ struct timespec tp;
+ unsigned int time;
+
+ clock_gettime(CLOCK_REALTIME, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ fprintf(stderr, "[%10.3f] %s%s@%d.%s(",
+ time / 1000.0,
+ send ? " -> " : "",
+ target->interface->name, target->id,
+ closure->message->name);
+
+ for (i = 2; i < closure->count; i++) {
+ if (i > 2)
+ fprintf(stderr, ", ");
+
+ value = closure->args[i];
+ switch (closure->message->signature[i - 2]) {
+ case 'u':
+ fprintf(stderr, "%u", value->uint32);
+ break;
+ case 'i':
+ fprintf(stderr, "%d", value->uint32);
+ break;
+ case 's':
+ fprintf(stderr, "\"%s\"", value->string);
+ break;
+ case 'o':
+ if (value->object)
+ fprintf(stderr, "%s@%u",
+ value->object->interface->name,
+ value->object->id);
+ else
+ fprintf(stderr, "nil");
+ break;
+ case 'n':
+ fprintf(stderr, "new id %u", value->uint32);
+ break;
+ case 'a':
+ fprintf(stderr, "array");
+ break;
+ case 'h':
+ fprintf(stderr, "fd %d", value->uint32);
+ break;
+ }
+ }
+
+ fprintf(stderr, ")\n");
+}
+
+void
+wl_closure_destroy(struct wl_closure *closure)
+{
+}
diff --git a/src/connection.h b/src/connection.h
new file mode 100644
index 0000000..5f4588b
--- /dev/null
+++ b/src/connection.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _CONNECTION_H_
+#define _CONNECTION_H_
+
+#include <stdarg.h>
+#include "wayland-util.h"
+
+struct wl_connection;
+struct wl_closure;
+
+#define WL_CONNECTION_READABLE 0x01
+#define WL_CONNECTION_WRITABLE 0x02
+
+typedef int (*wl_connection_update_func_t)(struct wl_connection *connection,
+ uint32_t mask, void *data);
+
+struct wl_connection *wl_connection_create(int fd,
+ wl_connection_update_func_t update,
+ void *data);
+void wl_connection_destroy(struct wl_connection *connection);
+void wl_connection_copy(struct wl_connection *connection, void *data, size_t size);
+void wl_connection_consume(struct wl_connection *connection, size_t size);
+int wl_connection_data(struct wl_connection *connection, uint32_t mask);
+void wl_connection_write(struct wl_connection *connection, const void *data, size_t count);
+
+struct wl_closure *
+wl_connection_vmarshal(struct wl_connection *connection,
+ struct wl_object *sender,
+ uint32_t opcode, va_list ap,
+ const struct wl_message *message);
+
+struct wl_closure *
+wl_connection_demarshal(struct wl_connection *connection,
+ uint32_t size,
+ struct wl_hash_table *objects,
+ const struct wl_message *message);
+void
+wl_closure_invoke(struct wl_closure *closure,
+ struct wl_object *target, void (*func)(void), void *data);
+void
+wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
+void
+wl_closure_print(struct wl_closure *closure, struct wl_object *target, int send);
+void
+wl_closure_destroy(struct wl_closure *closure);
+
+#endif
diff --git a/src/event-loop.c b/src/event-loop.c
new file mode 100644
index 0000000..615ec1d
--- /dev/null
+++ b/src/event-loop.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/epoll.h>
+#include <sys/signalfd.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <assert.h>
+#include "wayland-server.h"
+
+struct wl_event_loop {
+ int epoll_fd;
+ struct wl_list check_list;
+ struct wl_list idle_list;
+};
+
+struct wl_event_source_interface {
+ int (*dispatch)(struct wl_event_source *source,
+ struct epoll_event *ep);
+ int (*remove)(struct wl_event_source *source);
+};
+
+struct wl_event_source {
+ struct wl_event_source_interface *interface;
+ struct wl_event_loop *loop;
+ struct wl_list link;
+ void *data;
+};
+
+struct wl_event_source_fd {
+ struct wl_event_source base;
+ int fd;
+ wl_event_loop_fd_func_t func;
+};
+
+static int
+wl_event_source_fd_dispatch(struct wl_event_source *source,
+ struct epoll_event *ep)
+{
+ struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
+ uint32_t mask;
+
+ mask = 0;
+ if (ep->events & EPOLLIN)
+ mask |= WL_EVENT_READABLE;
+ if (ep->events & EPOLLOUT)
+ mask |= WL_EVENT_WRITEABLE;
+
+ return fd_source->func(fd_source->fd, mask, fd_source->base.data);
+}
+
+static int
+wl_event_source_fd_remove(struct wl_event_source *source)
+{
+ struct wl_event_source_fd *fd_source =
+ (struct wl_event_source_fd *) source;
+ struct wl_event_loop *loop = source->loop;
+ int fd;
+
+ fd = fd_source->fd;
+ free(source);
+
+ return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
+}
+
+struct wl_event_source_interface fd_source_interface = {
+ wl_event_source_fd_dispatch,
+ wl_event_source_fd_remove
+};
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_fd(struct wl_event_loop *loop,
+ int fd, uint32_t mask,
+ wl_event_loop_fd_func_t func,
+ void *data)
+{
+ struct wl_event_source_fd *source;
+ struct epoll_event ep;
+
+ source = malloc(sizeof *source);
+ if (source == NULL)
+ return NULL;
+
+ source->base.interface = &fd_source_interface;
+ source->base.loop = loop;
+ wl_list_init(&source->base.link);
+ source->fd = fd;
+ source->func = func;
+ source->base.data = data;
+
+ memset(&ep, 0, sizeof ep);
+ if (mask & WL_EVENT_READABLE)
+ ep.events |= EPOLLIN;
+ if (mask & WL_EVENT_WRITEABLE)
+ ep.events |= EPOLLOUT;
+ ep.data.ptr = source;
+
+ if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
+ free(source);
+ return NULL;
+ }
+
+ return &source->base;
+}
+
+WL_EXPORT int
+wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
+{
+ struct wl_event_source_fd *fd_source =
+ (struct wl_event_source_fd *) source;
+ struct wl_event_loop *loop = source->loop;
+ struct epoll_event ep;
+
+ memset(&ep, 0, sizeof ep);
+ 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, fd_source->fd, &ep);
+}
+
+struct wl_event_source_timer {
+ struct wl_event_source base;
+ int fd;
+ wl_event_loop_timer_func_t func;
+};
+
+static int
+wl_event_source_timer_dispatch(struct wl_event_source *source,
+ struct epoll_event *ep)
+{
+ struct wl_event_source_timer *timer_source =
+ (struct wl_event_source_timer *) source;
+ uint64_t expires;
+
+ read(timer_source->fd, &expires, sizeof expires);
+
+ return timer_source->func(timer_source->base.data);
+}
+
+static int
+wl_event_source_timer_remove(struct wl_event_source *source)
+{
+ struct wl_event_source_timer *timer_source =
+ (struct wl_event_source_timer *) source;
+
+ close(timer_source->fd);
+ free(source);
+ return 0;
+}
+
+struct wl_event_source_interface timer_source_interface = {
+ wl_event_source_timer_dispatch,
+ wl_event_source_timer_remove
+};
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_timer(struct wl_event_loop *loop,
+ wl_event_loop_timer_func_t func,
+ void *data)
+{
+ struct wl_event_source_timer *source;
+ struct epoll_event ep;
+
+ source = malloc(sizeof *source);
+ if (source == NULL)
+ return NULL;
+
+ source->base.interface = &timer_source_interface;
+ source->base.loop = loop;
+ wl_list_init(&source->base.link);
+
+ source->fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ if (source->fd < 0) {
+ fprintf(stderr, "could not create timerfd\n: %m");
+ free(source);
+ return NULL;
+ }
+
+ source->func = func;
+ source->base.data = data;
+
+ memset(&ep, 0, sizeof ep);
+ ep.events = EPOLLIN;
+ ep.data.ptr = source;
+
+ if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
+ close(source->fd);
+ free(source);
+ return NULL;
+ }
+
+ return &source->base;
+}
+
+WL_EXPORT int
+wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
+{
+ struct wl_event_source_timer *timer_source =
+ (struct wl_event_source_timer *) source;
+ struct itimerspec its;
+
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = 0;
+ its.it_value.tv_sec = ms_delay / 1000;
+ its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
+ if (timerfd_settime(timer_source->fd, 0, &its, NULL) < 0) {
+ fprintf(stderr, "could not set timerfd\n: %m");
+ return -1;
+ }
+
+ return 0;
+}
+
+struct wl_event_source_signal {
+ struct wl_event_source base;
+ int fd;
+ int signal_number;
+ wl_event_loop_signal_func_t func;
+};
+
+static int
+wl_event_source_signal_dispatch(struct wl_event_source *source,
+ struct epoll_event *ep)
+{
+ struct wl_event_source_signal *signal_source =
+ (struct wl_event_source_signal *) source;
+ struct signalfd_siginfo signal_info;
+
+ read(signal_source->fd, &signal_info, sizeof signal_info);
+
+ return signal_source->func(signal_source->signal_number,
+ signal_source->base.data);
+}
+
+static int
+wl_event_source_signal_remove(struct wl_event_source *source)
+{
+ struct wl_event_source_signal *signal_source =
+ (struct wl_event_source_signal *) source;
+
+ close(signal_source->fd);
+ free(source);
+ return 0;
+}
+
+struct wl_event_source_interface signal_source_interface = {
+ wl_event_source_signal_dispatch,
+ wl_event_source_signal_remove
+};
+
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_signal(struct wl_event_loop *loop,
+ int signal_number,
+ wl_event_loop_signal_func_t func,
+ void *data)
+{
+ struct wl_event_source_signal *source;
+ struct epoll_event ep;
+ sigset_t mask;
+
+ source = malloc(sizeof *source);
+ if (source == NULL)
+ return NULL;
+
+ source->base.interface = &signal_source_interface;
+ source->base.loop = loop;
+ wl_list_init(&source->base.link);
+ source->signal_number = signal_number;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, signal_number);
+ source->fd = signalfd(-1, &mask, SFD_CLOEXEC);
+ if (source->fd < 0) {
+ fprintf(stderr, "could not create fd to watch signal\n: %m");
+ free(source);
+ return NULL;
+ }
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ source->func = func;
+ source->base.data = data;
+
+ memset(&ep, 0, sizeof ep);
+ ep.events = EPOLLIN;
+ ep.data.ptr = source;
+
+ if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
+ close(source->fd);
+ free(source);
+ return NULL;
+ }
+
+ return &source->base;
+}
+
+struct wl_event_source_idle {
+ struct wl_event_source base;
+ wl_event_loop_idle_func_t func;
+};
+
+static int
+wl_event_source_idle_remove(struct wl_event_source *source)
+{
+ free(source);
+
+ return 0;
+}
+
+struct wl_event_source_interface idle_source_interface = {
+ NULL,
+ wl_event_source_idle_remove
+};
+
+WL_EXPORT 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_event_source_idle *source;
+
+ source = malloc(sizeof *source);
+ if (source == NULL)
+ return NULL;
+
+ source->base.interface = &idle_source_interface;
+ source->base.loop = loop;
+
+ source->func = func;
+ source->base.data = data;
+
+ wl_list_insert(loop->idle_list.prev, &source->base.link);
+
+ return &source->base;
+}
+
+WL_EXPORT void
+wl_event_source_check(struct wl_event_source *source)
+{
+ wl_list_insert(source->loop->check_list.prev, &source->link);
+}
+
+WL_EXPORT int
+wl_event_source_remove(struct wl_event_source *source)
+{
+ if (!wl_list_empty(&source->link))
+ wl_list_remove(&source->link);
+
+ source->interface->remove(source);
+
+ return 0;
+}
+
+WL_EXPORT struct wl_event_loop *
+wl_event_loop_create(void)
+{
+ struct wl_event_loop *loop;
+
+ loop = malloc(sizeof *loop);
+ if (loop == NULL)
+ return NULL;
+
+ loop->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (loop->epoll_fd < 0) {
+ free(loop);
+ return NULL;
+ }
+ wl_list_init(&loop->check_list);
+ wl_list_init(&loop->idle_list);
+
+ return loop;
+}
+
+WL_EXPORT void
+wl_event_loop_destroy(struct wl_event_loop *loop)
+{
+ close(loop->epoll_fd);
+ free(loop);
+}
+
+static int
+post_dispatch_check(struct wl_event_loop *loop)
+{
+ struct epoll_event ep;
+ struct wl_event_source *source, *next;
+ int n;
+
+ ep.events = 0;
+ n = 0;
+ wl_list_for_each_safe(source, next, &loop->check_list, link)
+ n += source->interface->dispatch(source, &ep);
+
+ return n;
+}
+
+static void
+dispatch_idle_sources(struct wl_event_loop *loop)
+{
+ struct wl_event_source_idle *source, *next;
+
+ wl_list_for_each_safe(source, next, &loop->idle_list, base.link) {
+ source->func(source->base.data);
+ wl_event_source_remove(&source->base);
+ }
+}
+
+WL_EXPORT int
+wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
+{
+ struct epoll_event ep[32];
+ struct wl_event_source *source;
+ int i, count, n;
+
+ dispatch_idle_sources(loop);
+
+ count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
+ if (count < 0)
+ return -1;
+ n = 0;
+ for (i = 0; i < count; i++) {
+ source = ep[i].data.ptr;
+ n += source->interface->dispatch(source, &ep[i]);
+ }
+
+ while (n > 0)
+ n = post_dispatch_check(loop);
+
+ return 0;
+}
+
+WL_EXPORT int
+wl_event_loop_get_fd(struct wl_event_loop *loop)
+{
+ return loop->epoll_fd;
+}
diff --git a/src/scanner.c b/src/scanner.c
new file mode 100644
index 0000000..9584046
--- /dev/null
+++ b/src/scanner.c
@@ -0,0 +1,868 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <expat.h>
+
+#include "wayland-util.h"
+
+static int
+usage(int ret)
+{
+ fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
+ exit(ret);
+}
+
+#define XML_BUFFER_SIZE 4096
+
+struct protocol {
+ char *name;
+ char *uppercase_name;
+ struct wl_list interface_list;
+ int type_index;
+ int null_run_length;
+ char *copyright;
+};
+
+struct interface {
+ char *name;
+ char *uppercase_name;
+ int version;
+ struct wl_list request_list;
+ struct wl_list event_list;
+ struct wl_list enumeration_list;
+ struct wl_list link;
+};
+
+struct message {
+ char *name;
+ char *uppercase_name;
+ struct wl_list arg_list;
+ struct wl_list link;
+ int arg_count;
+ int type_index;
+ int all_null;
+ int destructor;
+};
+
+enum arg_type {
+ NEW_ID,
+ INT,
+ UNSIGNED,
+ STRING,
+ OBJECT,
+ ARRAY,
+ FD
+};
+
+struct arg {
+ char *name;
+ enum arg_type type;
+ char *interface_name;
+ struct wl_list link;
+};
+
+struct enumeration {
+ char *name;
+ char *uppercase_name;
+ struct wl_list entry_list;
+ struct wl_list link;
+};
+
+struct entry {
+ char *name;
+ char *uppercase_name;
+ char *value;
+ struct wl_list link;
+};
+
+struct parse_context {
+ const char *filename;
+ XML_Parser parser;
+ struct protocol *protocol;
+ struct interface *interface;
+ struct message *message;
+ struct enumeration *enumeration;
+ char character_data[8192];
+ int character_data_length;
+};
+
+static char *
+uppercase_dup(const char *src)
+{
+ char *u;
+ int i;
+
+ u = strdup(src);
+ for (i = 0; u[i]; i++)
+ u[i] = toupper(u[i]);
+ u[i] = '\0';
+
+ return u;
+}
+
+static void
+fail(struct parse_context *ctx, const char *msg)
+{
+ fprintf(stderr, "%s:%ld: %s\n",
+ ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
+ exit(EXIT_FAILURE);
+}
+
+static void
+start_element(void *data, const char *element_name, const char **atts)
+{
+ struct parse_context *ctx = data;
+ struct interface *interface;
+ struct message *message;
+ struct arg *arg;
+ struct enumeration *enumeration;
+ struct entry *entry;
+ const char *name, *type, *interface_name, *value;
+ int i, version;
+
+ name = NULL;
+ type = NULL;
+ version = 0;
+ interface_name = NULL;
+ value = NULL;
+ for (i = 0; atts[i]; i += 2) {
+ if (strcmp(atts[i], "name") == 0)
+ name = atts[i + 1];
+ if (strcmp(atts[i], "version") == 0)
+ version = atoi(atts[i + 1]);
+ if (strcmp(atts[i], "type") == 0)
+ type = atts[i + 1];
+ if (strcmp(atts[i], "value") == 0)
+ value = atts[i + 1];
+ if (strcmp(atts[i], "interface") == 0)
+ interface_name = atts[i + 1];
+ }
+
+ ctx->character_data_length = 0;
+ if (strcmp(element_name, "protocol") == 0) {
+ if (name == NULL)
+ fail(ctx, "no protocol name given");
+
+ ctx->protocol->name = strdup(name);
+ ctx->protocol->uppercase_name = uppercase_dup(name);
+ } else if (strcmp(element_name, "copyright") == 0) {
+
+ } else if (strcmp(element_name, "interface") == 0) {
+ if (name == NULL)
+ fail(ctx, "no interface name given");
+
+ if (version == 0)
+ fail(ctx, "no interface version given");
+
+ interface = malloc(sizeof *interface);
+ interface->name = strdup(name);
+ interface->uppercase_name = uppercase_dup(name);
+ interface->version = version;
+ wl_list_init(&interface->request_list);
+ wl_list_init(&interface->event_list);
+ wl_list_init(&interface->enumeration_list);
+ wl_list_insert(ctx->protocol->interface_list.prev,
+ &interface->link);
+ ctx->interface = interface;
+ } else if (strcmp(element_name, "request") == 0 ||
+ strcmp(element_name, "event") == 0) {
+ if (name == NULL)
+ fail(ctx, "no request name given");
+
+ message = malloc(sizeof *message);
+ message->name = strdup(name);
+ message->uppercase_name = uppercase_dup(name);
+ wl_list_init(&message->arg_list);
+ message->arg_count = 0;
+
+ if (strcmp(element_name, "request") == 0)
+ wl_list_insert(ctx->interface->request_list.prev,
+ &message->link);
+ else
+ wl_list_insert(ctx->interface->event_list.prev,
+ &message->link);
+
+ if (type != NULL && strcmp(type, "destructor") == 0)
+ message->destructor = 1;
+ else
+ message->destructor = 0;
+
+ if (strcmp(name, "destroy") == 0 && !message->destructor)
+ fail(ctx, "destroy request should be destructor type");
+
+ ctx->message = message;
+ } else if (strcmp(element_name, "arg") == 0) {
+ arg = malloc(sizeof *arg);
+ arg->name = strdup(name);
+
+ if (strcmp(type, "int") == 0)
+ arg->type = INT;
+ else if (strcmp(type, "uint") == 0)
+ arg->type = UNSIGNED;
+ else if (strcmp(type, "string") == 0)
+ arg->type = STRING;
+ else if (strcmp(type, "array") == 0)
+ arg->type = ARRAY;
+ else if (strcmp(type, "fd") == 0)
+ arg->type = FD;
+ else if (strcmp(type, "new_id") == 0) {
+ if (interface_name == NULL)
+ fail(ctx, "no interface name given");
+ arg->type = NEW_ID;
+ arg->interface_name = strdup(interface_name);
+ } else if (strcmp(type, "object") == 0) {
+ if (interface_name == NULL)
+ fail(ctx, "no interface name given");
+ arg->type = OBJECT;
+ arg->interface_name = strdup(interface_name);
+ } else {
+ fail(ctx, "unknown type");
+ }
+
+ wl_list_insert(ctx->message->arg_list.prev, &arg->link);
+ ctx->message->arg_count++;
+ } else if (strcmp(element_name, "enum") == 0) {
+ if (name == NULL)
+ fail(ctx, "no enum name given");
+
+ enumeration = malloc(sizeof *enumeration);
+ enumeration->name = strdup(name);
+ enumeration->uppercase_name = uppercase_dup(name);
+ wl_list_init(&enumeration->entry_list);
+
+ wl_list_insert(ctx->interface->enumeration_list.prev,
+ &enumeration->link);
+
+ ctx->enumeration = enumeration;
+ } else if (strcmp(element_name, "entry") == 0) {
+ entry = malloc(sizeof *entry);
+ entry->name = strdup(name);
+ entry->uppercase_name = uppercase_dup(name);
+ entry->value = strdup(value);
+ wl_list_insert(ctx->enumeration->entry_list.prev,
+ &entry->link);
+ }
+}
+
+static void
+end_element(void *data, const XML_Char *name)
+{
+ struct parse_context *ctx = data;
+
+ if (strcmp(name, "copyright") == 0) {
+ ctx->protocol->copyright =
+ strndup(ctx->character_data,
+ ctx->character_data_length);
+ }
+}
+
+static void
+character_data(void *data, const XML_Char *s, int len)
+{
+ struct parse_context *ctx = data;
+
+ if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
+ fprintf(stderr, "too much character data");
+ exit(EXIT_FAILURE);
+ }
+
+ memcpy(ctx->character_data + ctx->character_data_length, s, len);
+ ctx->character_data_length += len;
+}
+
+static void
+emit_opcodes(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+ int opcode;
+
+ if (wl_list_empty(message_list))
+ return;
+
+ opcode = 0;
+ wl_list_for_each(m, message_list, link)
+ printf("#define %s_%s\t%d\n",
+ interface->uppercase_name, m->uppercase_name, opcode++);
+
+ printf("\n");
+}
+
+static void
+emit_type(struct arg *a)
+{
+ switch (a->type) {
+ default:
+ case INT:
+ case FD:
+ printf("int32_t ");
+ break;
+ case NEW_ID:
+ case UNSIGNED:
+ printf("uint32_t ");
+ break;
+ case STRING:
+ printf("const char *");
+ break;
+ case OBJECT:
+ printf("struct %s *", a->interface_name);
+ break;
+ case ARRAY:
+ printf("struct wl_array *");
+ break;
+ }
+}
+
+static void
+emit_stubs(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+ struct arg *a, *ret;
+ int has_destructor, has_destroy;
+
+ /* We provide a hand written constructor for the display object */
+ if (strcmp(interface->name, "wl_display") != 0)
+ printf("static inline struct %s *\n"
+ "%s_create(struct wl_display *display, uint32_t id, uint32_t version)\n"
+ "{\n"
+ "\twl_display_bind(display, id, \"%s\", version);\n\n"
+ "\treturn (struct %s *)\n"
+ "\t\twl_proxy_create_for_id(display, &%s_interface, id);\n"
+ "}\n\n",
+ interface->name,
+ interface->name,
+ interface->name,
+ interface->name,
+ interface->name);
+
+ printf("static inline void\n"
+ "%s_set_user_data(struct %s *%s, void *user_data)\n"
+ "{\n"
+ "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+
+ printf("static inline void *\n"
+ "%s_get_user_data(struct %s *%s)\n"
+ "{\n"
+ "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+
+ has_destructor = 0;
+ has_destroy = 0;
+ wl_list_for_each(m, message_list, link) {
+ if (m->destructor)
+ has_destructor = 1;
+ if (strcmp(m->name, "destroy)") == 0)
+ has_destroy = 1;
+ }
+
+ if (!has_destructor && has_destroy) {
+ fprintf(stderr,
+ "interface %s has method named destroy but"
+ "no destructor", interface->name);
+ exit(EXIT_FAILURE);
+ }
+
+ /* And we have a hand-written display destructor */
+ if (!has_destructor && strcmp(interface->name, "wl_display") != 0)
+ printf("static inline void\n"
+ "%s_destroy(struct %s *%s)\n"
+ "{\n"
+ "\twl_proxy_destroy("
+ "(struct wl_proxy *) %s);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+
+ if (wl_list_empty(message_list))
+ return;
+
+ wl_list_for_each(m, message_list, link) {
+ ret = NULL;
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (a->type == NEW_ID)
+ ret = a;
+ }
+
+ if (ret)
+ printf("static inline struct %s *\n",
+ ret->interface_name);
+ else
+ printf("static inline void\n");
+
+ printf("%s_%s(struct %s *%s",
+ interface->name, m->name,
+ interface->name, interface->name);
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (a->type == NEW_ID)
+ continue;
+ printf(", ");
+ emit_type(a);
+ printf("%s", a->name);
+ }
+
+ printf(")\n"
+ "{\n");
+ if (ret)
+ printf("\tstruct wl_proxy *%s;\n\n"
+ "\t%s = wl_proxy_create("
+ "(struct wl_proxy *) %s,\n"
+ "\t\t\t &%s_interface);\n"
+ "\tif (!%s)\n"
+ "\t\treturn NULL;\n\n",
+ ret->name,
+ ret->name,
+ interface->name, ret->interface_name,
+ ret->name);
+
+ printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
+ "\t\t\t %s_%s",
+ interface->name,
+ interface->uppercase_name,
+ m->uppercase_name);
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ printf(", ");
+ printf("%s", a->name);
+ }
+ printf(");\n");
+
+ if (m->destructor)
+ printf("\n\twl_proxy_destroy("
+ "(struct wl_proxy *) %s);\n",
+ interface->name);
+
+ if (ret)
+ printf("\n\treturn (struct %s *) %s;\n",
+ ret->interface_name, ret->name);
+
+ printf("}\n\n");
+ }
+}
+
+static const char *indent(int n)
+{
+ const char *whitespace[] = {
+ "\t\t\t\t\t\t\t\t\t\t\t\t",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t "
+ };
+
+ return whitespace[n % 8] + 12 - n / 8;
+}
+
+static void
+emit_enumerations(struct interface *interface)
+{
+ struct enumeration *e;
+ struct entry *entry;
+
+ wl_list_for_each(e, &interface->enumeration_list, link) {
+ printf("#ifndef %s_%s_ENUM\n",
+ interface->uppercase_name, e->uppercase_name);
+ printf("#define %s_%s_ENUM\n",
+ interface->uppercase_name, e->uppercase_name);
+ printf("enum %s_%s {\n", interface->name, e->name);
+ wl_list_for_each(entry, &e->entry_list, link)
+ printf("\t%s_%s_%s = %s,\n",
+ interface->uppercase_name,
+ e->uppercase_name,
+ entry->uppercase_name, entry->value);
+ printf("};\n");
+ printf("#endif /* %s_%s_ENUM */\n\n",
+ interface->uppercase_name, e->uppercase_name);
+ }
+}
+
+static void
+emit_structs(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+ struct arg *a;
+ int is_interface, n;
+
+ if (wl_list_empty(message_list))
+ return;
+
+ is_interface = message_list == &interface->request_list;
+ printf("struct %s_%s {\n", interface->name,
+ is_interface ? "interface" : "listener");
+
+ wl_list_for_each(m, message_list, link) {
+ printf("\tvoid (*%s)(", m->name);
+
+ n = strlen(m->name) + 17;
+ if (is_interface) {
+ printf("struct wl_client *client,\n"
+ "%sstruct %s *%s",
+ indent(n),
+ interface->name, interface->name);
+ } else {
+ printf("void *data,\n"),
+ printf("%sstruct %s *%s",
+ indent(n), interface->name, interface->name);
+ }
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ printf(",\n%s", indent(n));
+
+ emit_type(a);
+ printf("%s", a->name);
+ }
+
+ printf(");\n");
+ }
+
+ printf("};\n\n");
+
+ if (!is_interface) {
+ printf("static inline int\n"
+ "%s_add_listener(struct %s *%s,\n"
+ "%sconst struct %s_listener *listener, void *data)\n"
+ "{\n"
+ "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
+ "%s(void (**)(void)) listener, data);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ indent(17 + strlen(interface->name)),
+ interface->name,
+ interface->name,
+ indent(37));
+ }
+}
+
+static void
+format_copyright(const char *copyright)
+{
+ int bol = 1, start = 0, i;
+
+ for (i = 0; copyright[i]; i++) {
+ if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
+ continue;
+ } else if (bol) {
+ bol = 0;
+ start = i;
+ }
+
+ if (copyright[i] == '\n' || copyright[i] == '\0') {
+ printf("%s %.*s\n",
+ i == 0 ? "/*" : " *",
+ i - start, copyright + start);
+ bol = 1;
+ }
+ }
+ printf(" */\n\n");
+}
+
+static void
+emit_header(struct protocol *protocol, int server)
+{
+ struct interface *i;
+ const char *s = server ? "SERVER" : "CLIENT";
+
+ if (protocol->copyright)
+ format_copyright(protocol->copyright);
+
+ printf("#ifndef %s_%s_PROTOCOL_H\n"
+ "#define %s_%s_PROTOCOL_H\n"
+ "\n"
+ "#ifdef __cplusplus\n"
+ "extern \"C\" {\n"
+ "#endif\n"
+ "\n"
+ "#include <stdint.h>\n"
+ "#include <stddef.h>\n"
+ "#include \"wayland-util.h\"\n\n"
+ "struct wl_client;\n\n",
+ protocol->uppercase_name, s,
+ protocol->uppercase_name, s);
+
+ wl_list_for_each(i, &protocol->interface_list, link)
+ printf("struct %s;\n", i->name);
+ printf("\n");
+
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ printf("extern const struct wl_interface "
+ "%s_interface;\n",
+ i->name);
+ }
+ printf("\n");
+
+ wl_list_for_each(i, &protocol->interface_list, link) {
+
+ emit_enumerations(i);
+
+ if (server) {
+ emit_structs(&i->request_list, i);
+ emit_opcodes(&i->event_list, i);
+ } else {
+ emit_structs(&i->event_list, i);
+ emit_opcodes(&i->request_list, i);
+ emit_stubs(&i->request_list, i);
+ }
+ }
+
+ printf("#ifdef __cplusplus\n"
+ "}\n"
+ "#endif\n"
+ "\n"
+ "#endif\n");
+}
+
+static void
+emit_types_forward_declarations(struct protocol *protocol,
+ struct wl_list *message_list)
+{
+ struct message *m;
+ struct arg *a;
+ int length;
+
+ wl_list_for_each(m, message_list, link) {
+ length = 0;
+ m->all_null = 1;
+ wl_list_for_each(a, &m->arg_list, link) {
+ length++;
+ switch (a->type) {
+ case NEW_ID:
+ case OBJECT:
+ m->all_null = 0;
+ printf("extern const struct wl_interface %s_interface;\n",
+ a->interface_name);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (m->all_null && length > protocol->null_run_length)
+ protocol->null_run_length = length;
+ }
+}
+
+static void
+emit_null_run(struct protocol *protocol)
+{
+ int i;
+
+ for (i = 0; i < protocol->null_run_length; i++)
+ printf("\tNULL,\n");
+}
+
+static void
+emit_types(struct protocol *protocol, struct wl_list *message_list)
+{
+ struct message *m;
+ struct arg *a;
+
+ wl_list_for_each(m, message_list, link) {
+ if (m->all_null) {
+ m->type_index = 0;
+ continue;
+ }
+
+ m->type_index =
+ protocol->null_run_length + protocol->type_index;
+ protocol->type_index += m->arg_count;
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ switch (a->type) {
+ case NEW_ID:
+ case OBJECT:
+ if (strcmp(a->interface_name,
+ "wl_object") != 0)
+ printf("\t&%s_interface,\n",
+ a->interface_name);
+ else
+ printf("\tNULL,\n");
+ break;
+ default:
+ printf("\tNULL,\n");
+ break;
+ }
+ }
+ }
+}
+
+static void
+emit_messages(struct wl_list *message_list,
+ struct interface *interface, const char *suffix)
+{
+ struct message *m;
+ struct arg *a;
+
+ if (wl_list_empty(message_list))
+ return;
+
+ printf("static const struct wl_message "
+ "%s_%s[] = {\n",
+ interface->name, suffix);
+
+ wl_list_for_each(m, message_list, link) {
+ printf("\t{ \"%s\", \"", m->name);
+ wl_list_for_each(a, &m->arg_list, link) {
+ switch (a->type) {
+ default:
+ case INT:
+ printf("i");
+ break;
+ case NEW_ID:
+ printf("n");
+ break;
+ case UNSIGNED:
+ printf("u");
+ break;
+ case STRING:
+ printf("s");
+ break;
+ case OBJECT:
+ printf("o");
+ break;
+ case ARRAY:
+ printf("a");
+ break;
+ case FD:
+ printf("h");
+ break;
+ }
+ }
+ printf("\", types + %d },\n", m->type_index);
+ }
+
+ printf("};\n\n");
+}
+
+static void
+emit_code(struct protocol *protocol)
+{
+ struct interface *i;
+
+ if (protocol->copyright)
+ format_copyright(protocol->copyright);
+
+ printf("#include <stdlib.h>\n"
+ "#include <stdint.h>\n"
+ "#include \"wayland-util.h\"\n\n");
+
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ emit_types_forward_declarations(protocol, &i->request_list);
+ emit_types_forward_declarations(protocol, &i->event_list);
+ }
+ printf("\n");
+
+ printf("static const struct wl_interface *types[] = {\n");
+ emit_null_run(protocol);
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ emit_types(protocol, &i->request_list);
+ emit_types(protocol, &i->event_list);
+ }
+ printf("};\n\n");
+
+ wl_list_for_each(i, &protocol->interface_list, link) {
+
+ emit_messages(&i->request_list, i, "requests");
+ emit_messages(&i->event_list, i, "events");
+
+ printf("WL_EXPORT const struct wl_interface "
+ "%s_interface = {\n"
+ "\t\"%s\", %d,\n",
+ i->name, i->name, i->version);
+
+ if (!wl_list_empty(&i->request_list))
+ printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
+ i->name, i->name);
+ else
+ printf("\t0, NULL,\n");
+
+ if (!wl_list_empty(&i->event_list))
+ printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
+ i->name, i->name);
+ else
+ printf("\t0, NULL,\n");
+
+ printf("};\n\n");
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct parse_context ctx;
+ struct protocol protocol;
+ int len;
+ void *buf;
+
+ if (argc != 2)
+ usage(EXIT_FAILURE);
+
+ wl_list_init(&protocol.interface_list);
+ protocol.type_index = 0;
+ protocol.null_run_length = 0;
+ protocol.copyright = NULL;
+ ctx.protocol = &protocol;
+
+ ctx.filename = "<stdin>";
+ ctx.parser = XML_ParserCreate(NULL);
+ XML_SetUserData(ctx.parser, &ctx);
+ if (ctx.parser == NULL) {
+ fprintf(stderr, "failed to create parser\n");
+ exit(EXIT_FAILURE);
+ }
+
+ XML_SetElementHandler(ctx.parser, start_element, end_element);
+ XML_SetCharacterDataHandler(ctx.parser, character_data);
+
+ do {
+ buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
+ len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
+ if (len < 0) {
+ fprintf(stderr, "fread: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ XML_ParseBuffer(ctx.parser, len, len == 0);
+
+ } while (len > 0);
+
+ XML_ParserFree(ctx.parser);
+
+ if (strcmp(argv[1], "client-header") == 0) {
+ emit_header(&protocol, 0);
+ } else if (strcmp(argv[1], "server-header") == 0) {
+ emit_header(&protocol, 1);
+ } else if (strcmp(argv[1], "code") == 0) {
+ emit_code(&protocol);
+ }
+
+ return 0;
+}
diff --git a/src/scanner.mk b/src/scanner.mk
new file mode 100644
index 0000000..1b6963c
--- /dev/null
+++ b/src/scanner.mk
@@ -0,0 +1,8 @@
+%-protocol.c : $(protocoldir)/%.xml
+ $(AM_V_GEN)$(wayland_scanner) code < $< > $@
+
+%-server-protocol.h : $(protocoldir)/%.xml
+ $(AM_V_GEN)$(wayland_scanner) server-header < $< > $@
+
+%-client-protocol.h : $(protocoldir)/%.xml
+ $(AM_V_GEN)$(wayland_scanner) client-header < $< > $@
diff --git a/src/wayland-client.c b/src/wayland-client.c
new file mode 100644
index 0000000..9d1f66b
--- /dev/null
+++ b/src/wayland-client.c
@@ -0,0 +1,604 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#include "connection.h"
+#include "wayland-util.h"
+#include "wayland-client.h"
+
+struct wl_global_listener {
+ wl_display_global_func_t handler;
+ void *data;
+ struct wl_list link;
+};
+
+struct wl_proxy {
+ struct wl_object object;
+ struct wl_display *display;
+ void *user_data;
+};
+
+struct wl_sync_handler {
+ wl_display_sync_func_t func;
+ uint32_t key;
+ void *data;
+ struct wl_list link;
+};
+
+struct wl_frame_handler {
+ wl_display_frame_func_t func;
+ uint32_t key;
+ void *data;
+ struct wl_surface *surface;
+ struct wl_list link;
+};
+
+struct wl_global {
+ uint32_t id;
+ char *interface;
+ uint32_t version;
+ struct wl_list link;
+};
+
+struct wl_display {
+ struct wl_proxy proxy;
+ struct wl_connection *connection;
+ int fd;
+ uint32_t id, id_count, next_range;
+ uint32_t mask;
+ struct wl_hash_table *objects;
+ struct wl_list global_listener_list;
+ struct wl_list global_list;
+
+ wl_display_update_func_t update;
+ void *update_data;
+
+ wl_display_global_func_t global_handler;
+ void *global_handler_data;
+
+ struct wl_list sync_list, frame_list;
+ uint32_t key;
+};
+
+static int wl_debug = 0;
+
+static int
+connection_update(struct wl_connection *connection,
+ uint32_t mask, void *data)
+{
+ struct wl_display *display = data;
+
+ display->mask = mask;
+ if (display->update)
+ return display->update(display->mask,
+ display->update_data);
+
+ return 0;
+}
+
+WL_EXPORT struct wl_global_listener *
+wl_display_add_global_listener(struct wl_display *display,
+ wl_display_global_func_t handler, void *data)
+{
+ struct wl_global_listener *listener;
+ struct wl_global *global;
+
+ listener = malloc(sizeof *listener);
+ if (listener == NULL)
+ return NULL;
+
+ listener->handler = handler;
+ listener->data = data;
+ wl_list_insert(display->global_listener_list.prev, &listener->link);
+
+ wl_list_for_each(global, &display->global_list, link)
+ (*listener->handler)(display, global->id, global->interface,
+ global->version, listener->data);
+
+ return listener;
+}
+
+WL_EXPORT void
+wl_display_remove_global_listener(struct wl_display *display,
+ struct wl_global_listener *listener)
+{
+ wl_list_remove(&listener->link);
+ free(listener);
+}
+
+WL_EXPORT struct wl_proxy *
+wl_proxy_create_for_id(struct wl_display *display,
+ const struct wl_interface *interface, uint32_t id)
+{
+ struct wl_proxy *proxy;
+
+ proxy = malloc(sizeof *proxy);
+ if (proxy == NULL)
+ return NULL;
+
+ proxy->object.interface = interface;
+ proxy->object.implementation = NULL;
+ proxy->object.id = id;
+ proxy->display = display;
+ wl_hash_table_insert(display->objects, proxy->object.id, proxy);
+
+ return proxy;
+}
+
+WL_EXPORT struct wl_proxy *
+wl_proxy_create(struct wl_proxy *factory,
+ const struct wl_interface *interface)
+{
+ return wl_proxy_create_for_id(factory->display, interface,
+ wl_display_allocate_id(factory->display));
+}
+
+WL_EXPORT void
+wl_proxy_destroy(struct wl_proxy *proxy)
+{
+ wl_hash_table_remove(proxy->display->objects, proxy->object.id);
+ free(proxy);
+}
+
+WL_EXPORT int
+wl_proxy_add_listener(struct wl_proxy *proxy,
+ void (**implementation)(void), void *data)
+{
+ if (proxy->object.implementation) {
+ fprintf(stderr, "proxy already has listener\n");
+ return -1;
+ }
+
+ proxy->object.implementation = implementation;
+ proxy->user_data = data;
+
+ return 0;
+}
+
+WL_EXPORT void
+wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
+{
+ struct wl_closure *closure;
+ va_list ap;
+
+ va_start(ap, opcode);
+ closure = wl_connection_vmarshal(proxy->display->connection,
+ &proxy->object, opcode, ap,
+ &proxy->object.interface->methods[opcode]);
+ va_end(ap);
+
+ wl_closure_send(closure, proxy->display->connection);
+
+ if (wl_debug)
+ wl_closure_print(closure, &proxy->object, true);
+
+ wl_closure_destroy(closure);
+}
+
+/* Can't do this, there may be more than one instance of an
+ * interface... */
+WL_EXPORT uint32_t
+wl_display_get_global(struct wl_display *display,
+ const char *interface, uint32_t version)
+{
+ struct wl_global *global;
+
+ wl_list_for_each(global, &display->global_list, link)
+ if (strcmp(interface, global->interface) == 0 &&
+ version <= global->version)
+ return global->id;
+
+ return 0;
+}
+
+static void
+display_handle_error(void *data,
+ struct wl_display *display, struct wl_object *object,
+ uint32_t code, const char *message)
+{
+ fprintf(stderr, "%s@%d: error %d: %s\n",
+ object->interface->name, object->id, code, message);
+ abort();
+}
+
+static void
+display_handle_global(void *data,
+ struct wl_display *display,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct wl_global_listener *listener;
+ struct wl_global *global;
+
+ if (strcmp(interface, "wl_display") == 0)
+ wl_hash_table_insert(display->objects,
+ id, &display->proxy.object);
+
+ global = malloc(sizeof *global);
+ global->id = id;
+ global->interface = strdup(interface);
+ global->version = version;
+ wl_list_insert(display->global_list.prev, &global->link);
+
+ wl_list_for_each(listener, &display->global_listener_list, link)
+ (*listener->handler)(display,
+ id, interface, version, listener->data);
+}
+
+static void
+display_handle_global_remove(void *data,
+ struct wl_display *display, uint32_t id)
+{
+ struct wl_global *global;
+
+ wl_list_for_each(global, &display->global_list, link)
+ if (global->id == id) {
+ wl_list_remove(&global->link);
+ free(global);
+ break;
+ }
+}
+
+static void
+display_handle_range(void *data,
+ struct wl_display *display, uint32_t range)
+{
+ display->next_range = range;
+}
+
+static void
+display_handle_key(void *data,
+ struct wl_display *display, uint32_t key, uint32_t time)
+{
+ struct wl_sync_handler *sync_handler;
+ struct wl_frame_handler *frame_handler;
+
+ sync_handler = container_of(display->sync_list.next,
+ struct wl_sync_handler, link);
+ if (!wl_list_empty(&display->sync_list) && sync_handler->key == key) {
+ wl_list_remove(&sync_handler->link);
+ sync_handler->func(sync_handler->data);
+ free(sync_handler);
+ return;
+ }
+
+ frame_handler = container_of(display->frame_list. next,
+ struct wl_frame_handler, link);
+ if (!wl_list_empty(&display->frame_list) &&
+ frame_handler->key == key) {
+ wl_list_remove(&frame_handler->link);
+ frame_handler->func(frame_handler->surface,
+ frame_handler->data, time);
+ free(frame_handler);
+ return;
+ }
+
+ fprintf(stderr, "unsolicited sync event, client gone?\n");
+}
+
+static const struct wl_display_listener display_listener = {
+ display_handle_error,
+ display_handle_global,
+ display_handle_global_remove,
+ display_handle_range,
+ display_handle_key
+};
+
+static int
+connect_to_socket(struct wl_display *display, const char *name)
+{
+ struct sockaddr_un addr;
+ socklen_t size;
+ const char *runtime_dir;
+ size_t name_size;
+
+ display->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (display->fd < 0)
+ return -1;
+
+ runtime_dir = getenv("XDG_RUNTIME_DIR");
+ if (runtime_dir == NULL) {
+ runtime_dir = ".";
+ fprintf(stderr,
+ "XDG_RUNTIME_DIR not set, falling back to %s\n",
+ runtime_dir);
+ }
+
+ if (name == NULL)
+ name = getenv("WAYLAND_DISPLAY");
+ if (name == NULL)
+ name = "wayland-0";
+
+ memset(&addr, 0, sizeof addr);
+ addr.sun_family = AF_LOCAL;
+ name_size =
+ snprintf(addr.sun_path, sizeof addr.sun_path,
+ "%s/%s", runtime_dir, name) + 1;
+
+ size = offsetof (struct sockaddr_un, sun_path) + name_size;
+
+ if (connect(display->fd, (struct sockaddr *) &addr, size) < 0) {
+ close(display->fd);
+ return -1;
+ }
+
+ return 0;
+}
+
+WL_EXPORT struct wl_display *
+wl_display_connect(const char *name)
+{
+ struct wl_display *display;
+ const char *debug;
+ char *connection, *end;
+ int flags;
+
+ debug = getenv("WAYLAND_DEBUG");
+ if (debug)
+ wl_debug = 1;
+
+ display = malloc(sizeof *display);
+ if (display == NULL)
+ return NULL;
+
+ memset(display, 0, sizeof *display);
+ connection = getenv("WAYLAND_SOCKET");
+ if (connection) {
+ display->fd = strtol(connection, &end, 0);
+ if (*end != '\0') {
+ free(display);
+ return NULL;
+ }
+ flags = fcntl(display->fd, F_GETFD);
+ if (flags != -1)
+ fcntl(display->fd, F_SETFD, flags | FD_CLOEXEC);
+ } else if (connect_to_socket(display, name) < 0) {
+ free(display);
+ return NULL;
+ }
+
+ display->objects = wl_hash_table_create();
+ if (display->objects == NULL) {
+ close(display->fd);
+ free(display);
+ return NULL;
+ }
+ wl_list_init(&display->global_listener_list);
+ wl_list_init(&display->global_list);
+
+ display->proxy.object.interface = &wl_display_interface;
+ display->proxy.object.id = 1;
+ display->proxy.display = display;
+
+ wl_list_init(&display->sync_list);
+ wl_list_init(&display->frame_list);
+
+ display->proxy.object.implementation =
+ (void(**)(void)) &display_listener;
+ display->proxy.user_data = display;
+
+ display->connection = wl_connection_create(display->fd,
+ connection_update,
+ display);
+ if (display->connection == NULL) {
+ wl_hash_table_destroy(display->objects);
+ close(display->fd);
+ free(display);
+ return NULL;
+ }
+
+ wl_display_bind(display, 1, "wl_display", 1);
+
+ return display;
+}
+
+WL_EXPORT void
+wl_display_destroy(struct wl_display *display)
+{
+ struct wl_global *global, *gnext;
+ struct wl_global_listener *listener, *lnext;
+
+ wl_connection_destroy(display->connection);
+ wl_hash_table_destroy(display->objects);
+ wl_list_for_each_safe(global, gnext,
+ &display->global_list, link)
+ free(global);
+ wl_list_for_each_safe(listener, lnext,
+ &display->global_listener_list, link)
+ free(listener);
+
+ close(display->fd);
+ free(display);
+}
+
+WL_EXPORT int
+wl_display_get_fd(struct wl_display *display,
+ wl_display_update_func_t update, void *data)
+{
+ display->update = update;
+ display->update_data = data;
+
+ display->update(display->mask, display->update_data);
+
+ return display->fd;
+}
+
+WL_EXPORT int
+wl_display_sync_callback(struct wl_display *display,
+ wl_display_sync_func_t func, void *data)
+{
+ struct wl_sync_handler *handler;
+
+ handler = malloc(sizeof *handler);
+ if (handler == NULL)
+ return -1;
+
+ handler->func = func;
+ handler->key = display->key++;
+ handler->data = data;
+
+ wl_list_insert(display->sync_list.prev, &handler->link);
+ wl_display_sync(display, handler->key);
+
+ return 0;
+}
+
+WL_EXPORT int
+wl_display_frame_callback(struct wl_display *display,
+ struct wl_surface *surface,
+ wl_display_frame_func_t func, void *data)
+{
+ struct wl_frame_handler *handler;
+
+ handler = malloc(sizeof *handler);
+ if (handler == NULL)
+ return -1;
+
+ handler->func = func;
+ handler->key = display->key++;
+ handler->data = data;
+ handler->surface = surface;
+
+ wl_list_insert(display->frame_list.prev, &handler->link);
+ wl_display_frame(display, handler->surface, handler->key);
+
+ return 0;
+}
+
+static void
+handle_event(struct wl_display *display,
+ uint32_t id, uint32_t opcode, uint32_t size)
+{
+ uint32_t p[32];
+ struct wl_proxy *proxy;
+ struct wl_closure *closure;
+ const struct wl_message *message;
+
+ wl_connection_copy(display->connection, p, size);
+ if (id == 1)
+ proxy = &display->proxy;
+ else
+ proxy = wl_hash_table_lookup(display->objects, id);
+
+ if (proxy == NULL || proxy->object.implementation == NULL) {
+ wl_connection_consume(display->connection, size);
+ return;
+ }
+
+ message = &proxy->object.interface->events[opcode];
+ closure = wl_connection_demarshal(display->connection,
+ size, display->objects, message);
+
+ if (closure == NULL) {
+ fprintf(stderr, "Error demarshalling event: %m\n");
+ abort();
+ }
+
+ if (wl_debug)
+ wl_closure_print(closure, &proxy->object, false);
+
+ wl_closure_invoke(closure, &proxy->object,
+ proxy->object.implementation[opcode],
+ proxy->user_data);
+
+ wl_closure_destroy(closure);
+}
+
+WL_EXPORT void
+wl_display_iterate(struct wl_display *display, uint32_t mask)
+{
+ uint32_t p[2], object, opcode, size;
+ int len;
+
+ mask &= display->mask;
+ if (mask == 0) {
+ fprintf(stderr,
+ "wl_display_iterate called with unsolicited flags");
+ return;
+ }
+
+ len = wl_connection_data(display->connection, mask);
+ while (len > 0) {
+ if (len < sizeof p)
+ break;
+
+ wl_connection_copy(display->connection, p, sizeof p);
+ object = p[0];
+ opcode = p[1] & 0xffff;
+ size = p[1] >> 16;
+ if (len < size)
+ break;
+
+ handle_event(display, object, opcode, size);
+ len -= size;
+ }
+
+ if (len < 0) {
+ fprintf(stderr, "read error: %m\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+WL_EXPORT void
+wl_display_flush(struct wl_display *display)
+{
+ while (display->mask & WL_DISPLAY_WRITABLE)
+ wl_display_iterate (display, WL_DISPLAY_WRITABLE);
+}
+
+WL_EXPORT uint32_t
+wl_display_allocate_id(struct wl_display *display)
+{
+ if (display->id_count == 0) {
+ display->id_count = 256;
+ display->id = display->next_range;
+ }
+
+ display->id_count--;
+
+ return display->id++;
+}
+
+WL_EXPORT void
+wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
+{
+ proxy->user_data = user_data;
+}
+
+WL_EXPORT void *
+wl_proxy_get_user_data(struct wl_proxy *proxy)
+{
+ return proxy->user_data;
+}
diff --git a/src/wayland-client.h b/src/wayland-client.h
new file mode 100644
index 0000000..385dc16
--- /dev/null
+++ b/src/wayland-client.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _WAYLAND_CLIENT_H
+#define _WAYLAND_CLIENT_H
+
+#include "wayland-util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct wl_proxy;
+struct wl_display;
+
+void wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);
+struct wl_proxy *wl_proxy_create(struct wl_proxy *factory,
+ const struct wl_interface *interface);
+struct wl_proxy *wl_proxy_create_for_id(struct wl_display *display,
+ const struct wl_interface *interface,
+ uint32_t id);
+void wl_proxy_destroy(struct wl_proxy *proxy);
+int wl_proxy_add_listener(struct wl_proxy *proxy,
+ void (**implementation)(void), void *data);
+void wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
+void *wl_proxy_get_user_data(struct wl_proxy *proxy);
+
+#include "wayland-client-protocol.h"
+
+#define WL_DISPLAY_READABLE 0x01
+#define WL_DISPLAY_WRITABLE 0x02
+
+typedef int (*wl_display_update_func_t)(uint32_t mask, void *data);
+typedef void (*wl_display_sync_func_t)(void *data);
+typedef void (*wl_display_frame_func_t)(struct wl_surface *surface,
+ void *data, uint32_t time);
+
+struct wl_display *wl_display_connect(const char *name);
+void wl_display_destroy(struct wl_display *display);
+int wl_display_get_fd(struct wl_display *display,
+ wl_display_update_func_t update, void *data);
+uint32_t wl_display_allocate_id(struct wl_display *display);
+void wl_display_iterate(struct wl_display *display, uint32_t mask);
+void wl_display_flush(struct wl_display *display);
+int wl_display_sync_callback(struct wl_display *display,
+ wl_display_sync_func_t func, void *data);
+int wl_display_frame_callback(struct wl_display *display,
+ struct wl_surface *surface,
+ wl_display_frame_func_t func, void *data);
+
+struct wl_global_listener;
+typedef void (*wl_display_global_func_t)(struct wl_display *display,
+ uint32_t id,
+ const char *interface,
+ uint32_t version,
+ void *data);
+void
+wl_display_remove_global_listener(struct wl_display *display,
+ struct wl_global_listener *listener);
+struct wl_global_listener *
+wl_display_add_global_listener(struct wl_display *display,
+ wl_display_global_func_t handler, void *data);
+WL_EXPORT uint32_t
+wl_display_get_global(struct wl_display *display,
+ const char *interface, uint32_t version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-client.pc.in b/src/wayland-client.pc.in
new file mode 100644
index 0000000..59a925d
--- /dev/null
+++ b/src/wayland-client.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: Wayland Client
+Description: Wayland client side library
+Version: 0.1
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-client
diff --git a/src/wayland-egl.h b/src/wayland-egl.h
new file mode 100644
index 0000000..85fe73d
--- /dev/null
+++ b/src/wayland-egl.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _WAYLAND_EGL_H
+#define _WAYLAND_EGL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <wayland-client.h>
+
+#define WL_EGL_PLATFORM 1
+
+struct wl_egl_window;
+struct wl_egl_pixmap;
+
+struct wl_egl_window *
+wl_egl_window_create(struct wl_surface *surface,
+ int width, int height,
+ struct wl_visual *visual);
+
+void
+wl_egl_window_destroy(struct wl_egl_window *egl_window);
+
+void
+wl_egl_window_resize(struct wl_egl_window *egl_window,
+ int width, int height,
+ int dx, int dy);
+
+void
+wl_egl_window_get_attached_size(struct wl_egl_window *egl_window,
+ int *width, int *height);
+
+struct wl_egl_pixmap *
+wl_egl_pixmap_create(int width, int height,
+ struct wl_visual *visual, uint32_t flags);
+void
+wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap);
+
+struct wl_buffer *
+wl_egl_pixmap_create_buffer(struct wl_egl_pixmap *egl_pixmap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-hash.c b/src/wayland-hash.c
new file mode 100644
index 0000000..b299a33
--- /dev/null
+++ b/src/wayland-hash.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ * Copyright © 1988-2004 Keith Packard and Bart Massey.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the authors
+ * or their institutions shall not be used in advertising or
+ * otherwise to promote the sale, use or other dealings in this
+ * Software without prior written authorization from the
+ * authors.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Keith Packard <keithp@keithp.com>
+ */
+
+#include <stdlib.h>
+
+#include "wayland-util.h"
+
+struct hash_entry {
+ uint32_t hash;
+ void *data;
+};
+
+struct wl_hash_table {
+ struct hash_entry *table;
+ uint32_t size;
+ uint32_t rehash;
+ uint32_t max_entries;
+ uint32_t size_index;
+ uint32_t entries;
+ uint32_t deleted_entries;
+};
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+/*
+ * From Knuth -- a good choice for hash/rehash values is p, p-2 where
+ * p and p-2 are both prime. These tables are sized to have an extra 10%
+ * free to avoid exponential performance degradation as the hash table fills
+ */
+
+static const uint32_t deleted_data;
+
+static const struct {
+ uint32_t max_entries, size, rehash;
+} hash_sizes[] = {
+ { 2, 5, 3 },
+ { 4, 7, 5 },
+ { 8, 13, 11 },
+ { 16, 19, 17 },
+ { 32, 43, 41 },
+ { 64, 73, 71 },
+ { 128, 151, 149 },
+ { 256, 283, 281 },
+ { 512, 571, 569 },
+ { 1024, 1153, 1151 },
+ { 2048, 2269, 2267 },
+ { 4096, 4519, 4517 },
+ { 8192, 9013, 9011 },
+ { 16384, 18043, 18041 },
+ { 32768, 36109, 36107 },
+ { 65536, 72091, 72089 },
+ { 131072, 144409, 144407 },
+ { 262144, 288361, 288359 },
+ { 524288, 576883, 576881 },
+ { 1048576, 1153459, 1153457 },
+ { 2097152, 2307163, 2307161 },
+ { 4194304, 4613893, 4613891 },
+ { 8388608, 9227641, 9227639 },
+ { 16777216, 18455029, 18455027 },
+ { 33554432, 36911011, 36911009 },
+ { 67108864, 73819861, 73819859 },
+ { 134217728, 147639589, 147639587 },
+ { 268435456, 295279081, 295279079 },
+ { 536870912, 590559793, 590559791 },
+ { 1073741824, 1181116273, 1181116271},
+ { 2147483648ul, 2362232233ul, 2362232231ul}
+};
+
+static int
+entry_is_free(struct hash_entry *entry)
+{
+ return entry->data == NULL;
+}
+
+static int
+entry_is_deleted(struct hash_entry *entry)
+{
+ return entry->data == &deleted_data;
+}
+
+static int
+entry_is_present(struct hash_entry *entry)
+{
+ return entry->data != NULL && entry->data != &deleted_data;
+}
+
+WL_EXPORT struct wl_hash_table *
+wl_hash_table_create(void)
+{
+ struct wl_hash_table *ht;
+
+ ht = malloc(sizeof(*ht));
+ if (ht == NULL)
+ return NULL;
+
+ ht->size_index = 0;
+ ht->size = hash_sizes[ht->size_index].size;
+ ht->rehash = hash_sizes[ht->size_index].rehash;
+ ht->max_entries = hash_sizes[ht->size_index].max_entries;
+ ht->table = calloc(ht->size, sizeof(*ht->table));
+ ht->entries = 0;
+ ht->deleted_entries = 0;
+
+ if (ht->table == NULL) {
+ free(ht);
+ return NULL;
+ }
+
+ return ht;
+}
+
+/**
+ * Frees the given hash table.
+ */
+WL_EXPORT void
+wl_hash_table_destroy(struct wl_hash_table *ht)
+{
+ if (!ht)
+ return;
+
+ free(ht->table);
+ free(ht);
+}
+
+/**
+ * Finds a hash table entry with the given key and hash of that key.
+ *
+ * Returns NULL if no entry is found. Note that the data pointer may be
+ * modified by the user.
+ */
+static void *
+hash_table_search(struct wl_hash_table *ht, uint32_t hash)
+{
+ uint32_t hash_address;
+
+ hash_address = hash % ht->size;
+ do {
+ uint32_t double_hash;
+
+ struct hash_entry *entry = ht->table + hash_address;
+
+ if (entry_is_free(entry)) {
+ return NULL;
+ } else if (entry_is_present(entry) && entry->hash == hash) {
+ return entry;
+ }
+
+ double_hash = hash % ht->rehash;
+ if (double_hash == 0)
+ double_hash = 1;
+
+ hash_address = (hash_address + double_hash) % ht->size;
+ } while (hash_address != hash % ht->size);
+
+ return NULL;
+}
+
+WL_EXPORT void *
+wl_hash_table_lookup(struct wl_hash_table *ht, uint32_t hash)
+{
+ struct hash_entry *entry;
+
+ entry = hash_table_search(ht, hash);
+ if (entry != NULL)
+ return entry->data;
+
+ return NULL;
+}
+
+static void
+hash_table_rehash(struct wl_hash_table *ht, int new_size_index)
+{
+ struct wl_hash_table old_ht;
+ struct hash_entry *table, *entry;
+
+ if (new_size_index >= ARRAY_SIZE(hash_sizes))
+ return;
+
+ table = calloc(hash_sizes[new_size_index].size, sizeof(*ht->table));
+ if (table == NULL)
+ return;
+
+ old_ht = *ht;
+
+ ht->table = table;
+ ht->size_index = new_size_index;
+ ht->size = hash_sizes[ht->size_index].size;
+ ht->rehash = hash_sizes[ht->size_index].rehash;
+ ht->max_entries = hash_sizes[ht->size_index].max_entries;
+ ht->entries = 0;
+ ht->deleted_entries = 0;
+
+ for (entry = old_ht.table;
+ entry != old_ht.table + old_ht.size;
+ entry++) {
+ if (entry_is_present(entry)) {
+ wl_hash_table_insert(ht, entry->hash, entry->data);
+ }
+ }
+
+ free(old_ht.table);
+}
+
+/**
+ * Inserts the data with the given hash into the table.
+ *
+ * Note that insertion may rearrange the table on a resize or rehash,
+ * so previously found hash_entries are no longer valid after this function.
+ */
+WL_EXPORT int
+wl_hash_table_insert(struct wl_hash_table *ht, uint32_t hash, void *data)
+{
+ uint32_t hash_address;
+
+ if (ht->entries >= ht->max_entries) {
+ hash_table_rehash(ht, ht->size_index + 1);
+ } else if (ht->deleted_entries + ht->entries >= ht->max_entries) {
+ hash_table_rehash(ht, ht->size_index);
+ }
+
+ hash_address = hash % ht->size;
+ do {
+ struct hash_entry *entry = ht->table + hash_address;
+ uint32_t double_hash;
+
+ if (!entry_is_present(entry)) {
+ if (entry_is_deleted(entry))
+ ht->deleted_entries--;
+ entry->hash = hash;
+ entry->data = data;
+ ht->entries++;
+ return 0;
+ }
+
+ double_hash = hash % ht->rehash;
+ if (double_hash == 0)
+ double_hash = 1;
+
+ hash_address = (hash_address + double_hash) % ht->size;
+ } while (hash_address != hash % ht->size);
+
+ /* We could hit here if a required resize failed. An unchecked-malloc
+ * application could ignore this result.
+ */
+ return -1;
+}
+
+/**
+ * This function deletes the given hash table entry.
+ *
+ * Note that deletion doesn't otherwise modify the table, so an iteration over
+ * the table deleting entries is safe.
+ */
+WL_EXPORT void
+wl_hash_table_remove(struct wl_hash_table *ht, uint32_t hash)
+{
+ struct hash_entry *entry;
+
+ entry = hash_table_search(ht, hash);
+ if (entry != NULL) {
+ entry->data = (void *) &deleted_data;
+ ht->entries--;
+ ht->deleted_entries++;
+ }
+}
diff --git a/src/wayland-server.c b/src/wayland-server.c
new file mode 100644
index 0000000..2019cb4
--- /dev/null
+++ b/src/wayland-server.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <ffi.h>
+
+#include "wayland-server.h"
+#include "wayland-server-protocol.h"
+#include "connection.h"
+
+struct wl_socket {
+ int fd;
+ int fd_lock;
+ struct sockaddr_un addr;
+ char lock_addr[113];
+ struct wl_list link;
+};
+
+struct wl_client {
+ struct wl_connection *connection;
+ struct wl_event_source *source;
+ struct wl_display *display;
+ struct wl_list resource_list;
+ uint32_t id_count;
+ uint32_t mask;
+ struct wl_list link;
+};
+
+struct wl_display {
+ struct wl_object object;
+ struct wl_event_loop *loop;
+ struct wl_hash_table *objects;
+ int run;
+
+ struct wl_list frame_list;
+ uint32_t client_id_range;
+ uint32_t id;
+
+ struct wl_list global_list;
+ struct wl_list socket_list;
+ struct wl_list client_list;
+};
+
+struct wl_frame_listener {
+ struct wl_resource resource;
+ struct wl_client *client;
+ uint32_t key;
+ struct wl_surface *surface;
+ struct wl_list link;
+};
+
+struct wl_global {
+ struct wl_object *object;
+ wl_global_bind_func_t func;
+ struct wl_list link;
+};
+
+static int wl_debug = 0;
+
+WL_EXPORT void
+wl_client_post_event(struct wl_client *client, struct wl_object *sender,
+ uint32_t opcode, ...)
+{
+ struct wl_closure *closure;
+ va_list ap;
+
+ va_start(ap, opcode);
+ closure = wl_connection_vmarshal(client->connection,
+ sender, opcode, ap,
+ &sender->interface->events[opcode]);
+ va_end(ap);
+
+ wl_closure_send(closure, client->connection);
+
+ if (wl_debug)
+ wl_closure_print(closure, sender, true);
+
+ wl_closure_destroy(closure);
+}
+
+WL_EXPORT void
+wl_client_post_error(struct wl_client *client, struct wl_object *object,
+ uint32_t code, const char *msg, ...)
+{
+ char buffer[128];
+ va_list ap;
+
+ va_start(ap, msg);
+ vsnprintf(buffer, sizeof buffer, msg, ap);
+ va_end(ap);
+
+ wl_client_post_event(client, &client->display->object,
+ WL_DISPLAY_ERROR, object, code, buffer);
+}
+
+static int
+wl_client_connection_data(int fd, uint32_t mask, void *data)
+{
+ struct wl_client *client = data;
+ struct wl_connection *connection = client->connection;
+ struct wl_object *object;
+ struct wl_closure *closure;
+ const struct wl_message *message;
+ uint32_t p[2], opcode, size;
+ uint32_t cmask = 0;
+ int len;
+
+ if (mask & WL_EVENT_READABLE)
+ cmask |= WL_CONNECTION_READABLE;
+ if (mask & WL_EVENT_WRITEABLE)
+ cmask |= WL_CONNECTION_WRITABLE;
+
+ len = wl_connection_data(connection, cmask);
+ if (len < 0) {
+ wl_client_destroy(client);
+ return 1;
+ }
+
+ while (len >= sizeof p) {
+ wl_connection_copy(connection, p, sizeof p);
+ opcode = p[1] & 0xffff;
+ size = p[1] >> 16;
+ if (len < size)
+ break;
+
+ object = wl_hash_table_lookup(client->display->objects, p[0]);
+ if (object == NULL) {
+ wl_client_post_error(client, &client->display->object,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid object %d", p[0]);
+ wl_connection_consume(connection, size);
+ len -= size;
+ continue;
+ }
+
+ if (opcode >= object->interface->method_count) {
+ wl_client_post_error(client, &client->display->object,
+ WL_DISPLAY_ERROR_INVALID_METHOD,
+ "invalid method %d, object %s@%d",
+ object->interface->name,
+ object->id, opcode);
+ wl_connection_consume(connection, size);
+ len -= size;
+ continue;
+ }
+
+ message = &object->interface->methods[opcode];
+ closure = wl_connection_demarshal(client->connection, size,
+ client->display->objects,
+ message);
+ len -= size;
+
+ if (closure == NULL && errno == EINVAL) {
+ wl_client_post_error(client, &client->display->object,
+ WL_DISPLAY_ERROR_INVALID_METHOD,
+ "invalid arguments for %s@%d.%s",
+ object->interface->name,
+ object->id, message->name);
+ continue;
+ } else if (closure == NULL && errno == ENOMEM) {
+ wl_client_post_no_memory(client);
+ continue;
+ }
+
+
+ if (wl_debug)
+ wl_closure_print(closure, object, false);
+
+ wl_closure_invoke(closure, object,
+ object->implementation[opcode], client);
+
+ wl_closure_destroy(closure);
+ }
+
+ return 1;
+}
+
+static int
+wl_client_connection_update(struct wl_connection *connection,
+ uint32_t mask, void *data)
+{
+ struct wl_client *client = data;
+ uint32_t emask = 0;
+
+ client->mask = mask;
+ if (mask & WL_CONNECTION_READABLE)
+ emask |= WL_EVENT_READABLE;
+ if (mask & WL_CONNECTION_WRITABLE)
+ emask |= WL_EVENT_WRITEABLE;
+
+ return wl_event_source_fd_update(client->source, emask);
+}
+
+WL_EXPORT void
+wl_client_flush(struct wl_client *client)
+{
+ if (client->mask & WL_CONNECTION_WRITABLE)
+ wl_connection_data(client->connection, WL_CONNECTION_WRITABLE);
+}
+
+WL_EXPORT struct wl_display *
+wl_client_get_display(struct wl_client *client)
+{
+ return client->display;
+}
+
+static void
+wl_display_post_range(struct wl_display *display, struct wl_client *client)
+{
+ wl_client_post_event(client, &client->display->object,
+ WL_DISPLAY_RANGE, display->client_id_range);
+ display->client_id_range += 256;
+ client->id_count += 256;
+}
+
+WL_EXPORT struct wl_client *
+wl_client_create(struct wl_display *display, int fd)
+{
+ struct wl_client *client;
+ struct wl_global *global;
+
+ client = malloc(sizeof *client);
+ 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_client_connection_data, client);
+ client->connection =
+ wl_connection_create(fd, wl_client_connection_update, client);
+ if (client->connection == NULL) {
+ free(client);
+ return NULL;
+ }
+
+ wl_list_insert(display->client_list.prev, &client->link);
+
+ wl_list_init(&client->resource_list);
+
+ wl_display_post_range(display, client);
+
+ wl_list_for_each(global, &display->global_list, link)
+ wl_client_post_global(client, global->object);
+
+ return client;
+}
+
+WL_EXPORT void
+wl_client_add_resource(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct wl_display *display = client->display;
+
+ if (client->id_count-- < 64)
+ wl_display_post_range(display, client);
+
+ wl_list_init(&resource->destroy_listener_list);
+
+ wl_hash_table_insert(client->display->objects,
+ resource->object.id, resource);
+ wl_list_insert(client->resource_list.prev, &resource->link);
+}
+
+WL_EXPORT void
+wl_client_post_no_memory(struct wl_client *client)
+{
+ wl_client_post_error(client, &client->display->object,
+ WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
+}
+
+WL_EXPORT void
+wl_client_post_global(struct wl_client *client, struct wl_object *object)
+{
+ wl_client_post_event(client,
+ &client->display->object,
+ WL_DISPLAY_GLOBAL,
+ object->id,
+ object->interface->name,
+ object->interface->version);
+}
+
+WL_EXPORT void
+wl_resource_destroy(struct wl_resource *resource,
+ struct wl_client *client, uint32_t time)
+{
+ struct wl_display *display = client->display;
+ struct wl_listener *l, *next;
+
+ wl_list_for_each_safe(l, next,
+ &resource->destroy_listener_list, link)
+ l->func(l, resource, time);
+
+ wl_list_remove(&resource->link);
+ if (resource->object.id > 0)
+ wl_hash_table_remove(display->objects, resource->object.id);
+ resource->destroy(resource, client);
+}
+
+WL_EXPORT void
+wl_client_destroy(struct wl_client *client)
+{
+ struct wl_resource *resource, *tmp;
+
+ printf("disconnect from client %p\n", client);
+
+ wl_list_for_each_safe(resource, tmp, &client->resource_list, link)
+ wl_resource_destroy(resource, client, 0);
+
+ wl_event_source_remove(client->source);
+ wl_connection_destroy(client->connection);
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static void
+lose_pointer_focus(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
+{
+ struct wl_input_device *device =
+ container_of(listener, struct wl_input_device,
+ pointer_focus_listener);
+
+ wl_input_device_set_pointer_focus(device, NULL, time, 0, 0, 0, 0);
+}
+
+static void
+lose_keyboard_focus(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
+{
+ struct wl_input_device *device =
+ container_of(listener, struct wl_input_device,
+ keyboard_focus_listener);
+
+ wl_input_device_set_keyboard_focus(device, NULL, time);
+}
+
+WL_EXPORT void
+wl_input_device_init(struct wl_input_device *device,
+ struct wl_compositor *compositor)
+{
+ wl_list_init(&device->pointer_focus_listener.link);
+ device->pointer_focus_listener.func = lose_pointer_focus;
+ wl_list_init(&device->keyboard_focus_listener.link);
+ device->keyboard_focus_listener.func = lose_keyboard_focus;
+
+ device->x = 100;
+ device->y = 100;
+ device->compositor = compositor;
+}
+
+WL_EXPORT void
+wl_input_device_set_pointer_focus(struct wl_input_device *device,
+ struct wl_surface *surface,
+ uint32_t time,
+ int32_t x, int32_t y,
+ int32_t sx, int32_t sy)
+{
+ if (device->pointer_focus == surface)
+ return;
+
+ if (device->pointer_focus &&
+ (!surface || device->pointer_focus->client != surface->client))
+ wl_client_post_event(device->pointer_focus->client,
+ &device->object,
+ WL_INPUT_DEVICE_POINTER_FOCUS,
+ time, NULL, 0, 0, 0, 0);
+ if (device->pointer_focus)
+ wl_list_remove(&device->pointer_focus_listener.link);
+
+ if (surface) {
+ wl_client_post_event(surface->client,
+ &device->object,
+ WL_INPUT_DEVICE_POINTER_FOCUS,
+ time, surface, x, y, sx, sy);
+ wl_list_insert(surface->resource.destroy_listener_list.prev,
+ &device->pointer_focus_listener.link);
+ }
+
+ device->pointer_focus = surface;
+ device->pointer_focus_time = time;
+
+}
+
+WL_EXPORT void
+wl_input_device_set_keyboard_focus(struct wl_input_device *device,
+ struct wl_surface *surface,
+ uint32_t time)
+{
+ if (device->keyboard_focus == surface)
+ return;
+
+ if (device->keyboard_focus &&
+ (!surface || device->keyboard_focus->client != surface->client))
+ wl_client_post_event(device->keyboard_focus->client,
+ &device->object,
+ WL_INPUT_DEVICE_KEYBOARD_FOCUS,
+ time, NULL, &device->keys);
+ if (device->keyboard_focus)
+ wl_list_remove(&device->keyboard_focus_listener.link);
+
+ if (surface) {
+ wl_client_post_event(surface->client,
+ &device->object,
+ WL_INPUT_DEVICE_KEYBOARD_FOCUS,
+ time, surface, &device->keys);
+ wl_list_insert(surface->resource.destroy_listener_list.prev,
+ &device->keyboard_focus_listener.link);
+ }
+
+ device->keyboard_focus = surface;
+ device->keyboard_focus_time = time;
+}
+
+WL_EXPORT void
+wl_input_device_end_grab(struct wl_input_device *device, uint32_t time)
+{
+ const struct wl_grab_interface *interface;
+
+ interface = device->grab->interface;
+ interface->end(device->grab, time);
+ device->grab->input_device = NULL;
+ device->grab = NULL;
+
+ wl_list_remove(&device->grab_listener.link);
+}
+
+static void
+lose_grab_surface(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time)
+{
+ struct wl_input_device *device =
+ container_of(listener,
+ struct wl_input_device, grab_listener);
+
+ wl_input_device_end_grab(device, time);
+}
+
+WL_EXPORT void
+wl_input_device_start_grab(struct wl_input_device *device,
+ struct wl_grab *grab,
+ uint32_t button, uint32_t time)
+{
+ struct wl_surface *focus = device->pointer_focus;
+
+ device->grab = grab;
+ device->grab_button = button;
+ device->grab_time = time;
+ device->grab_x = device->x;
+ device->grab_y = device->y;
+
+ device->grab_listener.func = lose_grab_surface;
+ wl_list_insert(focus->resource.destroy_listener_list.prev,
+ &device->grab_listener.link);
+
+ grab->input_device = device;
+}
+
+WL_EXPORT int
+wl_input_device_update_grab(struct wl_input_device *device,
+ struct wl_grab *grab,
+ struct wl_surface *surface, uint32_t time)
+{
+ if (device->grab != &device->motion_grab ||
+ device->grab_time != time ||
+ device->pointer_focus != surface)
+ return -1;
+
+ device->grab = grab;
+ grab->input_device = device;
+
+ return 0;
+}
+
+static void
+display_bind(struct wl_client *client,
+ struct wl_display *display, uint32_t id,
+ const char *interface, uint32_t version)
+{
+ struct wl_global *global;
+
+ wl_list_for_each(global, &display->global_list, link)
+ if (global->object->id == id)
+ break;
+
+ if (&global->link == &display->global_list)
+ wl_client_post_error(client, &client->display->object,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid object %d", id);
+ else if (global->func)
+ global->func(client, global->object, version);
+}
+
+static void
+display_sync(struct wl_client *client,
+ struct wl_display *display, uint32_t key)
+{
+ wl_client_post_event(client, &display->object, WL_DISPLAY_KEY, key, 0);
+}
+
+static void
+destroy_frame_listener(struct wl_resource *resource, struct wl_client *client)
+{
+ struct wl_frame_listener *listener =
+ container_of(resource, struct wl_frame_listener, resource);
+
+ wl_list_remove(&listener->link);
+ free(listener);
+}
+
+static void
+display_frame(struct wl_client *client,
+ struct wl_display *display,
+ struct wl_surface *surface,
+ uint32_t key)
+{
+ struct wl_frame_listener *listener;
+
+ listener = malloc(sizeof *listener);
+ if (listener == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ /* The listener is a resource so we destroy it when the client
+ * goes away. */
+ listener->resource.destroy = destroy_frame_listener;
+ listener->resource.object.id = 0;
+ listener->client = client;
+ listener->key = key;
+ listener->surface = surface;
+ wl_list_init(&listener->resource.destroy_listener_list);
+ wl_list_insert(client->resource_list.prev, &listener->resource.link);
+ wl_list_insert(display->frame_list.prev, &listener->link);
+}
+
+struct wl_display_interface display_interface = {
+ display_bind,
+ display_sync,
+ display_frame
+};
+
+
+WL_EXPORT struct wl_display *
+wl_display_create(void)
+{
+ struct wl_display *display;
+ const char *debug;
+
+ debug = getenv("WAYLAND_DEBUG");
+ if (debug)
+ wl_debug = 1;
+
+ display = malloc(sizeof *display);
+ if (display == NULL)
+ return NULL;
+
+ display->loop = wl_event_loop_create();
+ if (display->loop == NULL) {
+ free(display);
+ return NULL;
+ }
+
+ display->objects = wl_hash_table_create();
+ if (display->objects == NULL) {
+ wl_event_loop_destroy(display->loop);
+ free(display);
+ return NULL;
+ }
+
+ wl_list_init(&display->frame_list);
+ wl_list_init(&display->global_list);
+ wl_list_init(&display->socket_list);
+ wl_list_init(&display->client_list);
+
+ display->client_id_range = 256; /* Gah, arbitrary... */
+
+ display->id = 1;
+ display->object.interface = &wl_display_interface;
+ display->object.implementation = (void (**)(void)) &display_interface;
+ wl_display_add_object(display, &display->object);
+ if (wl_display_add_global(display, &display->object, NULL)) {
+ wl_hash_table_destroy(display->objects);
+ wl_event_loop_destroy(display->loop);
+ free(display);
+ return NULL;
+ }
+
+ return display;
+}
+
+WL_EXPORT void
+wl_display_destroy(struct wl_display *display)
+{
+ struct wl_socket *s, *next;
+ struct wl_global *global, *gnext;
+
+ wl_event_loop_destroy(display->loop);
+ wl_hash_table_destroy(display->objects);
+ wl_list_for_each_safe(s, next, &display->socket_list, link) {
+ close(s->fd);
+ unlink(s->addr.sun_path);
+ close(s->fd_lock);
+ unlink(s->lock_addr);
+ free(s);
+ }
+
+ wl_list_for_each_safe(global, gnext, &display->global_list, link)
+ free(global);
+
+ free(display);
+}
+
+WL_EXPORT void
+wl_display_add_object(struct wl_display *display, struct wl_object *object)
+{
+ object->id = display->id++;
+ wl_hash_table_insert(display->objects, object->id, object);
+}
+
+WL_EXPORT int
+wl_display_add_global(struct wl_display *display,
+ struct wl_object *object, wl_global_bind_func_t func)
+{
+ struct wl_global *global;
+
+ global = malloc(sizeof *global);
+ if (global == NULL)
+ return -1;
+
+ global->object = object;
+ global->func = func;
+ wl_list_insert(display->global_list.prev, &global->link);
+
+ return 0;
+}
+
+WL_EXPORT int
+wl_display_remove_global(struct wl_display *display,
+ struct wl_object *object)
+{
+ struct wl_global *global;
+ struct wl_client *client;
+
+ wl_list_for_each(global, &display->global_list, link)
+ if (global->object == object)
+ break;
+
+ if (&global->link == &display->global_list)
+ return -1;
+
+ wl_list_for_each(client, &display->client_list, link)
+ wl_client_post_event(client,
+ &client->display->object,
+ WL_DISPLAY_GLOBAL_REMOVE,
+ global->object->id);
+ wl_list_remove(&global->link);
+ free(global);
+
+ return 0;
+}
+
+WL_EXPORT void
+wl_display_post_frame(struct wl_display *display, struct wl_surface *surface,
+ uint32_t time)
+{
+ struct wl_frame_listener *listener, *next;
+
+ wl_list_for_each_safe(listener, next, &display->frame_list, link) {
+ if (listener->surface != surface)
+ continue;
+ wl_client_post_event(listener->client, &display->object,
+ WL_DISPLAY_KEY, listener->key, time);
+ wl_resource_destroy(&listener->resource, listener->client, 0);
+ }
+}
+
+WL_EXPORT struct wl_event_loop *
+wl_display_get_event_loop(struct wl_display *display)
+{
+ return display->loop;
+}
+
+WL_EXPORT void
+wl_display_terminate(struct wl_display *display)
+{
+ display->run = 0;
+}
+
+WL_EXPORT void
+wl_display_run(struct wl_display *display)
+{
+ display->run = 1;
+
+ while (display->run)
+ wl_event_loop_dispatch(display->loop, -1);
+}
+
+static int
+socket_data(int fd, uint32_t mask, void *data)
+{
+ struct wl_display *display = data;
+ struct sockaddr_un name;
+ socklen_t length;
+ int client_fd;
+
+ length = sizeof name;
+ client_fd =
+ accept4(fd, (struct sockaddr *) &name, &length, SOCK_CLOEXEC);
+ if (client_fd < 0 && errno == ENOSYS) {
+ client_fd = accept(fd, (struct sockaddr *) &name, &length);
+ if (client_fd >= 0 && fcntl(client_fd, F_SETFD, FD_CLOEXEC) == -1)
+ fprintf(stderr, "failed to set FD_CLOEXEC flag on client fd, errno: %d\n", errno);
+ }
+
+ if (client_fd < 0)
+ fprintf(stderr, "failed to accept, errno: %d\n", errno);
+
+ wl_client_create(display, client_fd);
+
+ return 1;
+}
+
+static int
+get_socket_lock(struct wl_socket *socket, socklen_t name_size)
+{
+ struct stat socket_stat;
+ int lock_size = name_size + 5;
+
+ snprintf(socket->lock_addr, lock_size,
+ "%s.lock", socket->addr.sun_path);
+
+ socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC,
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
+
+ if (socket->fd_lock < 0) {
+ fprintf(stderr,
+ "unable to open lockfile %s check permissions\n",
+ socket->lock_addr);
+ return -1;
+ }
+
+ if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) {
+ fprintf(stderr,
+ "unable to lock lockfile %s, maybe another compositor is running\n",
+ socket->lock_addr);
+ close(socket->fd_lock);
+ return -1;
+ }
+
+ if (stat(socket->addr.sun_path, &socket_stat) < 0 ) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "did not manage to stat file %s\n",
+ socket->addr.sun_path);
+ close(socket->fd_lock);
+ return -1;
+ }
+ } else if (socket_stat.st_mode & S_IWUSR ||
+ socket_stat.st_mode & S_IWGRP) {
+ unlink(socket->addr.sun_path);
+ }
+
+ return 0;
+}
+
+WL_EXPORT int
+wl_display_add_socket(struct wl_display *display, const char *name)
+{
+ struct wl_socket *s;
+ socklen_t size, name_size;
+ const char *runtime_dir;
+
+ s = malloc(sizeof *s);
+ if (s == NULL)
+ return -1;
+
+ s->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (s->fd < 0) {
+ free(s);
+ return -1;
+ }
+
+ runtime_dir = getenv("XDG_RUNTIME_DIR");
+ if (runtime_dir == NULL) {
+ runtime_dir = ".";
+ fprintf(stderr,
+ "XDG_RUNTIME_DIR not set, falling back to %s\n",
+ runtime_dir);
+ }
+
+ if (name == NULL)
+ name = getenv("WAYLAND_DISPLAY");
+ if (name == NULL)
+ name = "wayland-0";
+
+ memset(&s->addr, 0, sizeof s->addr);
+ s->addr.sun_family = AF_LOCAL;
+ name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
+ "%s/%s", runtime_dir, name) + 1;
+ fprintf(stderr, "using socket %s\n", s->addr.sun_path);
+
+ if (get_socket_lock(s,name_size) < 0) {
+ close(s->fd);
+ free(s);
+ return -1;
+ }
+
+ size = offsetof (struct sockaddr_un, sun_path) + name_size;
+ if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
+ close(s->fd);
+ free(s);
+ return -1;
+ }
+
+ if (listen(s->fd, 1) < 0) {
+ close(s->fd);
+ unlink(s->addr.sun_path);
+ free(s);
+ return -1;
+ }
+
+ if (wl_event_loop_add_fd(display->loop, s->fd,
+ WL_EVENT_READABLE,
+ socket_data, display) == NULL) {
+ close(s->fd);
+ unlink(s->addr.sun_path);
+ free(s);
+ return -1;
+ }
+ wl_list_insert(display->socket_list.prev, &s->link);
+
+ return 0;
+}
+
+static void
+compositor_bind(struct wl_client *client,
+ struct wl_object *global, uint32_t version)
+{
+ struct wl_compositor *compositor =
+ container_of(global, struct wl_compositor, object);
+
+ wl_client_post_event(client, global,
+ WL_COMPOSITOR_TOKEN_VISUAL,
+ &compositor->argb_visual.object,
+ WL_COMPOSITOR_VISUAL_ARGB32);
+
+ wl_client_post_event(client, global,
+ WL_COMPOSITOR_TOKEN_VISUAL,
+ &compositor->premultiplied_argb_visual.object,
+ WL_COMPOSITOR_VISUAL_PREMULTIPLIED_ARGB32);
+
+ wl_client_post_event(client, global,
+ WL_COMPOSITOR_TOKEN_VISUAL,
+ &compositor->rgb_visual.object,
+ WL_COMPOSITOR_VISUAL_XRGB32);
+}
+
+WL_EXPORT int
+wl_compositor_init(struct wl_compositor *compositor,
+ const struct wl_compositor_interface *interface,
+ struct wl_display *display)
+{
+ compositor->object.interface = &wl_compositor_interface;
+ compositor->object.implementation = (void (**)(void)) interface;
+ wl_display_add_object(display, &compositor->object);
+ if (wl_display_add_global(display,
+ &compositor->object, compositor_bind))
+ return -1;
+
+ compositor->argb_visual.object.interface = &wl_visual_interface;
+ compositor->argb_visual.object.implementation = NULL;
+ wl_display_add_object(display, &compositor->argb_visual.object);
+ if (wl_display_add_global(display,
+ &compositor->argb_visual.object, NULL))
+ return -1;
+
+ compositor->premultiplied_argb_visual.object.interface =
+ &wl_visual_interface;
+ compositor->premultiplied_argb_visual.object.implementation = NULL;
+ wl_display_add_object(display,
+ &compositor->premultiplied_argb_visual.object);
+ if (wl_display_add_global(display,
+ &compositor->premultiplied_argb_visual.object,
+ NULL))
+ return -1;
+
+ compositor->rgb_visual.object.interface = &wl_visual_interface;
+ compositor->rgb_visual.object.implementation = NULL;
+ wl_display_add_object(display, &compositor->rgb_visual.object);
+ if (wl_display_add_global(display,
+ &compositor->rgb_visual.object, NULL))
+ return -1;
+
+ return 0;
+}
diff --git a/src/wayland-server.h b/src/wayland-server.h
new file mode 100644
index 0000000..69d0d51
--- /dev/null
+++ b/src/wayland-server.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef WAYLAND_H
+#define WAYLAND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include "wayland-util.h"
+#include "wayland-server-protocol.h"
+
+enum {
+ WL_EVENT_READABLE = 0x01,
+ WL_EVENT_WRITEABLE = 0x02
+};
+
+struct wl_event_loop;
+struct wl_event_source;
+typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data);
+typedef int (*wl_event_loop_timer_func_t)(void *data);
+typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data);
+typedef void (*wl_event_loop_idle_func_t)(void *data);
+
+struct wl_event_loop *wl_event_loop_create(void);
+void wl_event_loop_destroy(struct wl_event_loop *loop);
+struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop,
+ int fd, uint32_t mask,
+ wl_event_loop_fd_func_t func,
+ void *data);
+int wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask);
+struct wl_event_source *wl_event_loop_add_timer(struct wl_event_loop *loop,
+ wl_event_loop_timer_func_t func,
+ void *data);
+struct wl_event_source *
+wl_event_loop_add_signal(struct wl_event_loop *loop,
+ int signal_number,
+ wl_event_loop_signal_func_t func,
+ void *data);
+
+int wl_event_source_timer_update(struct wl_event_source *source,
+ int ms_delay);
+int wl_event_source_remove(struct wl_event_source *source);
+void wl_event_source_check(struct wl_event_source *source);
+
+
+int wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout);
+struct wl_event_source *wl_event_loop_add_idle(struct wl_event_loop *loop,
+ wl_event_loop_idle_func_t func,
+ void *data);
+int wl_event_loop_get_fd(struct wl_event_loop *loop);
+
+struct wl_client;
+struct wl_display;
+struct wl_input_device;
+
+struct wl_display *wl_display_create(void);
+void wl_display_destroy(struct wl_display *display);
+struct wl_event_loop *wl_display_get_event_loop(struct wl_display *display);
+int wl_display_add_socket(struct wl_display *display, const char *name);
+void wl_display_terminate(struct wl_display *display);
+void wl_display_run(struct wl_display *display);
+
+void wl_display_add_object(struct wl_display *display,
+ struct wl_object *object);
+
+typedef void (*wl_global_bind_func_t)(struct wl_client *client,
+ struct wl_object *global,
+ uint32_t version);
+
+int wl_display_add_global(struct wl_display *display,
+ struct wl_object *object,
+ wl_global_bind_func_t func);
+
+int wl_display_remove_global(struct wl_display *display,
+ struct wl_object *object);
+
+struct wl_client *wl_client_create(struct wl_display *display, int fd);
+void wl_client_destroy(struct wl_client *client);
+void wl_client_post_error(struct wl_client *client, struct wl_object *object,
+ uint32_t code, const char *msg, ...);
+void wl_client_post_no_memory(struct wl_client *client);
+void wl_client_post_global(struct wl_client *client, struct wl_object *object);
+void wl_client_flush(struct wl_client *client);
+
+struct wl_visual {
+ struct wl_object object;
+};
+
+struct wl_shm_callbacks {
+ void (*buffer_created)(struct wl_buffer *buffer);
+
+ void (*buffer_damaged)(struct wl_buffer *buffer,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height);
+
+ void (*buffer_destroyed)(struct wl_buffer *buffer);
+};
+
+struct wl_compositor {
+ struct wl_object object;
+ struct wl_visual argb_visual;
+ struct wl_visual premultiplied_argb_visual;
+ struct wl_visual rgb_visual;
+};
+
+struct wl_resource {
+ struct wl_object object;
+ void (*destroy)(struct wl_resource *resource,
+ struct wl_client *client);
+ struct wl_list link;
+ struct wl_list destroy_listener_list;
+};
+
+struct wl_buffer {
+ struct wl_resource resource;
+ struct wl_client *client;
+ struct wl_visual *visual;
+ int32_t width, height;
+ uint32_t busy_count;
+ void *user_data;
+};
+
+struct wl_listener {
+ struct wl_list link;
+ void (*func)(struct wl_listener *listener,
+ struct wl_resource *resource, uint32_t time);
+};
+
+struct wl_surface {
+ struct wl_resource resource;
+ struct wl_client *client;
+};
+
+struct wl_grab;
+struct wl_grab_interface {
+ void (*motion)(struct wl_grab *grab,
+ uint32_t time, int32_t x, int32_t y);
+ void (*button)(struct wl_grab *grab,
+ uint32_t time, int32_t button, int32_t state);
+ void (*end)(struct wl_grab *grab, uint32_t time);
+};
+
+struct wl_grab {
+ const struct wl_grab_interface *interface;
+ struct wl_input_device *input_device;
+};
+
+struct wl_input_device {
+ struct wl_object object;
+ struct wl_compositor *compositor;
+ struct wl_surface *pointer_focus;
+ struct wl_surface *keyboard_focus;
+ struct wl_array keys;
+ uint32_t pointer_focus_time;
+ uint32_t keyboard_focus_time;
+ struct wl_listener pointer_focus_listener;
+ struct wl_listener keyboard_focus_listener;
+
+ int32_t x, y;
+ struct wl_grab *grab;
+ struct wl_grab motion_grab;
+ uint32_t grab_time;
+ int32_t grab_x, grab_y;
+ uint32_t grab_button;
+ struct wl_listener grab_listener;
+};
+
+struct wl_drag_offer {
+ struct wl_object object;
+};
+
+struct wl_drag {
+ struct wl_resource resource;
+ struct wl_grab grab;
+ struct wl_drag_offer drag_offer;
+ struct wl_surface *source;
+ struct wl_surface *drag_focus;
+ struct wl_client *target;
+ int32_t x, y, sx, sy;
+ struct wl_array types;
+ const char *type;
+ uint32_t pointer_focus_time;
+ struct wl_listener drag_focus_listener;
+};
+
+struct wl_selection_offer {
+ struct wl_object object;
+};
+
+struct wl_selection {
+ struct wl_resource resource;
+ struct wl_client *client;
+ struct wl_input_device *input_device;
+ struct wl_selection_offer selection_offer;
+ struct wl_surface *selection_focus;
+ struct wl_client *target;
+ struct wl_array types;
+ struct wl_listener selection_focus_listener;
+};
+
+void
+wl_client_post_event(struct wl_client *client,
+ struct wl_object *sender,
+ uint32_t event, ...);
+
+int
+wl_display_set_compositor(struct wl_display *display,
+ struct wl_compositor *compositor,
+ const struct wl_compositor_interface *implementation);
+
+void
+wl_display_post_frame(struct wl_display *display, struct wl_surface *surface,
+ uint32_t msecs);
+
+void
+wl_client_add_resource(struct wl_client *client,
+ struct wl_resource *resource);
+
+struct wl_display *
+wl_client_get_display(struct wl_client *client);
+
+void
+wl_resource_destroy(struct wl_resource *resource,
+ struct wl_client *client, uint32_t time);
+
+void
+wl_input_device_init(struct wl_input_device *device,
+ struct wl_compositor *compositor);
+
+void
+wl_input_device_set_pointer_focus(struct wl_input_device *device,
+ struct wl_surface *surface,
+ uint32_t time,
+ int32_t x, int32_t y,
+ int32_t sx, int32_t sy);
+
+void
+wl_input_device_set_keyboard_focus(struct wl_input_device *device,
+ struct wl_surface *surface,
+ uint32_t time);
+
+void
+wl_input_device_end_grab(struct wl_input_device *device, uint32_t time);
+void
+wl_input_device_start_grab(struct wl_input_device *device,
+ struct wl_grab *grab,
+ uint32_t button, uint32_t time);
+int
+wl_input_device_update_grab(struct wl_input_device *device,
+ struct wl_grab *grab,
+ struct wl_surface *surface, uint32_t time);
+
+struct wl_shm;
+
+void *
+wl_shm_buffer_get_data(struct wl_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_stride(struct wl_buffer *buffer);
+
+struct wl_buffer *
+wl_shm_buffer_create(struct wl_shm *shm, int width, int height,
+ int stride, struct wl_visual *visual,
+ void *data);
+
+int
+wl_buffer_is_shm(struct wl_buffer *buffer);
+
+struct wl_shm *
+wl_shm_init(struct wl_display *display,
+ const struct wl_shm_callbacks *callbacks);
+
+void
+wl_shm_finish(struct wl_shm *shm);
+
+int
+wl_compositor_init(struct wl_compositor *compositor,
+ const struct wl_compositor_interface *interface,
+ struct wl_display *display);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/wayland-server.pc.in b/src/wayland-server.pc.in
new file mode 100644
index 0000000..b317461
--- /dev/null
+++ b/src/wayland-server.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: Wayland Server
+Description: Server side implementation of the Wayland protocol
+Version: 0.1
+Cflags: -I${includedir}
+Libs: -L${libdir} -lwayland-server
diff --git a/src/wayland-shm.c b/src/wayland-shm.c
new file mode 100644
index 0000000..90d2fcf
--- /dev/null
+++ b/src/wayland-shm.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Kristian Høgsberg <krh@bitplanet.net>
+ * Benjamin Franzke <benjaminfranzke@googlemail.com>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "wayland-server.h"
+
+struct wl_shm {
+ struct wl_object object;
+ const struct wl_shm_callbacks *callbacks;
+};
+
+struct wl_shm_buffer {
+ struct wl_buffer buffer;
+ struct wl_shm *shm;
+ int32_t stride;
+ void *data;
+};
+
+static void
+destroy_buffer(struct wl_resource *resource, struct wl_client *client)
+{
+ struct wl_shm_buffer *buffer =
+ container_of(resource, struct wl_shm_buffer, buffer.resource);
+
+ munmap(buffer->data, buffer->stride * buffer->buffer.height);
+
+ buffer->shm->callbacks->buffer_destroyed(&buffer->buffer);
+
+ free(buffer);
+}
+
+static void
+shm_buffer_damage(struct wl_client *client, struct wl_buffer *buffer_base,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
+
+ buffer->shm->callbacks->buffer_damaged(buffer_base, x, y,
+ width, height);
+}
+
+static void
+shm_buffer_destroy(struct wl_client *client, struct wl_buffer *buffer)
+{
+ wl_resource_destroy(&buffer->resource, client, 0);
+}
+
+const static struct wl_buffer_interface shm_buffer_interface = {
+ shm_buffer_damage,
+ shm_buffer_destroy
+};
+
+static struct wl_shm_buffer *
+wl_shm_buffer_init(struct wl_shm *shm, struct wl_client *client, uint32_t id,
+ int32_t width, int32_t height,
+ int32_t stride, struct wl_visual *visual,
+ void *data)
+{
+ struct wl_shm_buffer *buffer;
+
+ buffer = calloc(1, sizeof *buffer);
+ if (buffer == NULL)
+ return NULL;
+
+ buffer->buffer.width = width;
+ buffer->buffer.height = height;
+ buffer->buffer.visual = visual;
+ buffer->buffer.client = client;
+ buffer->stride = stride;
+ buffer->data = data;
+
+ buffer->buffer.resource.object.id = id;
+ buffer->buffer.resource.object.interface = &wl_buffer_interface;
+ buffer->buffer.resource.object.implementation = (void (**)(void))
+ &shm_buffer_interface;
+
+ buffer->buffer.resource.destroy = destroy_buffer;
+
+ buffer->shm = shm;
+
+ buffer->shm->callbacks->buffer_created(&buffer->buffer);
+
+ return buffer;
+}
+
+static void
+shm_create_buffer(struct wl_client *client, struct wl_shm *shm,
+ uint32_t id, int fd, int32_t width, int32_t height,
+ uint32_t stride, struct wl_visual *visual)
+{
+ struct wl_shm_buffer *buffer;
+ void *data;
+
+ if (!visual || visual->object.interface != &wl_visual_interface) {
+ wl_client_post_error(client, &shm->object,
+ WL_SHM_ERROR_INVALID_VISUAL,
+ "invalid visual");
+ close(fd);
+ return;
+ }
+
+ if (width < 0 || height < 0 || stride < width) {
+ wl_client_post_error(client, &shm->object,
+ WL_SHM_ERROR_INVALID_STRIDE,
+ "invalid width, height or stride (%dx%d, %u)",
+ width, height, stride);
+ close(fd);
+ return;
+ }
+
+ data = mmap(NULL, stride * height,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ close(fd);
+ if (data == MAP_FAILED) {
+ wl_client_post_error(client, &shm->object,
+ WL_SHM_ERROR_INVALID_FD,
+ "failed mmap fd %d", fd);
+ return;
+ }
+
+ buffer = wl_shm_buffer_init(shm, client, id,
+ width, height, stride, visual,
+ data);
+ if (buffer == NULL) {
+ munmap(data, stride * height);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_client_add_resource(client, &buffer->buffer.resource);
+}
+
+const static struct wl_shm_interface shm_interface = {
+ shm_create_buffer
+};
+
+
+WL_EXPORT struct wl_shm *
+wl_shm_init(struct wl_display *display,
+ const struct wl_shm_callbacks *callbacks)
+{
+ struct wl_shm *shm;
+
+ shm = malloc(sizeof *shm);
+ if (!shm)
+ return NULL;
+
+ shm->object.interface = &wl_shm_interface;
+ shm->object.implementation = (void (**)(void)) &shm_interface;
+ wl_display_add_object(display, &shm->object);
+ wl_display_add_global(display, &shm->object, NULL);
+
+ shm->callbacks = callbacks;
+
+ return shm;
+}
+
+WL_EXPORT void
+wl_shm_finish(struct wl_shm *shm)
+{
+ /* FIXME: add wl_display_del_{object,global} */
+
+ free(shm);
+}
+
+WL_EXPORT int
+wl_buffer_is_shm(struct wl_buffer *buffer)
+{
+ return buffer->resource.object.implementation ==
+ (void (**)(void)) &shm_buffer_interface;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_stride(struct wl_buffer *buffer_base)
+{
+ struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
+
+ if (!wl_buffer_is_shm(buffer_base))
+ return 0;
+
+ return buffer->stride;
+}
+
+WL_EXPORT void *
+wl_shm_buffer_get_data(struct wl_buffer *buffer_base)
+{
+ struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
+
+ if (!wl_buffer_is_shm(buffer_base))
+ return NULL;
+
+ return buffer->data;
+}
diff --git a/src/wayland-util.c b/src/wayland-util.c
new file mode 100644
index 0000000..3643274
--- /dev/null
+++ b/src/wayland-util.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "wayland-util.h"
+
+WL_EXPORT void
+wl_list_init(struct wl_list *list)
+{
+ list->prev = list;
+ list->next = list;
+}
+
+WL_EXPORT 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;
+}
+
+WL_EXPORT void
+wl_list_remove(struct wl_list *elm)
+{
+ elm->prev->next = elm->next;
+ elm->next->prev = elm->prev;
+}
+
+WL_EXPORT int
+wl_list_length(struct wl_list *list)
+{
+ struct wl_list *e;
+ int count;
+
+ count = 0;
+ e = list->next;
+ while (e != list) {
+ e = e->next;
+ count++;
+ }
+
+ return count;
+}
+
+WL_EXPORT int
+wl_list_empty(struct wl_list *list)
+{
+ return list->next == list;
+}
+
+WL_EXPORT void
+wl_array_init(struct wl_array *array)
+{
+ memset(array, 0, sizeof *array);
+}
+
+WL_EXPORT void
+wl_array_release(struct wl_array *array)
+{
+ free(array->data);
+}
+
+WL_EXPORT void *
+wl_array_add(struct wl_array *array, int size)
+{
+ int alloc;
+ void *data, *p;
+
+ if (array->alloc > 0)
+ alloc = array->alloc;
+ else
+ alloc = 16;
+
+ while (alloc < array->size + size)
+ alloc *= 2;
+
+ if (array->alloc < alloc) {
+ if (array->alloc > 0)
+ data = realloc(array->data, alloc);
+ else
+ data = malloc(alloc);
+
+ if (data == NULL)
+ return 0;
+ array->data = data;
+ array->alloc = alloc;
+ }
+
+ p = array->data + array->size;
+ array->size += size;
+
+ return p;
+}
+
+WL_EXPORT void
+wl_array_copy(struct wl_array *array, struct wl_array *source)
+{
+ array->size = 0;
+ wl_array_add(array, source->size);
+ memcpy(array->data, source->data, source->size);
+}
diff --git a/src/wayland-util.h b/src/wayland-util.h
new file mode 100644
index 0000000..a9f869a
--- /dev/null
+++ b/src/wayland-util.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef WAYLAND_UTIL_H
+#define WAYLAND_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.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 ALIGN(n, a) ( ((n) + ((a) - 1)) & ~((a) - 1) )
+#define DIV_ROUNDUP(n, a) ( ((n) + ((a) - 1)) / (a) )
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct wl_message {
+ const char *name;
+ const char *signature;
+ const struct wl_interface **types;
+};
+
+struct wl_interface {
+ const char *name;
+ int version;
+ int method_count;
+ const struct wl_message *methods;
+ int event_count;
+ const struct wl_message *events;
+};
+
+struct wl_object {
+ const struct wl_interface *interface;
+ void (**implementation)(void);
+ uint32_t id;
+};
+
+struct wl_hash_table;
+struct wl_hash_table *wl_hash_table_create(void);
+void wl_hash_table_destroy(struct wl_hash_table *ht);
+void *wl_hash_table_lookup(struct wl_hash_table *ht, uint32_t hash);
+int wl_hash_table_insert(struct wl_hash_table *ht, uint32_t hash, void *data);
+void wl_hash_table_remove(struct wl_hash_table *ht, uint32_t hash);
+
+/**
+ * wl_list - linked list
+ *
+ * The list head is of "struct wl_list" type, and must be initialized
+ * using wl_list_init(). All entries in the list must be of the same
+ * type. The item type must have a "struct wl_list" member. This
+ * member will be initialized by wl_list_insert(). There is no need to
+ * call wl_list_init() on the individual item. To query if the list is
+ * empty in O(1), use wl_list_empty().
+ *
+ * Let's call the list reference "struct wl_list foo_list", the item type as
+ * "item_t", and the item member as "struct wl_list link". The following code
+ *
+ * The following code will initialize a list:
+ *
+ * wl_list_init(foo_list);
+ * wl_list_insert(foo_list, item1); Pushes item1 at the head
+ * wl_list_insert(foo_list, item2); Pushes item2 at the head
+ * wl_list_insert(item2, item3); Pushes item3 after item2
+ *
+ * The list now looks like [item2, item3, item1]
+ *
+ * Will iterate the list in ascending order:
+ *
+ * item_t *item;
+ * wl_list_for_each(item, foo_list, link) {
+ * Do_something_with_item(item);
+ * }
+ */
+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);
+int wl_list_empty(struct wl_list *list);
+
+#define __container_of(ptr, sample, member) \
+ (void *)((char *)(ptr) - \
+ ((char *)&(sample)->member - (char *)(sample)))
+
+#define wl_list_for_each(pos, head, member) \
+ for (pos = 0, pos = __container_of((head)->next, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.next, pos, member))
+
+#define wl_list_for_each_safe(pos, tmp, head, member) \
+ for (pos = 0, tmp = 0, \
+ pos = __container_of((head)->next, pos, member), \
+ tmp = __container_of((pos)->member.next, tmp, member); \
+ &pos->member != (head); \
+ pos = tmp, \
+ tmp = __container_of(pos->member.next, tmp, member))
+
+#define wl_list_for_each_reverse(pos, head, member) \
+ for (pos = 0, pos = __container_of((head)->prev, pos, member); \
+ &pos->member != (head); \
+ pos = __container_of(pos->member.prev, pos, member))
+
+struct wl_array {
+ uint32_t size;
+ uint32_t alloc;
+ void *data;
+};
+
+void wl_array_init(struct wl_array *array);
+void wl_array_release(struct wl_array *array);
+void *wl_array_add(struct wl_array *array, int size);
+void wl_array_copy(struct wl_array *array, struct wl_array *source);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif