From b3131d9268ce68062c7410a9b672539026000f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 24 Dec 2008 19:30:25 -0500 Subject: [PATCH] Add client side demarshalling for events. This also consolidates the marshalling code in connection.c and uses the same functions in the server and client for marshalling. --- Makefile.in | 6 +- connection.c | 144 +++++++++++++++++++ connection.h | 15 +- wayland-client.c | 276 +++++++++++++++++------------------- wayland-protocol.c | 2 +- wayland-system-compositor.c | 2 + wayland.c | 189 ++++-------------------- 7 files changed, 322 insertions(+), 312 deletions(-) diff --git a/Makefile.in b/Makefile.in index 5910911b..09cd2b7c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,16 +16,14 @@ libwayland-server.so : \ wayland-util.o \ wayland-protocol.o -libwayland-server.so : CFLAGS += @FFI_CFLAGS@ -libwayland-server.so : LDLIBS += @FFI_LIBS@ -ldl -rdynamic - libwayland.so : \ wayland-client.o \ connection.o \ wayland-util.o \ wayland-protocol.o -$(libs) : CFLAGS += -fPIC +$(libs) : CFLAGS += -fPIC @FFI_CFLAGS@ +$(libs) : LDLIBS += @FFI_LIBS@ $(libs) : gcc -shared $^ $(LDLIBS) -o $@ diff --git a/connection.c b/connection.c index 54309631..be9c88b5 100644 --- a/connection.c +++ b/connection.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "wayland-util.h" #include "connection.h" @@ -218,3 +220,145 @@ wl_connection_write(struct wl_connection *connection, const void *data, size_t c WL_CONNECTION_WRITABLE, connection->data); } + +void +wl_connection_vmarshal(struct wl_connection *connection, + struct wl_object *sender, + uint32_t opcode, va_list ap, + const struct wl_message *message) +{ + struct wl_object *object; + uint32_t args[32], length, *p, size; + const char *s; + int i, count; + + count = strlen(message->signature); + assert(count <= ARRAY_LENGTH(args)); + + p = &args[2]; + for (i = 0; i < count; i++) { + switch (message->signature[i]) { + case 'u': + case 'i': + *p++ = va_arg(ap, uint32_t); + break; + case 's': + s = va_arg(ap, const char *); + length = strlen(s); + *p++ = length; + memcpy(p, s, length); + p += DIV_ROUNDUP(length, sizeof(*p)); + break; + case 'o': + case 'n': + object = va_arg(ap, struct wl_object *); + *p++ = object->id; + break; + default: + assert(0); + break; + } + } + + size = (p - args) * sizeof *p; + args[0] = sender->id; + args[1] = opcode | (size << 16); + wl_connection_write(connection, args, size); +} + +void +wl_connection_demarshal(struct wl_connection *connection, + uint32_t size, + struct wl_hash *objects, + void (*func)(void), + void *data, struct wl_object *target, + const struct wl_message *message) +{ + ffi_type *types[20]; + ffi_cif cif; + uint32_t *p, result, length; + int i, count; + union { + uint32_t uint32; + char *string; + void *object; + uint32_t new_id; + } values[20]; + void *args[20]; + struct wl_object *object; + uint32_t buffer[64]; + + count = strlen(message->signature) + 2; + if (count > ARRAY_LENGTH(types)) { + printf("too many args (%d)\n", count); + return; + } + + if (sizeof buffer < size) { + printf("request too big, should malloc tmp buffer here\n"); + return; + } + + types[0] = &ffi_type_pointer; + values[0].object = data; + args[0] = &values[0]; + + types[1] = &ffi_type_pointer; + values[1].object = target; + args[1] = &values[1]; + + wl_connection_copy(connection, buffer, size); + p = &buffer[2]; + for (i = 2; i < count; i++) { + switch (message->signature[i - 2]) { + case 'u': + case 'i': + types[i] = &ffi_type_uint32; + values[i].uint32 = *p++; + break; + case 's': + types[i] = &ffi_type_pointer; + length = *p++; + values[i].string = malloc(length + 1); + if (values[i].string == NULL) { + /* FIXME: Send NO_MEMORY */ + return; + } + memcpy(values[i].string, p, length); + values[i].string[length] = '\0'; + p += DIV_ROUNDUP(length, sizeof *p); + break; + case 'o': + types[i] = &ffi_type_pointer; + object = wl_hash_lookup(objects, *p); + if (object == NULL) + printf("unknown object (%d)\n", *p); + values[i].object = object; + p++; + break; + case 'n': + types[i] = &ffi_type_uint32; + values[i].new_id = *p; + object = wl_hash_lookup(objects, *p); + if (object != NULL) + printf("object already exists (%d)\n", *p); + p++; + break; + default: + printf("unknown type\n"); + break; + } + args[i] = &values[i]; + } + + ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types); + ffi_call(&cif, func, &result, args); + + for (i = 2; i < count; i++) { + switch (message->signature[i - 2]) { + case 's': + free(values[i].string); + break; + } + } +} diff --git a/connection.h b/connection.h index 68d63964..3db07ee2 100644 --- a/connection.h +++ b/connection.h @@ -24,6 +24,7 @@ #define _CONNECTION_H_ #include +#include "wayland-util.h" struct wl_connection; @@ -41,7 +42,17 @@ void wl_connection_copy(struct wl_connection *connection, void *data, size_t siz 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); -void wl_connection_vmarshal(struct wl_connection *connection, uint32_t id, - uint32_t opcode, const char *signature, va_list ap); + +void wl_connection_vmarshal(struct wl_connection *connection, + struct wl_object *sender, + uint32_t opcode, va_list ap, + const struct wl_message *message); + +void wl_connection_demarshal(struct wl_connection *connection, + uint32_t size, + struct wl_hash *objects, + void (*func)(void), + void *data, struct wl_object *target, + const struct wl_message *message); #endif diff --git a/wayland-client.c b/wayland-client.c index 2087a929..3d82c501 100644 --- a/wayland-client.c +++ b/wayland-client.c @@ -103,6 +103,41 @@ connection_update(struct wl_connection *connection, return 0; } +static void +output_handle_geometry(struct wl_display *display, + struct wl_output *output, int32_t width, int32_t height) +{ + output->width = width; + output->height = height; +} + +struct wl_output_listener { + void (*geometry)(struct wl_display *display, + struct wl_output *output, + int32_t width, int32_t height); +}; + +static const struct wl_output_listener output_listener = { + output_handle_geometry +}; + +static void +add_output(struct wl_display *display, struct wl_global *global) +{ + struct wl_output *output; + + output = malloc(sizeof *output); + if (output == NULL) + return; + + output->proxy.base.interface = &wl_output_interface; + output->proxy.base.implementation = (void(**)(void)) &output_listener; + output->proxy.base.id = global->id; + output->proxy.display = display; + display->output = output; + wl_hash_insert(display->objects, &output->proxy.base); +} + WL_EXPORT void wl_display_get_geometry(struct wl_display *display, int32_t *width, int32_t *height) { @@ -150,6 +185,79 @@ wl_display_get_rgb_visual(struct wl_display *display) struct wl_visual, link); } +static void +display_handle_invalid_object(struct wl_display *display, + struct wl_object *object, uint32_t id) +{ + fprintf(stderr, "sent request to invalid object\n"); +} + +static void +display_handle_invalid_method(struct wl_display *display, + struct wl_object *object, + uint32_t id, uint32_t opcode) +{ + fprintf(stderr, "sent invalid request opcode\n"); +} + +static void +display_handle_no_memory(struct wl_display *display, + struct wl_object *object) +{ + fprintf(stderr, "server out of memory\n"); +} + +static void +display_handle_global(struct wl_display *display, + struct wl_object *object, + uint32_t id, const char *interface, uint32_t version) +{ + struct wl_global *global; + + global = malloc(sizeof *global); + if (global == NULL) + return; + + global->id = id; + global->interface = strdup(interface); + global->version = version; + wl_list_insert(display->global_list.prev, &global->link); + if (strcmp(global->interface, "display") == 0) + wl_hash_insert(display->objects, &display->proxy.base); + if (strcmp(global->interface, "visual") == 0) + add_visual(display, global); + else if (strcmp(global->interface, "output") == 0) + add_output(display, global); +} + +static void +display_handle_range(struct wl_display *display, + struct wl_object *object, uint32_t range) +{ + display->next_range = range; +} + +struct wl_display_listener { + void (*invalid_object)(struct wl_display *display, + struct wl_object *object, uint32_t id); + void (*invalid_method)(struct wl_display *display, + struct wl_object *object, + uint32_t id, uint32_t opcode); + void (*no_memory)(struct wl_display *display, struct wl_object *object); + void (*global)(struct wl_display *display, struct wl_object *object, + uint32_t id, const char *interface, uint32_t version); + void (*range)(struct wl_display *display, + struct wl_object *object, uint32_t range); +}; + +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 +}; + WL_EXPORT struct wl_display * wl_display_create(const char *name, size_t name_size) { @@ -184,10 +292,9 @@ wl_display_create(const char *name, size_t name_size) wl_list_init(&display->visual_list); display->proxy.base.interface = &wl_display_interface; - display->proxy.base.implementation = NULL; + display->proxy.base.implementation = (void(**)(void)) &display_listener; display->proxy.base.id = 1; display->proxy.display = display; - wl_hash_insert(display->objects, &display->proxy.base); display->connection = wl_connection_create(display->fd, connection_update, @@ -239,100 +346,6 @@ wl_display_get_fd(struct wl_display *display, return display->fd; } -struct wl_output_listener { - void (*geometry)(struct wl_display *display, - struct wl_output *output, - int32_t width, int32_t height); -}; - -static void -handle_geometry(struct wl_display *display, - struct wl_output *output, int32_t width, int32_t height) -{ - output->width = width; - output->height = height; -} - -static const struct wl_output_listener output_listener = { - handle_geometry -}; - -static void -add_output(struct wl_display *display, struct wl_global *global) -{ - struct wl_output *output; - - output = malloc(sizeof *output); - if (output == NULL) - return; - - output->proxy.base.interface = &wl_output_interface; - output->proxy.base.implementation = (void(**)(void)) &output_listener; - output->proxy.base.id = global->id; - output->proxy.display = display; - display->output = output; - wl_hash_insert(display->objects, &output->proxy.base); -} - -static void -handle_display_event(struct wl_display *display, - uint32_t opcode, uint32_t *p, uint32_t size) -{ - struct wl_global *global; - uint32_t length; - - switch (opcode) { - case WL_DISPLAY_INVALID_OBJECT: - fprintf(stderr, "sent request to invalid object\n"); - break; - - case WL_DISPLAY_INVALID_METHOD: - fprintf(stderr, "sent invalid request opcode\n"); - break; - - case WL_DISPLAY_NO_MEMORY: - fprintf(stderr, "server out of memory\n"); - break; - - case WL_DISPLAY_GLOBAL: - global = malloc(sizeof *global); - if (global == NULL) - return; - - global->id = p[0]; - length = p[1]; - global->interface = malloc(length + 1); - if (global->interface == NULL) { - free(global); - return; - } - memcpy(global->interface, &p[2], length); - global->interface[length] = '\0'; - global->version = p[2 + DIV_ROUNDUP(length, sizeof *p)]; - wl_list_insert(display->global_list.prev, &global->link); - if (strcmp(global->interface, "visual") == 0) - add_visual(display, global); - else if (strcmp(global->interface, "output") == 0) - add_output(display, global); - break; - - case WL_DISPLAY_RANGE: - display->next_range = p[0]; - break; - } -} - -static void -handle_output_event(struct wl_display *display, - uint32_t opcode, uint32_t *p, uint32_t size) -{ - switch (opcode) { - case WL_OUTPUT_GEOMETRY: - handle_geometry(display, display->output, p[0], p[1]); - break; - } -} - static void handle_event(struct wl_display *display, uint32_t id, uint32_t opcode, uint32_t size) @@ -341,15 +354,24 @@ handle_event(struct wl_display *display, struct wl_object *object; wl_connection_copy(display->connection, p, size); - object = wl_hash_lookup(display->objects, id); - - if (object == &display->proxy.base) - handle_display_event(display, opcode, p + 2, size); - else if (object == &display->output->proxy.base && opcode == 0) - handle_output_event(display, opcode, p + 2, size); + if (id == 1) + object = &display->proxy.base; + else + object = wl_hash_lookup(display->objects, id); + + if (object != NULL) + wl_connection_demarshal(display->connection, + size, + display->objects, + object->implementation[opcode], + display, + object, + &object->interface->events[opcode]); else if (display->event_handler != NULL) - display->event_handler(display, id, opcode, size, p + 2, + display->event_handler(display, id, + opcode, size, p + 2, display->event_handler_data); + wl_connection_consume(display->connection, size); } @@ -428,57 +450,17 @@ wl_display_get_compositor(struct wl_display *display) return compositor; } -static void -wl_proxy_vmarshal(struct wl_proxy *target, uint32_t opcode, va_list ap) -{ - struct wl_object *object; - uint32_t args[32], length, *p, size; - const char *s, *signature; - int i, count; - - signature = target->base.interface->methods[opcode].signature; - count = strlen(signature); - /* FIXME: Make sure we don't overwrite args array. */ - - p = &args[2]; - for (i = 0; i < count; i++) { - switch (signature[i]) { - case 'u': - case 'i': - *p++ = va_arg(ap, uint32_t); - break; - case 's': - s = va_arg(ap, const char *); - length = strlen(s); - *p++ = length; - memcpy(p, s, length); - p += DIV_ROUNDUP(length, sizeof(*p)); - break; - case 'n': - case 'o': - object = va_arg(ap, struct wl_object *); - *p++ = object->id; - break; - default: - assert(0); - break; - } - } - - size = (p - args) * sizeof *p; - args[0] = target->base.id; - args[1] = opcode | (size << 16); - wl_connection_write(target->display->connection, args, size); -} - static void wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...) { va_list ap; va_start(ap, opcode); - wl_proxy_vmarshal(proxy, opcode, ap); + wl_connection_vmarshal(proxy->display->connection, + &proxy->base, opcode, ap, + &proxy->base.interface->methods[opcode]); va_end(ap); + } WL_EXPORT struct wl_surface * diff --git a/wayland-protocol.c b/wayland-protocol.c index 2c7ba99c..308cc708 100644 --- a/wayland-protocol.c +++ b/wayland-protocol.c @@ -29,7 +29,7 @@ static const struct wl_message display_events[] = { { "invalid_object", "u" }, { "invalid_method", "uu" }, { "no_memory", "" }, - { "global", "osu" }, + { "global", "nsu" }, { "range", "u" }, }; diff --git a/wayland-system-compositor.c b/wayland-system-compositor.c index 77c6bfe5..09daebf1 100644 --- a/wayland-system-compositor.c +++ b/wayland-system-compositor.c @@ -702,7 +702,9 @@ create_input_device(struct egl_compositor *ec, const char *glob) memset(device, 0, sizeof *device); device->base.interface = &wl_input_device_interface; + device->base.implementation = NULL; wl_display_add_object(ec->wl_display, &device->base); + wl_display_add_global(ec->wl_display, &device->base, NULL); device->x = 100; device->y = 100; device->pointer_surface = diff --git a/wayland.c b/wayland.c index 0fe2a8de..98cb341c 100644 --- a/wayland.c +++ b/wayland.c @@ -73,61 +73,6 @@ struct wl_global { void wl_client_destroy(struct wl_client *client); -static void -wl_client_vmarshal(struct wl_client *client, struct wl_object *sender, - uint32_t opcode, va_list ap) -{ - const struct wl_message *event; - struct wl_object *object; - uint32_t args[32], length, *p, size; - const char *s; - int i, count; - - event = &sender->interface->events[opcode]; - count = strlen(event->signature); - assert(count <= ARRAY_LENGTH(args)); - - p = &args[2]; - for (i = 0; i < count; i++) { - switch (event->signature[i]) { - case 'u': - case 'i': - *p++ = va_arg(ap, uint32_t); - break; - case 's': - s = va_arg(ap, const char *); - length = strlen(s); - *p++ = length; - memcpy(p, s, length); - p += DIV_ROUNDUP(length, sizeof(*p)); - break; - case 'o': - object = va_arg(ap, struct wl_object *); - *p++ = object->id; - break; - default: - assert(0); - break; - } - } - - size = (p - args) * sizeof *p; - args[0] = sender->id; - args[1] = opcode | (size << 16); - wl_connection_write(client->connection, args, size); -} - -static void -wl_client_marshal(struct wl_client *client, struct wl_object *sender, - uint32_t opcode, ...) -{ - va_list ap; - - va_start(ap, opcode); - wl_client_vmarshal(client, sender, opcode, ap); - va_end(ap); -} - WL_EXPORT void wl_client_post_event(struct wl_client *client, struct wl_object *sender, uint32_t opcode, ...) @@ -135,93 +80,12 @@ wl_client_post_event(struct wl_client *client, struct wl_object *sender, va_list ap; va_start(ap, opcode); - wl_client_vmarshal(client, sender, opcode, ap); + wl_connection_vmarshal(client->connection, + sender, opcode, ap, + &sender->interface->events[opcode]); va_end(ap); } -static void -wl_client_demarshal(struct wl_client *client, struct wl_object *target, - uint32_t opcode, size_t size) -{ - const struct wl_message *method; - ffi_type *types[20]; - ffi_cif cif; - uint32_t *p, result; - int i, count; - union { - uint32_t uint32; - const char *string; - void *object; - uint32_t new_id; - } values[20]; - void *args[20]; - struct wl_object *object; - uint32_t data[64]; - void (*func)(void); - - method = &target->interface->methods[opcode]; - count = strlen(method->signature) + 2; - if (count > ARRAY_LENGTH(types)) { - printf("too many args (%d)\n", count); - return; - } - - if (sizeof data < size) { - printf("request too big, should malloc tmp buffer here\n"); - return; - } - - types[0] = &ffi_type_pointer; - values[0].object = client; - args[0] = &values[0]; - - types[1] = &ffi_type_pointer; - values[1].object = target; - args[1] = &values[1]; - - wl_connection_copy(client->connection, data, size); - p = &data[2]; - for (i = 2; i < count; i++) { - switch (method->signature[i - 2]) { - case 'u': - case 'i': - types[i] = &ffi_type_uint32; - values[i].uint32 = *p; - p++; - break; - case 's': - types[i] = &ffi_type_pointer; - /* FIXME */ - values[i].uint32 = *p++; - break; - case 'o': - types[i] = &ffi_type_pointer; - object = wl_hash_lookup(client->display->objects, *p); - if (object == NULL) - printf("unknown object (%d)\n", *p); - values[i].object = object; - p++; - break; - case 'n': - types[i] = &ffi_type_uint32; - values[i].new_id = *p; - object = wl_hash_lookup(client->display->objects, *p); - if (object != NULL) - printf("object already exists (%d)\n", *p); - p++; - break; - default: - printf("unknown type\n"); - break; - } - args[i] = &values[i]; - } - - func = target->implementation[opcode]; - ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types); - ffi_call(&cif, func, &result, args); -} - static void wl_client_connection_data(int fd, uint32_t mask, void *data) { @@ -252,22 +116,29 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) object = wl_hash_lookup(client->display->objects, p[0]); if (object == NULL) { - wl_client_marshal(client, &client->display->base, - WL_DISPLAY_INVALID_OBJECT, p[0]); + 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_marshal(client, &client->display->base, - WL_DISPLAY_INVALID_METHOD, p[0], opcode); + wl_client_post_event(client, &client->display->base, + WL_DISPLAY_INVALID_METHOD, p[0], opcode); wl_connection_consume(connection, size); len -= size; continue; } - wl_client_demarshal(client, object, opcode, size); + wl_connection_demarshal(client->connection, + size, + client->display->objects, + object->implementation[opcode], + client, + object, + &object->interface->methods[opcode]); + wl_connection_consume(connection, size); len -= size; } @@ -291,8 +162,8 @@ wl_client_connection_update(struct wl_connection *connection, static void wl_display_post_range(struct wl_display *display, struct wl_client *client) { - wl_client_marshal(client, &client->display->base, - WL_DISPLAY_RANGE, display->client_id_range); + wl_client_post_event(client, &client->display->base, + WL_DISPLAY_RANGE, display->client_id_range); display->client_id_range += 256; client->id_count += 256; } @@ -323,11 +194,11 @@ wl_client_create(struct wl_display *display, int fd) global = container_of(display->global_list.next, struct wl_global, link); while (&global->link != &display->global_list) { - wl_client_marshal(client, &client->display->base, - WL_DISPLAY_GLOBAL, - global->object, - global->object->interface->name, - global->object->interface->version); + wl_client_post_event(client, &client->display->base, + WL_DISPLAY_GLOBAL, + global->object, + global->object->interface->name, + global->object->interface->version); global = container_of(global->link.next, struct wl_global, link); } @@ -395,8 +266,8 @@ wl_client_add_surface(struct wl_client *client, ref = malloc(sizeof *ref); if (ref == NULL) { - wl_client_marshal(client, &display->base, - WL_DISPLAY_NO_MEMORY); + wl_client_post_event(client, &display->base, + WL_DISPLAY_NO_MEMORY); return -1; } @@ -415,8 +286,8 @@ wl_client_send_acknowledge(struct wl_client *client, wl_list_remove(&client->link); wl_list_insert(client->display->pending_frame_list.prev, &client->link); - wl_client_marshal(client, &compositor->base, - WL_COMPOSITOR_ACKNOWLEDGE, key, frame); + wl_client_post_event(client, &compositor->base, + WL_COMPOSITOR_ACKNOWLEDGE, key, frame); } WL_EXPORT int @@ -505,7 +376,9 @@ wl_surface_post_event(struct wl_surface *surface, va_list ap; va_start(ap, event); - wl_client_vmarshal(surface->client, sender, event, ap); + wl_connection_vmarshal(surface->client->connection, + sender, event, ap, + &sender->interface->events[event]); va_end(ap); } @@ -520,8 +393,8 @@ wl_display_post_frame(struct wl_display *display, struct wl_client, link); while (&client->link != &display->pending_frame_list) { - wl_client_marshal(client, &compositor->base, - WL_COMPOSITOR_FRAME, frame, msecs); + wl_client_post_event(client, &compositor->base, + WL_COMPOSITOR_FRAME, frame, msecs); client = container_of(client->link.next, struct wl_client, link); }