mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-08 13:29:47 -05:00
Move core protocol libraries into wayland/ subdirectory
This commit is contained in:
parent
76b43326a5
commit
6dd08ebbe1
20 changed files with 69 additions and 61 deletions
61
wayland/Makefile
Normal file
61
wayland/Makefile
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
include ../config.mk
|
||||
|
||||
libs = libwayland-server.so libwayland-client.so
|
||||
|
||||
all : $(libs) scanner
|
||||
|
||||
headers = \
|
||||
wayland-util.h \
|
||||
wayland-server-protocol.h \
|
||||
wayland-server.h \
|
||||
wayland-client-protocol.h \
|
||||
wayland-client.h \
|
||||
|
||||
libwayland-server.so : \
|
||||
wayland-protocol.o \
|
||||
wayland-server.o \
|
||||
event-loop.o \
|
||||
connection.o \
|
||||
wayland-util.o \
|
||||
wayland-hash.o
|
||||
|
||||
libwayland-client.so : \
|
||||
wayland-protocol.o \
|
||||
wayland-client.o \
|
||||
connection.o \
|
||||
wayland-util.o \
|
||||
wayland-hash.o
|
||||
|
||||
wayland-server.o : wayland-server-protocol.h
|
||||
wayland-client.o : wayland-client-protocol.h
|
||||
|
||||
wayland-protocol.c : protocol.xml scanner
|
||||
./scanner code < $< > $@
|
||||
|
||||
wayland-server-protocol.h : protocol.xml scanner
|
||||
./scanner server-header < $< > $@
|
||||
|
||||
wayland-client-protocol.h : protocol.xml scanner
|
||||
./scanner client-header < $< > $@
|
||||
|
||||
$(libs) : CFLAGS += -fPIC $(FFI_CFLAGS)
|
||||
$(libs) : LDLIBS += $(FFI_LIBS)
|
||||
$(libs) :
|
||||
gcc -shared $^ $(LDLIBS) -o $@
|
||||
|
||||
scanner : \
|
||||
scanner.o \
|
||||
wayland-util.o
|
||||
|
||||
scanner : LDLIBS += $(EXPAT_LIBS)
|
||||
|
||||
install : $(libs) compositor
|
||||
install -d $(libdir) $(includedir) $(libdir)/pkgconfig
|
||||
install wayland-server.pc wayland-client.pc $(libdir)/pkgconfig
|
||||
install $(libs) $(libdir)
|
||||
install $(headers) $(includedir)
|
||||
|
||||
clean :
|
||||
rm -f scanner *.o *.so .*.deps
|
||||
rm -f wayland-protocol.c \
|
||||
wayland-server-protocol.h wayland-client-protocol.h
|
||||
718
wayland/connection.c
Normal file
718
wayland/connection.c
Normal file
|
|
@ -0,0 +1,718 @@
|
|||
/*
|
||||
* 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 <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 "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 fds_in_tail;
|
||||
int fd;
|
||||
void *data;
|
||||
wl_connection_update_func_t update;
|
||||
struct wl_closure 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);
|
||||
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;
|
||||
connection->fds_in.tail = connection->fds_in_tail;
|
||||
}
|
||||
|
||||
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_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, 0);
|
||||
} 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;
|
||||
}
|
||||
|
||||
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, 0);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return connection->in.head - connection->in.tail;
|
||||
}
|
||||
|
||||
void
|
||||
wl_connection_write(struct wl_connection *connection,
|
||||
const void *data, size_t count)
|
||||
{
|
||||
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 (uint32_t);
|
||||
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->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;
|
||||
|
||||
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':
|
||||
fd = va_arg(ap, int);
|
||||
dup_fd = dup(fd);
|
||||
if (dup_fd < 0) {
|
||||
fprintf(stderr, "dup failed: %m");
|
||||
abort();
|
||||
}
|
||||
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->closure;
|
||||
|
||||
count = strlen(message->signature) + 2;
|
||||
if (count > ARRAY_LENGTH(closure->types)) {
|
||||
printf("too many args (%d)\n", count);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
extra_space = wl_message_size_extra(message);
|
||||
if (sizeof closure->buffer < size + extra_space) {
|
||||
printf("request too big, should malloc tmp buffer here\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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] = ⌖
|
||||
|
||||
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)
|
||||
{
|
||||
union wl_value *value;
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "%s@%d.%s(",
|
||||
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':
|
||||
fprintf(stderr, "object %u",
|
||||
value->object ? value->object->id : 0);
|
||||
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)
|
||||
{
|
||||
}
|
||||
68
wayland/connection.h
Normal file
68
wayland/connection.h
Normal file
|
|
@ -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);
|
||||
void
|
||||
wl_closure_destroy(struct wl_closure *closure);
|
||||
|
||||
#endif
|
||||
457
wayland/event-loop.c
Normal file
457
wayland/event-loop.c
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* 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 idle_list;
|
||||
};
|
||||
|
||||
struct wl_event_source_interface {
|
||||
void (*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_event_source_fd {
|
||||
struct wl_event_source base;
|
||||
int fd;
|
||||
wl_event_loop_fd_func_t func;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
fd_source->func(fd_source->fd, mask, fd_source->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;
|
||||
source->fd = fd;
|
||||
source->func = func;
|
||||
source->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;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
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);
|
||||
|
||||
timer_source->func(timer_source->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;
|
||||
struct wl_event_loop *loop = source->loop;
|
||||
int fd;
|
||||
|
||||
fd = timer_source->fd;
|
||||
free(source);
|
||||
|
||||
return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
source->fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (source->fd < 0) {
|
||||
fprintf(stderr, "could not create timerfd\n: %m");
|
||||
free(source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
source->func = func;
|
||||
source->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) {
|
||||
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 = 0;
|
||||
its.it_value.tv_nsec = ms_delay * 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;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
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);
|
||||
|
||||
signal_source->func(signal_source->signal_number, signal_source->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;
|
||||
struct wl_event_loop *loop = source->loop;
|
||||
int fd;
|
||||
|
||||
fd = signal_source->fd;
|
||||
free(source);
|
||||
|
||||
return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signal_number);
|
||||
source->fd = signalfd(-1, &mask, 0);
|
||||
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->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) {
|
||||
free(source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &source->base;
|
||||
}
|
||||
|
||||
struct wl_event_source_idle {
|
||||
struct wl_event_source base;
|
||||
struct wl_list link;
|
||||
wl_event_loop_idle_func_t func;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
wl_event_source_idle_dispatch(struct wl_event_source *source,
|
||||
struct epoll_event *ep)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static int
|
||||
wl_event_source_idle_remove(struct wl_event_source *source)
|
||||
{
|
||||
struct wl_event_source_idle *idle_source =
|
||||
(struct wl_event_source_idle *) source;
|
||||
|
||||
wl_list_remove(&idle_source->link);
|
||||
free(source);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct wl_event_source_interface idle_source_interface = {
|
||||
wl_event_source_idle_dispatch,
|
||||
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->data = data;
|
||||
wl_list_insert(loop->idle_list.prev, &source->link);
|
||||
|
||||
return &source->base;
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_event_source_remove(struct wl_event_source *source)
|
||||
{
|
||||
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_create(16);
|
||||
if (loop->epoll_fd < 0) {
|
||||
free(loop);
|
||||
return NULL;
|
||||
}
|
||||
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 void
|
||||
dispatch_idles(struct wl_event_loop *loop)
|
||||
{
|
||||
struct wl_event_source_idle *source, *next;
|
||||
|
||||
source = container_of(loop->idle_list.next,
|
||||
struct wl_event_source_idle, link);
|
||||
|
||||
while (&source->link != &loop->idle_list) {
|
||||
source->func(source->data);
|
||||
next = container_of(source->link.next,
|
||||
struct wl_event_source_idle, link);
|
||||
free(source);
|
||||
source = next;
|
||||
}
|
||||
|
||||
wl_list_init(&loop->idle_list);
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_event_loop_wait(struct wl_event_loop *loop)
|
||||
{
|
||||
struct epoll_event ep[32];
|
||||
struct wl_event_source *source;
|
||||
int i, count, timeout;
|
||||
|
||||
if (wl_list_empty(&loop->idle_list))
|
||||
timeout = -1;
|
||||
else
|
||||
timeout = 0;
|
||||
|
||||
count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
|
||||
if (count < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
source = ep[i].data.ptr;
|
||||
source->interface->dispatch(source, &ep[i]);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
dispatch_idles(loop);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
266
wayland/protocol.xml
Normal file
266
wayland/protocol.xml
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
<protocol>
|
||||
|
||||
<interface name="display" version="1">
|
||||
<request name="sync">
|
||||
<arg name="key" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="frame">
|
||||
<arg name="key" type="uint"/>
|
||||
</request>
|
||||
|
||||
<event name="invalid_object">
|
||||
<arg name="object_id" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="invalid_method">
|
||||
<arg name="object_id" type="uint"/>
|
||||
<arg name="opcode" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="no_memory"/>
|
||||
|
||||
<event name="global">
|
||||
<arg name="id" type="new_id" interface="object"/>
|
||||
<arg name="name" type="string"/>
|
||||
<arg name="version" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="range">
|
||||
<arg name="base" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="sync">
|
||||
<arg name="key" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="frame">
|
||||
<arg name="key" type="uint"/>
|
||||
<arg name="time" type="uint"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="compositor" version="1">
|
||||
<request name="create_surface">
|
||||
<arg name="id" type="new_id" interface="surface"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="drm" version="1">
|
||||
<!-- dri2 auth and create buffer -->
|
||||
<request name="authenticate">
|
||||
<arg name="id" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="create_buffer">
|
||||
<arg name="id" type="new_id" interface="buffer"/>
|
||||
<arg name="name" type="uint"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
<arg name="stride" type="uint"/>
|
||||
<arg name="visual" type="object" interface="visual"/>
|
||||
</request>
|
||||
|
||||
<event name="device">
|
||||
<arg name="name" type="string"/>
|
||||
</event>
|
||||
|
||||
<event name="authenticated"/>
|
||||
</interface>
|
||||
|
||||
<interface name="buffer" version="1">
|
||||
<request name="destroy" type="destructor"/>
|
||||
</interface>
|
||||
|
||||
<interface name="shell" version="1">
|
||||
<request name="move">
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="input_device" type="object" interface="input_device"/>
|
||||
<arg name="time" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="resize">
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="input_device" type="object" interface="input_device"/>
|
||||
<arg name="time" type="uint"/>
|
||||
<!-- edges is an enum, need to get the values in here -->
|
||||
<arg name="edges" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="create_drag">
|
||||
<arg name="id" type="new_id" interface="drag"/>
|
||||
</request>
|
||||
|
||||
<event name="configure">
|
||||
<arg name="time" type="uint"/>
|
||||
<!-- Same as edges except also move (16) -->
|
||||
<arg name="type" type="uint"/>
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="drag" version="1">
|
||||
<!-- Add an offered mime type. Can be called several times to
|
||||
offer multiple types, but must be called before 'activate'. -->
|
||||
<request name="offer">
|
||||
<arg name="type" type="string"/>
|
||||
</request>
|
||||
|
||||
<request name="activate">
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="input_device" type="object" interface="input_device"/>
|
||||
<arg name="time" type="uint"/>
|
||||
</request>
|
||||
|
||||
<!-- Destroy the drag and cancel the session. -->
|
||||
<request name="destroy" type="destructor"/>
|
||||
|
||||
<!-- Sent when a target accepts pointer_focus or motion events.
|
||||
If a target does not accept any of the offered types, type is
|
||||
NULL -->
|
||||
<event name="target">
|
||||
<arg name="mime_type" type="string"/>
|
||||
</event>
|
||||
|
||||
<!-- Sent when the drag is finished. The final mime type is that
|
||||
of the last target event. If that was NULL, no drag target
|
||||
was valid when the drag finished, fd is undefined and the
|
||||
source should not send data. The event is also sent in case
|
||||
a drag source tries to activate a drag after the grab was
|
||||
released, in which case mime_type will also be NULL. -->
|
||||
<event name="finish">
|
||||
<arg name="fd" type="fd"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
|
||||
<interface name="drag_offer" version="1">
|
||||
<!-- Call to accept the offer of the given type -->
|
||||
<request name="accept">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="type" type="string"/>
|
||||
</request>
|
||||
|
||||
<!-- Called to initiate the drag finish sequence. Sends the pipe
|
||||
fd to the compositor, which forwards it to the source in the
|
||||
'finish' event -->
|
||||
<request name="receive">
|
||||
<arg name="fd" type="fd"/>
|
||||
</request>
|
||||
|
||||
<!-- Sent before the pointer_focus event to announce the types
|
||||
offered. One event per offered mime type. -->
|
||||
<event name="offer">
|
||||
<arg name="type" type="string"/>
|
||||
</event>
|
||||
|
||||
<!-- Similar to device::pointer_focus. Sent to potential target
|
||||
surfaces to offer drag data. If the device leaves the
|
||||
window, the drag stops or the originator cancels the drag,
|
||||
this event is sent with the NULL surface, at which point the
|
||||
drag object may no longer be valid. -->
|
||||
<event name="pointer_focus">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="surface_x" type="int"/>
|
||||
<arg name="surface_y" type="int"/>
|
||||
</event>
|
||||
|
||||
<!-- Similar to device::motion. Sent to potential target surfaces
|
||||
as the drag pointer moves around in the surface. -->
|
||||
<event name="motion">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="surface_x" type="int"/>
|
||||
<arg name="surface_y" type="int"/>
|
||||
</event>
|
||||
|
||||
<!-- Sent to indicate that the drag is finishing. The last
|
||||
motion/pointer_focus event gives the location of the drop.
|
||||
Target must respond with the 'receive' request, which sends
|
||||
an fd to the source for writing the drag data. -->
|
||||
<event name="drop"/>
|
||||
</interface>
|
||||
|
||||
<interface name="surface" version="1">
|
||||
<request name="destroy" type="destructor"/>
|
||||
|
||||
<request name="attach">
|
||||
<arg name="buffer" type="object" interface="buffer"/>
|
||||
</request>
|
||||
|
||||
<request name="map">
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</request>
|
||||
|
||||
<request name="damage">
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="input_device" version="1">
|
||||
<request name="attach">
|
||||
<arg name="buffer" type="object" interface="buffer"/>
|
||||
<arg name="hotspot_x" type="int"/>
|
||||
<arg name="hotspot_y" type="int"/>
|
||||
</request>
|
||||
|
||||
<event name="motion">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="surface_x" type="int"/>
|
||||
<arg name="surface_y" type="int"/>
|
||||
</event>
|
||||
|
||||
<event name="button">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="button" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="key">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="key" type="uint"/>
|
||||
<arg name="state" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="pointer_focus">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="x" type="int"/>
|
||||
<arg name="y" type="int"/>
|
||||
<arg name="surface_x" type="int"/>
|
||||
<arg name="surface_y" type="int"/>
|
||||
</event>
|
||||
|
||||
<event name="keyboard_focus">
|
||||
<arg name="time" type="uint"/>
|
||||
<arg name="surface" type="object" interface="surface"/>
|
||||
<arg name="keys" type="array"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="output" version="1">
|
||||
<event name="geometry">
|
||||
<arg name="width" type="int"/>
|
||||
<arg name="height" type="int"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="visual" version="1">
|
||||
|
||||
</protocol>
|
||||
677
wayland/scanner.c
Normal file
677
wayland/scanner.c
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <expat.h>
|
||||
|
||||
#include "wayland-util.h"
|
||||
|
||||
static const char copyright[] =
|
||||
"/*\n"
|
||||
" * Copyright © 2010 Kristian Høgsberg\n"
|
||||
" *\n"
|
||||
" * Permission to use, copy, modify, distribute, and sell this software and its\n"
|
||||
" * documentation for any purpose is hereby granted without fee, provided that\n"
|
||||
" * the above copyright notice appear in all copies and that both that copyright\n"
|
||||
" * notice and this permission notice appear in supporting documentation, and\n"
|
||||
" * that the name of the copyright holders not be used in advertising or\n"
|
||||
" * publicity pertaining to distribution of the software without specific,\n"
|
||||
" * written prior permission. The copyright holders make no representations\n"
|
||||
" * about the suitability of this software for any purpose. It is provided \"as\n"
|
||||
" * is\" without express or implied warranty.\n"
|
||||
" *\n"
|
||||
" * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,\n"
|
||||
" * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO\n"
|
||||
" * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR\n"
|
||||
" * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,\n"
|
||||
" * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n"
|
||||
" * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\n"
|
||||
" * OF THIS SOFTWARE.\n"
|
||||
" */\n";
|
||||
|
||||
static int
|
||||
usage(int ret)
|
||||
{
|
||||
fprintf(stderr, "usage: ./scanner [header|code]\n");
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
#define XML_BUFFER_SIZE 4096
|
||||
|
||||
struct protocol {
|
||||
struct wl_list interface_list;
|
||||
};
|
||||
|
||||
struct interface {
|
||||
char *name;
|
||||
char *uppercase_name;
|
||||
int version;
|
||||
struct wl_list request_list;
|
||||
struct wl_list event_list;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct message {
|
||||
char *name;
|
||||
char *uppercase_name;
|
||||
struct wl_list arg_list;
|
||||
struct wl_list link;
|
||||
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 parse_context {
|
||||
struct protocol *protocol;
|
||||
struct interface *interface;
|
||||
struct message *message;
|
||||
};
|
||||
|
||||
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
|
||||
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;
|
||||
const char *name, *type, *interface_name;
|
||||
int i, version;
|
||||
|
||||
name = NULL;
|
||||
type = NULL;
|
||||
version = 0;
|
||||
interface_name = 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], "interface") == 0)
|
||||
interface_name = atts[i + 1];
|
||||
}
|
||||
|
||||
if (strcmp(element_name, "interface") == 0) {
|
||||
if (name == NULL) {
|
||||
fprintf(stderr, "no interface name given\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (version == 0) {
|
||||
fprintf(stderr, "no interface version given\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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_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) {
|
||||
fprintf(stderr, "no request name given\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
message = malloc(sizeof *message);
|
||||
message->name = strdup(name);
|
||||
message->uppercase_name = uppercase_dup(name);
|
||||
wl_list_init(&message->arg_list);
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "no interface name given\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
arg->type = NEW_ID;
|
||||
arg->interface_name = strdup(interface_name);
|
||||
} else if (strcmp(type, "object") == 0) {
|
||||
if (interface_name == NULL) {
|
||||
fprintf(stderr, "no interface name given\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
arg->type = OBJECT;
|
||||
arg->interface_name = strdup(interface_name);
|
||||
} else {
|
||||
fprintf(stderr, "unknown type: %s\n", type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
wl_list_insert(ctx->message->arg_list.prev,
|
||||
&arg->link);
|
||||
}
|
||||
}
|
||||
|
||||
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 WL_%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("int ");
|
||||
break;
|
||||
case NEW_ID:
|
||||
case UNSIGNED:
|
||||
printf("uint32_t ");
|
||||
break;
|
||||
case STRING:
|
||||
printf("const char *");
|
||||
break;
|
||||
case OBJECT:
|
||||
printf("struct wl_%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, "display") != 0)
|
||||
printf("static inline struct wl_%s *\n"
|
||||
"wl_%s_create(struct wl_display *display, uint32_t id)\n"
|
||||
"{\n"
|
||||
"\treturn (struct wl_%s *)\n"
|
||||
"\t\twl_proxy_create_for_id(display, &wl_%s_interface, id);\n"
|
||||
"}\n\n",
|
||||
interface->name,
|
||||
interface->name,
|
||||
interface->name,
|
||||
interface->name);
|
||||
|
||||
printf("static inline void\n"
|
||||
"wl_%s_set_user_data(struct wl_%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"
|
||||
"wl_%s_get_user_data(struct wl_%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, "display") != 0)
|
||||
printf("static inline void\n"
|
||||
"wl_%s_destroy(struct wl_%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 wl_%s *\n",
|
||||
ret->interface_name);
|
||||
else
|
||||
printf("static inline void\n");
|
||||
|
||||
printf("wl_%s_%s(struct wl_%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 &wl_%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 WL_%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 wl_%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_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 wl_%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 wl_%s *%s",
|
||||
indent(n),
|
||||
interface->name, interface->name);
|
||||
} else {
|
||||
printf("void *data,\n"),
|
||||
printf("%sstruct wl_%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"
|
||||
"wl_%s_add_listener(struct wl_%s *%s,\n"
|
||||
"%sconst struct wl_%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 const char client_prototypes[] =
|
||||
"struct wl_proxy;\n\n"
|
||||
|
||||
"extern void\n"
|
||||
"wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);\n"
|
||||
|
||||
"extern struct wl_proxy *\n"
|
||||
"wl_proxy_create(struct wl_proxy *factory,\n"
|
||||
"\t\tconst struct wl_interface *interface);\n"
|
||||
|
||||
"extern struct wl_proxy *\n"
|
||||
"wl_proxy_create_for_id(struct wl_display *display,\n"
|
||||
"\t\t const struct wl_interface *interface, uint32_t id);\n"
|
||||
|
||||
"extern void\n"
|
||||
"wl_proxy_destroy(struct wl_proxy *proxy);\n\n"
|
||||
|
||||
"extern int\n"
|
||||
"wl_proxy_add_listener(struct wl_proxy *proxy,\n"
|
||||
"\t\t void (**implementation)(void), void *data);\n\n"
|
||||
|
||||
"extern void\n"
|
||||
"wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);\n\n"
|
||||
|
||||
"extern void *\n"
|
||||
"wl_proxy_get_user_data(struct wl_proxy *proxy);\n\n";
|
||||
|
||||
|
||||
static void
|
||||
emit_header(struct protocol *protocol, int server)
|
||||
{
|
||||
struct interface *i;
|
||||
|
||||
printf("%s\n\n"
|
||||
"#ifndef WAYLAND_PROTOCOL_H\n"
|
||||
"#define WAYLAND_PROTOCOL_H\n"
|
||||
"\n"
|
||||
"#ifdef __cplusplus\n"
|
||||
"extern \"C\" {\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
"#include <stdint.h>\n"
|
||||
"#include \"wayland-util.h\"\n\n"
|
||||
"struct wl_client;\n\n", copyright);
|
||||
|
||||
wl_list_for_each(i, &protocol->interface_list, link)
|
||||
printf("struct wl_%s;\n", i->name);
|
||||
printf("\n");
|
||||
|
||||
if (!server)
|
||||
printf(client_prototypes);
|
||||
|
||||
wl_list_for_each(i, &protocol->interface_list, link) {
|
||||
printf("extern const struct wl_interface "
|
||||
"wl_%s_interface;\n",
|
||||
i->name);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
wl_list_for_each(i, &protocol->interface_list, link) {
|
||||
|
||||
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_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("\" },\n");
|
||||
}
|
||||
|
||||
printf("};\n\n");
|
||||
}
|
||||
|
||||
static void
|
||||
emit_code(struct protocol *protocol)
|
||||
{
|
||||
struct interface *i;
|
||||
|
||||
printf("%s\n\n"
|
||||
"#include <stdlib.h>\n"
|
||||
"#include <stdint.h>\n"
|
||||
"#include \"wayland-util.h\"\n\n",
|
||||
copyright);
|
||||
|
||||
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 "
|
||||
"wl_%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;
|
||||
XML_Parser parser;
|
||||
int len;
|
||||
void *buf;
|
||||
|
||||
if (argc != 2)
|
||||
usage(EXIT_FAILURE);
|
||||
|
||||
wl_list_init(&protocol.interface_list);
|
||||
ctx.protocol = &protocol;
|
||||
|
||||
parser = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(parser, &ctx);
|
||||
if (parser == NULL) {
|
||||
fprintf(stderr, "failed to create parser\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
XML_SetElementHandler(parser, start_element, NULL);
|
||||
do {
|
||||
buf = XML_GetBuffer(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(parser, len, len == 0);
|
||||
|
||||
} while (len > 0);
|
||||
|
||||
XML_ParserFree(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;
|
||||
}
|
||||
533
wayland/wayland-client.c
Normal file
533
wayland/wayland-client.c
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include "wayland-client-protocol.h"
|
||||
#include "connection.h"
|
||||
#include "wayland-util.h"
|
||||
#include "wayland-client.h"
|
||||
|
||||
static const char socket_name[] = "\0wayland";
|
||||
|
||||
struct wl_global_listener {
|
||||
wl_display_global_func_t handler;
|
||||
void *data;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wl_listener {
|
||||
void (**implementation)(void);
|
||||
void *data;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wl_proxy {
|
||||
struct wl_object base;
|
||||
struct wl_display *display;
|
||||
struct wl_list listener_list;
|
||||
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_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_listener listener;
|
||||
struct wl_list global_listener_list;
|
||||
|
||||
struct wl_visual *argb_visual;
|
||||
struct wl_visual *premultiplied_argb_visual;
|
||||
struct wl_visual *rgb_visual;
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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->base.interface = interface;
|
||||
proxy->base.id = id;
|
||||
proxy->display = display;
|
||||
wl_list_init(&proxy->listener_list);
|
||||
wl_hash_table_insert(display->objects, proxy->base.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)
|
||||
{
|
||||
struct wl_listener *listener, *next;
|
||||
|
||||
wl_list_for_each_safe(listener, next, &proxy->listener_list, link)
|
||||
free(listener);
|
||||
|
||||
wl_hash_table_remove(proxy->display->objects, proxy->base.id);
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_proxy_add_listener(struct wl_proxy *proxy,
|
||||
void (**implementation)(void), void *data)
|
||||
{
|
||||
struct wl_listener *listener;
|
||||
|
||||
listener = malloc(sizeof *listener);
|
||||
if (listener == NULL)
|
||||
return -1;
|
||||
|
||||
listener->implementation = (void (**)(void)) implementation;
|
||||
listener->data = data;
|
||||
wl_list_insert(proxy->listener_list.prev, &listener->link);
|
||||
|
||||
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->base, opcode, ap,
|
||||
&proxy->base.interface->methods[opcode]);
|
||||
va_end(ap);
|
||||
|
||||
wl_closure_send(closure, proxy->display->connection);
|
||||
wl_closure_destroy(closure);
|
||||
}
|
||||
|
||||
static void
|
||||
add_visual(struct wl_display *display, uint32_t id)
|
||||
{
|
||||
struct wl_visual *visual;
|
||||
|
||||
visual = (struct wl_visual *)
|
||||
wl_proxy_create_for_id(display, &wl_visual_interface, id);
|
||||
if (display->argb_visual == NULL)
|
||||
display->argb_visual = visual;
|
||||
else if (display->premultiplied_argb_visual == NULL)
|
||||
display->premultiplied_argb_visual = visual;
|
||||
else
|
||||
display->rgb_visual = visual;
|
||||
}
|
||||
|
||||
WL_EXPORT struct wl_visual *
|
||||
wl_display_get_argb_visual(struct wl_display *display)
|
||||
{
|
||||
return display->argb_visual;
|
||||
}
|
||||
|
||||
WL_EXPORT struct wl_visual *
|
||||
wl_display_get_premultiplied_argb_visual(struct wl_display *display)
|
||||
{
|
||||
return display->premultiplied_argb_visual;
|
||||
}
|
||||
|
||||
WL_EXPORT struct wl_visual *
|
||||
wl_display_get_rgb_visual(struct wl_display *display)
|
||||
{
|
||||
return display->rgb_visual;
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_invalid_object(void *data,
|
||||
struct wl_display *display, uint32_t id)
|
||||
{
|
||||
fprintf(stderr, "sent request to invalid object\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_invalid_method(void *data,
|
||||
struct wl_display *display,
|
||||
uint32_t id, uint32_t opcode)
|
||||
{
|
||||
fprintf(stderr, "sent invalid request opcode\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_no_memory(void *data,
|
||||
struct wl_display *display)
|
||||
{
|
||||
fprintf(stderr, "server out of memory\n");
|
||||
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;
|
||||
|
||||
if (strcmp(interface, "display") == 0)
|
||||
wl_hash_table_insert(display->objects,
|
||||
id, &display->proxy.base);
|
||||
else if (strcmp(interface, "visual") == 0)
|
||||
add_visual(display, id);
|
||||
|
||||
wl_list_for_each(listener, &display->global_listener_list, link)
|
||||
(*listener->handler)(display,
|
||||
id, interface, version, listener->data);
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_range(void *data,
|
||||
struct wl_display *display, uint32_t range)
|
||||
{
|
||||
display->next_range = range;
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_sync(void *data, struct wl_display *display, uint32_t key)
|
||||
{
|
||||
struct wl_sync_handler *handler;
|
||||
|
||||
handler = container_of(display->sync_list.next,
|
||||
struct wl_sync_handler, link);
|
||||
if (handler->key != key) {
|
||||
fprintf(stderr, "unsolicited sync event, client gone?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_remove(&handler->link);
|
||||
handler->func(handler->data);
|
||||
free(handler);
|
||||
}
|
||||
|
||||
static void
|
||||
display_handle_frame(void *data,
|
||||
struct wl_display *display, uint32_t key, uint32_t time)
|
||||
{
|
||||
struct wl_frame_handler *handler;
|
||||
|
||||
handler = container_of(display->frame_list. next,
|
||||
struct wl_frame_handler, link);
|
||||
if (handler->key != key) {
|
||||
fprintf(stderr, "unsolicited frame event, client gone?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_remove(&handler->link);
|
||||
handler->func(handler->data, time);
|
||||
free(handler);
|
||||
}
|
||||
|
||||
static const struct wl_display_listener display_listener = {
|
||||
display_handle_invalid_object,
|
||||
display_handle_invalid_method,
|
||||
display_handle_no_memory,
|
||||
display_handle_global,
|
||||
display_handle_range,
|
||||
display_handle_sync,
|
||||
display_handle_frame
|
||||
};
|
||||
|
||||
WL_EXPORT struct wl_display *
|
||||
wl_display_create(const char *name, size_t name_size)
|
||||
{
|
||||
struct wl_display *display;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t size;
|
||||
|
||||
display = malloc(sizeof *display);
|
||||
if (display == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(display, 0, sizeof *display);
|
||||
display->fd = socket(PF_LOCAL, SOCK_STREAM, 0);
|
||||
if (display->fd < 0) {
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr.sun_family = AF_LOCAL;
|
||||
memcpy(addr.sun_path, name, name_size);
|
||||
|
||||
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
||||
|
||||
if (connect(display->fd, (struct sockaddr *) &addr, size) < 0) {
|
||||
close(display->fd);
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
display->objects = wl_hash_table_create();
|
||||
wl_list_init(&display->global_listener_list);
|
||||
|
||||
display->proxy.base.interface = &wl_display_interface;
|
||||
display->proxy.base.id = 1;
|
||||
display->proxy.display = display;
|
||||
wl_list_init(&display->proxy.listener_list);
|
||||
|
||||
wl_list_init(&display->sync_list);
|
||||
wl_list_init(&display->frame_list);
|
||||
|
||||
display->listener.implementation = (void(**)(void)) &display_listener;
|
||||
wl_list_insert(display->proxy.listener_list.prev, &display->listener.link);
|
||||
|
||||
display->connection = wl_connection_create(display->fd,
|
||||
connection_update,
|
||||
display);
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
wl_display_destroy(struct wl_display *display)
|
||||
{
|
||||
wl_connection_destroy(display->connection);
|
||||
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,
|
||||
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;
|
||||
|
||||
wl_list_insert(display->frame_list.prev, &handler->link);
|
||||
wl_display_frame(display, 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_listener *listener;
|
||||
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) {
|
||||
wl_connection_consume(display->connection, size);
|
||||
return;
|
||||
}
|
||||
|
||||
message = &proxy->base.interface->events[opcode];
|
||||
closure = wl_connection_demarshal(display->connection,
|
||||
size, display->objects, message);
|
||||
|
||||
wl_list_for_each(listener, &proxy->listener_list, link)
|
||||
wl_closure_invoke(closure, &proxy->base,
|
||||
listener->implementation[opcode],
|
||||
listener->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;
|
||||
|
||||
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 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;
|
||||
}
|
||||
75
wayland/wayland-client.h
Normal file
75
wayland/wayland-client.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "wayland-client-protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#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)(void *data, uint32_t time);
|
||||
|
||||
struct wl_display *wl_display_create(const char *name, size_t name_size);
|
||||
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);
|
||||
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,
|
||||
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);
|
||||
struct wl_visual *
|
||||
wl_display_get_argb_visual(struct wl_display *display);
|
||||
struct wl_visual *
|
||||
wl_display_get_premultiplied_argb_visual(struct wl_display *display);
|
||||
struct wl_visual *
|
||||
wl_display_get_rgb_visual(struct wl_display *display);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
10
wayland/wayland-client.pc.in
Normal file
10
wayland/wayland-client.pc.in
Normal file
|
|
@ -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
|
||||
296
wayland/wayland-hash.c
Normal file
296
wayland/wayland-hash.c
Normal file
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
485
wayland/wayland-server.c
Normal file
485
wayland/wayland-server.c
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
/*
|
||||
* 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 <stdarg.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 <ffi.h>
|
||||
|
||||
#include "wayland-server.h"
|
||||
#include "wayland-server-protocol.h"
|
||||
#include "connection.h"
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct wl_display {
|
||||
struct wl_object base;
|
||||
struct wl_event_loop *loop;
|
||||
struct wl_hash_table *objects;
|
||||
|
||||
struct wl_list frame_list;
|
||||
uint32_t client_id_range;
|
||||
uint32_t id;
|
||||
|
||||
struct wl_list global_list;
|
||||
};
|
||||
|
||||
struct wl_frame_listener {
|
||||
struct wl_resource resource;
|
||||
struct wl_client *client;
|
||||
uint32_t key;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wl_global {
|
||||
struct wl_object *object;
|
||||
wl_client_connect_func_t func;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
WL_EXPORT struct wl_surface wl_grab_surface;
|
||||
|
||||
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;
|
||||
|
||||
if (client == NULL)
|
||||
/* wl_grab_surface case */
|
||||
return;
|
||||
|
||||
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) {
|
||||
fprintf(stderr, " -> ");
|
||||
wl_closure_print(closure, sender);
|
||||
}
|
||||
|
||||
wl_closure_destroy(closure);
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
}
|
||||
|
||||
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_event(client, &client->display->base,
|
||||
WL_DISPLAY_INVALID_OBJECT, p[0]);
|
||||
wl_connection_consume(connection, size);
|
||||
len -= size;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (opcode >= object->interface->method_count) {
|
||||
wl_client_post_event(client, &client->display->base,
|
||||
WL_DISPLAY_INVALID_METHOD, p[0], 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_event(client, &client->display->base,
|
||||
WL_DISPLAY_INVALID_METHOD,
|
||||
p[0], opcode);
|
||||
continue;
|
||||
} else if (closure == NULL && errno == ENOMEM) {
|
||||
wl_client_post_no_memory(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (wl_debug)
|
||||
wl_closure_print(closure, object);
|
||||
|
||||
wl_closure_invoke(closure, object,
|
||||
object->implementation[opcode], client);
|
||||
|
||||
wl_closure_destroy(closure);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
wl_client_connection_update(struct wl_connection *connection,
|
||||
uint32_t mask, void *data)
|
||||
{
|
||||
struct wl_client *client = data;
|
||||
uint32_t emask = 0;
|
||||
|
||||
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, mask);
|
||||
}
|
||||
|
||||
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->base,
|
||||
WL_DISPLAY_RANGE, display->client_id_range);
|
||||
display->client_id_range += 256;
|
||||
client->id_count += 256;
|
||||
}
|
||||
|
||||
static 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);
|
||||
|
||||
wl_list_init(&client->resource_list);
|
||||
|
||||
wl_display_post_range(display, client);
|
||||
|
||||
wl_list_for_each(global, &display->global_list, link)
|
||||
wl_client_post_event(client, &client->display->base,
|
||||
WL_DISPLAY_GLOBAL,
|
||||
global->object,
|
||||
global->object->interface->name,
|
||||
global->object->interface->version);
|
||||
|
||||
wl_list_for_each(global, &display->global_list, link)
|
||||
if (global->func)
|
||||
global->func(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_hash_table_insert(client->display->objects,
|
||||
resource->base.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_event(client,
|
||||
&client->display->base,
|
||||
WL_DISPLAY_NO_MEMORY);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
wl_client_post_global(struct wl_client *client, struct wl_object *object)
|
||||
{
|
||||
wl_client_post_event(client,
|
||||
&client->display->base,
|
||||
WL_DISPLAY_GLOBAL,
|
||||
object,
|
||||
object->interface->name,
|
||||
object->interface->version);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
wl_resource_destroy(struct wl_resource *resource, struct wl_client *client)
|
||||
{
|
||||
struct wl_display *display = client->display;
|
||||
|
||||
wl_list_remove(&resource->link);
|
||||
if (resource->base.id > 0)
|
||||
wl_hash_table_remove(display->objects, resource->base.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);
|
||||
|
||||
wl_event_source_remove(client->source);
|
||||
wl_connection_destroy(client->connection);
|
||||
free(client);
|
||||
}
|
||||
|
||||
static void
|
||||
display_sync(struct wl_client *client,
|
||||
struct wl_display *display, uint32_t key)
|
||||
{
|
||||
wl_client_post_event(client, &display->base, WL_DISPLAY_SYNC, key);
|
||||
}
|
||||
|
||||
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, 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.base.id = 0;
|
||||
listener->client = client;
|
||||
listener->key = key;
|
||||
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_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) {
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_list_init(&display->frame_list);
|
||||
wl_list_init(&display->global_list);
|
||||
|
||||
display->client_id_range = 256; /* Gah, arbitrary... */
|
||||
|
||||
display->id = 1;
|
||||
display->base.interface = &wl_display_interface;
|
||||
display->base.implementation = (void (**)(void)) &display_interface;
|
||||
wl_display_add_object(display, &display->base);
|
||||
if (wl_display_add_global(display, &display->base, NULL)) {
|
||||
wl_event_loop_destroy(display->loop);
|
||||
free(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return 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_client_connect_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 void
|
||||
wl_display_post_frame(struct wl_display *display, uint32_t time)
|
||||
{
|
||||
struct wl_frame_listener *listener, *next;
|
||||
|
||||
wl_list_for_each_safe(listener, next, &display->frame_list, link) {
|
||||
wl_client_post_event(listener->client, &display->base,
|
||||
WL_DISPLAY_FRAME, listener->key, time);
|
||||
wl_resource_destroy(&listener->resource, listener->client);
|
||||
}
|
||||
}
|
||||
|
||||
WL_EXPORT struct wl_event_loop *
|
||||
wl_display_get_event_loop(struct wl_display *display)
|
||||
{
|
||||
return display->loop;
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
wl_display_run(struct wl_display *display)
|
||||
{
|
||||
while (1)
|
||||
wl_event_loop_wait(display->loop);
|
||||
}
|
||||
|
||||
static void
|
||||
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 = accept (fd, (struct sockaddr *) &name, &length);
|
||||
if (client_fd < 0)
|
||||
fprintf(stderr, "failed to accept\n");
|
||||
|
||||
wl_client_create(display, client_fd);
|
||||
}
|
||||
|
||||
WL_EXPORT int
|
||||
wl_display_add_socket(struct wl_display *display,
|
||||
const char *name, size_t name_size)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int sock;
|
||||
socklen_t size;
|
||||
|
||||
sock = socket(PF_LOCAL, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
return -1;
|
||||
|
||||
addr.sun_family = AF_LOCAL;
|
||||
memcpy(addr.sun_path, name, name_size);
|
||||
|
||||
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
||||
if (bind(sock, (struct sockaddr *) &addr, size) < 0)
|
||||
return -1;
|
||||
|
||||
if (listen(sock, 1) < 0)
|
||||
return -1;
|
||||
|
||||
wl_event_loop_add_fd(display->loop, sock,
|
||||
WL_EVENT_READABLE,
|
||||
socket_data, display);
|
||||
|
||||
return 0;
|
||||
}
|
||||
173
wayland/wayland-server.h
Normal file
173
wayland/wayland-server.h
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
/* FIXME: We really want in-process objects here, so that the
|
||||
* compositor grabs can be implemented as passive grabs and the events
|
||||
* be delivered to an in-process listener. For now, we use this
|
||||
* special case as the grabbing surface. */
|
||||
extern struct wl_surface wl_grab_surface;
|
||||
|
||||
struct wl_event_loop;
|
||||
struct wl_event_source;
|
||||
typedef void (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data);
|
||||
typedef void (*wl_event_loop_timer_func_t)(void *data);
|
||||
typedef void (*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);
|
||||
|
||||
|
||||
int wl_event_loop_wait(struct wl_event_loop *loop);
|
||||
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_client;
|
||||
struct wl_display;
|
||||
struct wl_input_device;
|
||||
|
||||
struct wl_display *wl_display_create(void);
|
||||
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, size_t name_size);
|
||||
void wl_display_run(struct wl_display *display);
|
||||
|
||||
void wl_display_add_object(struct wl_display *display, struct wl_object *object);
|
||||
|
||||
typedef void (*wl_client_connect_func_t)(struct wl_client *client, struct wl_object *global);
|
||||
|
||||
int wl_display_add_global(struct wl_display *display, struct wl_object *object, wl_client_connect_func_t func);
|
||||
|
||||
void wl_client_destroy(struct wl_client *client);
|
||||
void wl_client_post_no_memory(struct wl_client *client);
|
||||
void wl_client_post_global(struct wl_client *client, struct wl_object *object);
|
||||
|
||||
struct wl_compositor {
|
||||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_resource {
|
||||
struct wl_object base;
|
||||
void (*destroy)(struct wl_resource *resource,
|
||||
struct wl_client *client);
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wl_buffer {
|
||||
struct wl_resource base;
|
||||
};
|
||||
|
||||
struct wl_surface {
|
||||
struct wl_resource base;
|
||||
struct wl_client *client;
|
||||
};
|
||||
|
||||
struct wl_shell {
|
||||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_input_device {
|
||||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_visual {
|
||||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_drag_offer {
|
||||
struct wl_object base;
|
||||
};
|
||||
|
||||
struct wl_drag {
|
||||
struct wl_resource resource;
|
||||
struct wl_drag_offer drag_offer;
|
||||
struct wl_surface *source;
|
||||
struct wl_surface *pointer_focus;
|
||||
struct wl_client *target;
|
||||
int32_t x, y, sx, sy;
|
||||
struct wl_input_device *input_device;
|
||||
struct wl_array types;
|
||||
const char *type;
|
||||
uint32_t pointer_focus_time;
|
||||
};
|
||||
|
||||
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, 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
10
wayland/wayland-server.pc.in
Normal file
10
wayland/wayland-server.pc.in
Normal file
|
|
@ -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
|
||||
115
wayland/wayland-util.c
Normal file
115
wayland/wayland-util.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
127
wayland/wayland-util.h
Normal file
127
wayland/wayland-util.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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_argument {
|
||||
uint32_t type;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct wl_message {
|
||||
const char *name;
|
||||
const char *signature;
|
||||
const void **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);
|
||||
|
||||
|
||||
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 = __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 = __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 = __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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue