diff --git a/wayland-client.c b/wayland-client.c index 21546f48..d6471ac3 100644 --- a/wayland-client.c +++ b/wayland-client.c @@ -41,6 +41,7 @@ static const char socket_name[] = "\0wayland"; struct wl_global { uint32_t id; char *interface; + uint32_t version; struct wl_list link; }; @@ -133,11 +134,8 @@ WL_EXPORT struct wl_display * wl_display_create(const char *name, size_t name_size) { struct wl_display *display; - struct wl_global *global; struct sockaddr_un addr; socklen_t size; - char buffer[256]; - uint32_t id, length, count, i; display = malloc(sizeof *display); if (display == NULL) @@ -165,29 +163,8 @@ wl_display_create(const char *name, size_t name_size) * guess... */ read(display->fd, &display->id, sizeof display->id); - read(display->fd, &count, sizeof count); - wl_list_init(&display->global_list); wl_list_init(&display->visual_list); - for (i = 0; i < count; i++) { - /* FIXME: actually discover advertised objects here. */ - read(display->fd, &id, sizeof id); - read(display->fd, &length, sizeof length); - read(display->fd, buffer, (length + 3) & ~3); - - global = malloc(sizeof *global); - if (global == NULL) - return NULL; - - global->id = id; - global->interface = malloc(length + 1); - memcpy(global->interface, buffer, length); - global->interface[length] = '\0'; - wl_list_insert(display->global_list.prev, &global->link); - - if (strcmp(global->interface, "visual") == 0) - add_visual(display, global); - } display->proxy.display = display; display->proxy.id = wl_display_get_object_id(display, "display"); @@ -196,6 +173,9 @@ wl_display_create(const char *name, size_t name_size) connection_update, display); + /* Process connection events. */ + wl_display_iterate(display, WL_CONNECTION_READABLE); + return display; } @@ -237,14 +217,47 @@ wl_display_get_fd(struct wl_display *display, return display->fd; } +#define WL_DISPLAY_INVALID_OBJECT 0 +#define WL_DISPLAY_INVALID_METHOD 1 +#define WL_DISPLAY_NO_MEMORY 2 +#define WL_DISPLAY_GLOBAL 3 + +static void +handle_global(struct wl_display *display, uint32_t *p, uint32_t size) +{ + struct wl_global *global; + uint32_t length; + + 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); +} + static void handle_event(struct wl_display *display, uint32_t object, uint32_t opcode, uint32_t size) { - uint32_t p[10]; + uint32_t p[32]; wl_connection_copy(display->connection, p, size); - if (display->event_handler != NULL) + if (object == 1 && opcode == WL_DISPLAY_GLOBAL) { + handle_global(display, p + 2, size); + } else if (display->event_handler != NULL) display->event_handler(display, object, opcode, size, p + 2, display->event_handler_data); wl_connection_consume(display->connection, size); diff --git a/wayland-util.h b/wayland-util.h index 5fc64516..25156872 100644 --- a/wayland-util.h +++ b/wayland-util.h @@ -31,6 +31,8 @@ #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); \ diff --git a/wayland.c b/wayland.c index e4022530..fe5f9db7 100644 --- a/wayland.c +++ b/wayland.c @@ -71,30 +71,31 @@ wl_client_vmarshal(struct wl_client *client, struct wl_object *sender, { const struct wl_event *event; struct wl_object *object; - uint32_t args[10], size; + uint32_t args[32], length, *p, size; + const char *s; int i, count; event = &sender->interface->events[opcode]; - count = strlen(event->signature) + 2; + count = strlen(event->signature); assert(count <= ARRAY_LENGTH(args)); - size = 0; - for (i = 2; i < count; i++) { - switch (event->signature[i - 2]) { + p = &args[2]; + for (i = 0; i < count; i++) { + switch (event->signature[i]) { case 'u': case 'i': - args[i] = va_arg(ap, uint32_t); - size += sizeof args[i]; + *p++ = va_arg(ap, uint32_t); break; case 's': - /* FIXME */ - args[i] = 0; - size += sizeof args[i]; + 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 *); - args[i] = object->id; - size += sizeof args[i]; + *p++ = object->id; break; default: assert(0); @@ -102,7 +103,7 @@ wl_client_vmarshal(struct wl_client *client, struct wl_object *sender, } } - size += 2 * sizeof args[0]; + size = (p - args) * sizeof *p; args[0] = sender->id; args[1] = opcode | (size << 16); wl_connection_write(client->connection, args, size); @@ -205,6 +206,7 @@ wl_client_demarshal(struct wl_client *client, struct wl_object *target, #define WL_DISPLAY_INVALID_OBJECT 0 #define WL_DISPLAY_INVALID_METHOD 1 #define WL_DISPLAY_NO_MEMORY 2 +#define WL_DISPLAY_GLOBAL 3 static void wl_client_connection_data(int fd, uint32_t mask, void *data) @@ -272,28 +274,11 @@ wl_client_connection_update(struct wl_connection *connection, return wl_event_source_fd_update(client->source, mask); } -static void -advertise_object(struct wl_client *client, struct wl_object *object) -{ - const struct wl_interface *interface; - static const char pad[4]; - uint32_t length, p[2]; - - interface = object->interface; - length = strlen(interface->name); - p[0] = object->id; - p[1] = length; - wl_connection_write(client->connection, p, sizeof p); - wl_connection_write(client->connection, interface->name, length); - wl_connection_write(client->connection, pad, -length & 3); -} - static struct wl_client * wl_client_create(struct wl_display *display, int fd) { struct wl_client *client; struct wl_object_ref *ref; - uint32_t count; client = malloc(sizeof *client); if (client == NULL) @@ -315,14 +300,14 @@ wl_client_create(struct wl_display *display, int fd) sizeof display->client_id_range); display->client_id_range += 256; - /* Write list of global objects to client. */ - count = wl_list_length(&display->global_list); - wl_connection_write(client->connection, &count, sizeof count); - ref = container_of(display->global_list.next, struct wl_object_ref, link); while (&ref->link != &display->global_list) { - advertise_object(client, ref->object); + wl_client_marshal(client, &client->display->base, + WL_DISPLAY_GLOBAL, + ref->object, + ref->object->interface->name, + ref->object->interface->version); ref = container_of(ref->link.next, struct wl_object_ref, link); @@ -455,6 +440,7 @@ static const struct wl_event display_events[] = { { "invalid_object", "u" }, { "invalid_method", "uu" }, { "no_memory", "" }, + { "global", "osu" }, }; static const struct wl_interface display_interface = {