diff --git a/wayland.c b/wayland.c index 73f2236d..602fe254 100644 --- a/wayland.c +++ b/wayland.c @@ -2,12 +2,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include "wayland.h" @@ -223,6 +225,50 @@ wl_surface_get_data(struct wl_surface *surface) void wl_client_destroy(struct wl_client *client); +static void +wl_client_marshal(struct wl_client *client, struct wl_object *sender, + uint32_t opcode, ...) +{ + const struct wl_event *event; + struct wl_object *object; + uint32_t args[10], size, *p; + va_list ap; + int i; + + event = &sender->interface->events[opcode]; + size = 0; + va_start(ap, opcode); + p = &args[2]; + for (i = 0; i < event->argument_count; i++) { + switch (event->arguments[i].type) { + case WL_ARGUMENT_UINT32: + p[i] = va_arg(ap, uint32_t); + size += sizeof p[i]; + break; + case WL_ARGUMENT_STRING: + /* FIXME */ + p[i] = 0; + size += sizeof p[i]; + break; + case WL_ARGUMENT_OBJECT: + object = va_arg(ap, struct wl_object *); + p[i] = object->id; + size += sizeof p[i]; + break; + case WL_ARGUMENT_NEW_ID: + default: + assert(0); + break; + } + } + va_end(ap); + + size += 2 * sizeof args[0]; + args[0] = sender->id; + args[1] = opcode | (size << 16); + wl_connection_write(client->connection, args, size); +} + static void wl_client_demarshal(struct wl_client *client, struct wl_object *target, const struct wl_method *method, size_t size) @@ -303,16 +349,6 @@ wl_client_demarshal(struct wl_client *client, struct wl_object *target, ffi_call(&cif, FFI_FN(method->func), &result, args); } -static void -wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event) -{ - uint32_t p[2]; - - p[0] = object->id; - p[1] = event | (8 << 16); - wl_connection_write(client->connection, p, sizeof p); -} - #define WL_DISPLAY_INVALID_OBJECT 0 #define WL_DISPLAY_INVALID_METHOD 1 #define WL_DISPLAY_NO_MEMORY 2 @@ -348,19 +384,18 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) if (len < size) break; - object = wl_hash_lookup(&client->display->objects, - p[0]); + object = wl_hash_lookup(&client->display->objects, p[0]); if (object == NULL) { - wl_client_event(client, &client->display->base, - WL_DISPLAY_INVALID_OBJECT); + wl_client_marshal(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_event(client, &client->display->base, - WL_DISPLAY_INVALID_METHOD); + wl_client_marshal(client, &client->display->base, + WL_DISPLAY_INVALID_METHOD, p[0], opcode); wl_connection_consume(connection, size); len -= size; continue; @@ -481,8 +516,8 @@ wl_display_create_surface(struct wl_client *client, ref = malloc(sizeof *ref); if (ref == NULL) { - wl_client_event(client, &display->base, - WL_DISPLAY_NO_MEMORY); + wl_client_marshal(client, &display->base, + WL_DISPLAY_NO_MEMORY); return -1; } @@ -502,19 +537,14 @@ wl_display_commit(struct wl_client *client, struct wl_display *display, uint32_t key) { const struct wl_compositor_interface *interface; - uint32_t frame, event[4]; + uint32_t frame; client->pending_frame = 1; interface = display->compositor->interface; frame = interface->notify_commit(display->compositor); - - event[0] = display->base.id; - event[1] = WL_DISPLAY_ACKNOWLEDGE | ((sizeof event) << 16); - event[2] = key; - event[3] = frame; - - wl_connection_write(client->connection, event, sizeof event); + wl_client_marshal(client, &display->base, + WL_DISPLAY_ACKNOWLEDGE, key, frame); return 0; } @@ -530,11 +560,36 @@ static const struct wl_method display_methods[] = { ARRAY_LENGTH(commit_arguments), commit_arguments }, }; +static const struct wl_argument invalid_object_arguments[] = { + { WL_ARGUMENT_UINT32 } +}; + +static const struct wl_argument invalid_method_arguments[] = { + { WL_ARGUMENT_UINT32 }, + { WL_ARGUMENT_UINT32 } +}; + +static const struct wl_argument acknowledge_arguments[] = { + { WL_ARGUMENT_UINT32 }, + { WL_ARGUMENT_UINT32 } +}; + +static const struct wl_argument frame_arguments[] = { + { WL_ARGUMENT_UINT32 }, + { WL_ARGUMENT_UINT32 } +}; + static const struct wl_event display_events[] = { - { "invalid_object" }, - { "invalid_method" }, - { "no_memory" }, - { "acknowledge" }, + { "invalid_object", + ARRAY_LENGTH(invalid_object_arguments), invalid_object_arguments }, + { "invalid_method", + ARRAY_LENGTH(invalid_method_arguments), invalid_method_arguments }, + { "no_memory", + 0, NULL }, + { "acknowledge", + ARRAY_LENGTH(acknowledge_arguments), acknowledge_arguments }, + { "frame", + ARRAY_LENGTH(frame_arguments), frame_arguments }, }; static const struct wl_interface display_interface = { @@ -701,20 +756,14 @@ wl_display_post_frame(struct wl_display *display, uint32_t frame, uint32_t msecs) { struct wl_client *client; - uint32_t event[4]; - - event[0] = display->base.id; - event[1] = WL_DISPLAY_FRAME | ((sizeof event) << 16); - event[2] = frame; - event[3] = msecs; client = container_of(display->client_list.next, struct wl_client, link); while (&client->link != &display->client_list) { if (client->pending_frame) { - wl_connection_write(client->connection, - event, sizeof event); + wl_client_marshal(client, &display->base, + WL_DISPLAY_FRAME, frame, msecs); client->pending_frame = 0; } client = container_of(client->link.next, diff --git a/wayland.h b/wayland.h index 23a0c56f..c8c67c9d 100644 --- a/wayland.h +++ b/wayland.h @@ -58,6 +58,8 @@ struct wl_method { struct wl_event { const char *name; + int argument_count; + const struct wl_argument *arguments; }; struct wl_interface {