8 #include <sys/socket.h>
13 #include "connection.h"
15 #define container_of(ptr, type, member) ({ \
16 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
17 (type *)( (char *)__mptr - offsetof(type,member) );})
25 void wl_list_init(struct wl_list *list)
32 wl_list_insert(struct wl_list *list, struct wl_list *elm)
35 elm->next = list->next;
37 elm->next->prev = elm;
41 wl_list_remove(struct wl_list *elm)
43 elm->prev->next = elm->next;
44 elm->next->prev = elm->prev;
48 struct wl_connection *connection;
49 struct wl_event_source *source;
50 struct wl_display *display;
51 struct wl_list object_list;
56 struct wl_object base;
57 struct wl_event_loop *loop;
58 struct wl_hash objects;
60 struct wl_object *pointer;
62 struct wl_compositor *compositor;
63 struct wl_compositor_interface *compositor_interface;
65 struct wl_list surface_list;
66 struct wl_list client_list;
67 uint32_t client_id_range;
74 struct wl_object base;
76 /* provided by client */
84 /* how to convert buffer contents to pixels in screen format;
85 * yuv->rgb, indexed->rgb, svg->rgb, but mostly just rgb->rgb. */
87 /* how to transform/render rectangular contents to polygons. */
89 void *compositor_data;
92 struct wl_object_ref {
93 struct wl_object *object;
98 wl_surface_destroy(struct wl_client *client,
99 struct wl_surface *surface)
101 struct wl_compositor_interface *interface;
103 interface = client->display->compositor->interface;
104 interface->notify_surface_destroy(client->display->compositor,
106 wl_list_remove(&surface->link);
110 wl_surface_attach(struct wl_client *client,
111 struct wl_surface *surface, uint32_t name,
112 uint32_t width, uint32_t height, uint32_t stride)
114 struct wl_compositor_interface *interface;
116 interface = client->display->compositor->interface;
117 interface->notify_surface_attach(client->display->compositor,
118 surface, name, width, height, stride);
121 static const struct wl_argument attach_arguments[] = {
122 { WL_ARGUMENT_UINT32 },
123 { WL_ARGUMENT_UINT32 },
124 { WL_ARGUMENT_UINT32 },
125 { WL_ARGUMENT_UINT32 },
129 wl_surface_map(struct wl_client *client, struct wl_surface *surface,
130 int32_t x, int32_t y, int32_t width, int32_t height)
132 struct wl_compositor_interface *interface;
134 /* FIXME: This needs to take a tri-mesh argument... - count
135 * and a list of tris. 0 tris means unmap. */
139 surface->map.width = width;
140 surface->map.height = height;
142 interface = client->display->compositor->interface;
143 interface->notify_surface_map(client->display->compositor,
144 surface, &surface->map);
147 static const struct wl_argument map_arguments[] = {
148 { WL_ARGUMENT_UINT32 },
149 { WL_ARGUMENT_UINT32 },
150 { WL_ARGUMENT_UINT32 },
151 { WL_ARGUMENT_UINT32 },
154 static const struct wl_method surface_methods[] = {
155 { "destroy", wl_surface_destroy,
157 { "attach", wl_surface_attach,
158 ARRAY_LENGTH(attach_arguments), attach_arguments },
159 { "map", wl_surface_map,
160 ARRAY_LENGTH(map_arguments), map_arguments }
163 static const struct wl_interface surface_interface = {
165 ARRAY_LENGTH(surface_methods),
170 wl_surface_create(struct wl_display *display, uint32_t id)
172 struct wl_surface *surface;
173 struct wl_compositor_interface *interface;
175 surface = malloc(sizeof *surface);
179 surface->base.id = id;
180 surface->base.interface = &surface_interface;
182 wl_list_insert(display->surface_list.prev, &surface->link);
184 interface = display->compositor->interface;
185 interface->notify_surface_create(display->compositor, surface);
191 wl_surface_set_data(struct wl_surface *surface, void *data)
193 surface->compositor_data = data;
197 wl_surface_get_data(struct wl_surface *surface)
199 return surface->compositor_data;
203 wl_client_destroy(struct wl_client *client);
206 wl_client_demarshal(struct wl_client *client, struct wl_object *target,
207 const struct wl_method *method, size_t size)
220 struct wl_object *object;
223 if (method->argument_count > ARRAY_LENGTH(types)) {
224 printf("too many args (%d)\n", method->argument_count);
228 if (sizeof data < size) {
229 printf("request too big, should malloc tmp buffer here\n");
233 types[0] = &ffi_type_pointer;
234 values[0].object = client;
235 args[0] = &values[0];
237 types[1] = &ffi_type_pointer;
238 values[1].object = target;
239 args[1] = &values[1];
241 wl_connection_copy(client->connection, data, size);
243 for (i = 0; i < method->argument_count; i++) {
244 switch (method->arguments[i].type) {
245 case WL_ARGUMENT_UINT32:
246 types[i + 2] = &ffi_type_uint32;
247 values[i + 2].uint32 = *p;
250 case WL_ARGUMENT_STRING:
251 types[i + 2] = &ffi_type_pointer;
253 values[i + 2].uint32 = *p++;
255 case WL_ARGUMENT_OBJECT:
256 types[i + 2] = &ffi_type_pointer;
257 object = wl_hash_lookup(&client->display->objects, *p);
259 printf("unknown object (%d)\n", *p);
260 if (object->interface != method->arguments[i].data)
261 printf("wrong object type\n");
262 values[i + 2].object = object;
265 case WL_ARGUMENT_NEW_ID:
266 types[i + 2] = &ffi_type_uint32;
267 values[i + 2].new_id = *p;
268 object = wl_hash_lookup(&client->display->objects, *p);
270 printf("object already exists (%d)\n", *p);
274 printf("unknown type\n");
277 args[i + 2] = &values[i + 2];
280 ffi_prep_cif(&cif, FFI_DEFAULT_ABI, method->argument_count + 2,
281 &ffi_type_uint32, types);
282 ffi_call(&cif, FFI_FN(method->func), &result, args);
286 wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t event)
291 p[1] = event | (8 << 16);
292 wl_connection_write(client->connection, p, sizeof p);
295 #define WL_DISPLAY_INVALID_OBJECT 0
296 #define WL_DISPLAY_INVALID_METHOD 1
297 #define WL_DISPLAY_NO_MEMORY 2
300 wl_client_connection_data(int fd, uint32_t mask, void *data)
302 struct wl_client *client = data;
303 struct wl_connection *connection = client->connection;
304 const struct wl_method *method;
305 struct wl_object *object;
306 uint32_t p[2], opcode, size;
310 if (mask & WL_EVENT_READABLE)
311 cmask |= WL_CONNECTION_READABLE;
312 if (mask & WL_EVENT_WRITEABLE)
313 cmask |= WL_CONNECTION_WRITABLE;
315 len = wl_connection_data(connection, cmask);
317 wl_client_destroy(client);
321 while (len > sizeof p) {
322 wl_connection_copy(connection, p, sizeof p);
323 opcode = p[1] & 0xffff;
328 object = wl_hash_lookup(&client->display->objects,
330 if (object == NULL) {
331 wl_client_event(client, &client->display->base,
332 WL_DISPLAY_INVALID_OBJECT);
333 wl_connection_consume(connection, size);
338 if (opcode >= object->interface->method_count) {
339 wl_client_event(client, &client->display->base,
340 WL_DISPLAY_INVALID_METHOD);
341 wl_connection_consume(connection, size);
346 method = &object->interface->methods[opcode];
347 wl_client_demarshal(client, object, method, size);
348 wl_connection_consume(connection, size);
354 wl_client_connection_update(struct wl_connection *connection,
355 uint32_t mask, void *data)
357 struct wl_client *client = data;
360 if (mask & WL_CONNECTION_READABLE)
361 emask |= WL_EVENT_READABLE;
362 if (mask & WL_CONNECTION_WRITABLE)
363 emask |= WL_EVENT_WRITEABLE;
365 return wl_event_loop_update_source(client->display->loop,
366 client->source, mask);
370 advertise_object(struct wl_client *client, struct wl_object *object)
372 const struct wl_interface *interface;
373 static const char pad[4];
374 uint32_t length, p[2];
376 interface = object->interface;
377 length = strlen(interface->name);
380 wl_connection_write(client->connection, p, sizeof p);
381 wl_connection_write(client->connection, interface->name, length);
382 wl_connection_write(client->connection, pad, -length & 3);
386 wl_client_create(struct wl_display *display, int fd)
388 struct wl_client *client;
390 client = malloc(sizeof *client);
394 memset(client, 0, sizeof *client);
395 client->display = display;
396 client->source = wl_event_loop_add_fd(display->loop, fd,
398 wl_client_connection_data, client);
399 client->connection = wl_connection_create(fd,
400 wl_client_connection_update,
402 wl_list_init(&client->object_list);
404 wl_connection_write(client->connection,
405 &display->client_id_range,
406 sizeof display->client_id_range);
407 display->client_id_range += 256;
409 advertise_object(client, &display->base);
411 wl_list_insert(display->client_list.prev, &client->link);
417 wl_client_destroy(struct wl_client *client)
419 struct wl_object_ref *ref;
421 printf("disconnect from client %p\n", client);
423 wl_list_remove(&client->link);
425 while (client->object_list.next != &client->object_list) {
426 ref = container_of(client->object_list.next,
427 struct wl_object_ref, link);
428 wl_list_remove(&ref->link);
429 wl_surface_destroy(client, (struct wl_surface *) ref->object);
433 wl_event_loop_remove_source(client->display->loop, client->source);
434 wl_connection_destroy(client->connection);
439 wl_display_create_surface(struct wl_client *client,
440 struct wl_display *display, uint32_t id)
442 struct wl_surface *surface;
443 struct wl_object_ref *ref;
445 surface = wl_surface_create(display, id);
447 ref = malloc(sizeof *ref);
449 wl_client_event(client, &display->base,
450 WL_DISPLAY_NO_MEMORY);
454 ref->object = &surface->base;
455 wl_hash_insert(&display->objects, &surface->base);
456 wl_list_insert(client->object_list.prev, &ref->link);
461 static const struct wl_argument create_surface_arguments[] = {
462 { WL_ARGUMENT_NEW_ID }
465 static const struct wl_method display_methods[] = {
466 { "create_surface", wl_display_create_surface,
467 ARRAY_LENGTH(create_surface_arguments), create_surface_arguments },
470 static const struct wl_event display_events[] = {
471 { "invalid_object" },
472 { "invalid_method" },
475 static const struct wl_interface display_interface = {
477 ARRAY_LENGTH(display_methods), display_methods,
478 ARRAY_LENGTH(display_events), display_events,
481 static const char input_device_file[] =
482 "/dev/input/by-id/usb-Apple__Inc._Apple_Internal_Keyboard_._Trackpad-event-mouse";
485 wl_display_create_input_devices(struct wl_display *display)
487 display->pointer = wl_input_device_create(display, input_device_file, 1);
489 if (display->pointer != NULL)
490 wl_hash_insert(&display->objects, display->pointer);
492 display->pointer_x = 100;
493 display->pointer_y = 100;
497 wl_display_create(void)
499 struct wl_display *display;
501 display = malloc(sizeof *display);
505 display->loop = wl_event_loop_create();
506 if (display->loop == NULL) {
511 display->base.id = 0;
512 display->base.interface = &display_interface;
513 wl_hash_insert(&display->objects, &display->base);
514 wl_list_init(&display->surface_list);
515 wl_list_init(&display->client_list);
517 wl_display_create_input_devices(display);
519 display->client_id_range = 256; /* Gah, arbitrary... */
525 wl_display_send_event(struct wl_display *display, uint32_t *data, size_t size)
527 struct wl_client *client;
529 client = container_of(display->client_list.next,
530 struct wl_client, link);
531 while (&client->link != &display->client_list) {
532 wl_connection_write(client->connection, data, size);
534 client = container_of(client->link.next,
535 struct wl_client, link);
539 #define WL_POINTER_MOTION 0
540 #define WL_POINTER_BUTTON 1
543 wl_display_post_relative_event(struct wl_display *display,
544 struct wl_object *source, int dx, int dy)
548 display->pointer_x += dx;
549 display->pointer_y += dy;
552 p[1] = (sizeof p << 16) | WL_POINTER_MOTION;
553 p[2] = display->pointer_x;
554 p[3] = display->pointer_y;
556 wl_display_send_event(display, p, sizeof p);
560 wl_display_post_absolute_event(struct wl_display *display,
561 struct wl_object *source, int x, int y)
565 display->pointer_x = x;
566 display->pointer_y = y;
569 p[1] = (sizeof p << 16) | WL_POINTER_MOTION;
570 p[2] = display->pointer_x;
571 p[3] = display->pointer_y;
573 wl_display_send_event(display, p, sizeof p);
577 wl_display_post_button_event(struct wl_display *display,
578 struct wl_object *source, int button, int state)
583 p[1] = (sizeof p << 16) | WL_POINTER_BUTTON;
587 wl_display_send_event(display, p, sizeof p);
591 wl_display_set_compositor(struct wl_display *display,
592 struct wl_compositor *compositor)
594 display->compositor = compositor;
597 struct wl_event_loop *
598 wl_display_get_event_loop(struct wl_display *display)
600 return display->loop;
604 wl_display_run(struct wl_display *display)
607 wl_event_loop_wait(display->loop);
610 /* The plan here is to generate a random anonymous socket name and
611 * advertise that through a service on the session dbus.
613 static const char socket_name[] = "\0wayland";
616 socket_data(int fd, uint32_t mask, void *data)
618 struct wl_display *display = data;
619 struct sockaddr_un name;
623 length = sizeof name;
624 client_fd = accept (fd, (struct sockaddr *) &name, &length);
626 fprintf(stderr, "failed to accept\n");
628 wl_client_create(display, client_fd);
632 wl_display_add_socket(struct wl_display *display)
634 struct sockaddr_un name;
638 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
642 name.sun_family = AF_LOCAL;
643 memcpy(name.sun_path, socket_name, sizeof socket_name);
645 size = offsetof (struct sockaddr_un, sun_path) + sizeof socket_name;
646 if (bind(sock, (struct sockaddr *) &name, size) < 0)
649 if (listen(sock, 1) < 0)
652 wl_event_loop_add_fd(display->loop, sock,
654 socket_data, display);
660 struct wl_surface_iterator {
661 struct wl_list *head;
662 struct wl_surface *surface;
666 struct wl_surface_iterator *
667 wl_surface_iterator_create(struct wl_display *display, uint32_t mask)
669 struct wl_surface_iterator *iterator;
671 iterator = malloc(sizeof *iterator);
672 if (iterator == NULL)
675 iterator->head = &display->surface_list;
676 iterator->surface = container_of(display->surface_list.next,
677 struct wl_surface, link);
678 iterator->mask = mask;
684 wl_surface_iterator_next(struct wl_surface_iterator *iterator,
685 struct wl_surface **surface)
687 if (&iterator->surface->link == iterator->head)
690 *surface = iterator->surface;
691 iterator->surface = container_of(iterator->surface->link.next,
692 struct wl_surface, link);
698 wl_surface_iterator_destroy(struct wl_surface_iterator *iterator)
703 int main(int argc, char *argv[])
705 struct wl_display *display;
706 struct wl_compositor *compositor;
708 display = wl_display_create();
710 if (wl_display_add_socket(display)) {
711 fprintf(stderr, "failed to add socket: %m\n");
715 compositor = wl_compositor_create(display);
716 wl_display_set_compositor(display, compositor);
718 printf("wayland online, display is %p\n", display);
720 wl_display_run(display);