2 * Copyright © 2008 Kristian Høgsberg
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
31 #include <sys/socket.h>
38 #include "connection.h"
39 #include "wayland-util.h"
40 #include "wayland-client.h"
42 struct wl_global_listener {
43 wl_display_global_func_t handler;
49 struct wl_object object;
50 struct wl_display *display;
54 struct wl_sync_handler {
55 wl_display_sync_func_t func;
61 struct wl_frame_handler {
62 wl_display_frame_func_t func;
65 struct wl_surface *surface;
77 struct wl_proxy proxy;
78 struct wl_connection *connection;
80 uint32_t id, id_count, next_range;
82 struct wl_hash_table *objects;
83 struct wl_list global_listener_list;
84 struct wl_list global_list;
86 wl_display_update_func_t update;
89 wl_display_global_func_t global_handler;
90 void *global_handler_data;
92 struct wl_list sync_list, frame_list;
96 static int wl_debug = 0;
99 connection_update(struct wl_connection *connection,
100 uint32_t mask, void *data)
102 struct wl_display *display = data;
104 display->mask = mask;
106 return display->update(display->mask,
107 display->update_data);
112 WL_EXPORT struct wl_global_listener *
113 wl_display_add_global_listener(struct wl_display *display,
114 wl_display_global_func_t handler, void *data)
116 struct wl_global_listener *listener;
117 struct wl_global *global;
119 listener = malloc(sizeof *listener);
120 if (listener == NULL)
123 listener->handler = handler;
124 listener->data = data;
125 wl_list_insert(display->global_listener_list.prev, &listener->link);
127 wl_list_for_each(global, &display->global_list, link)
128 (*listener->handler)(display, global->id, global->interface,
129 global->version, listener->data);
135 wl_display_remove_global_listener(struct wl_display *display,
136 struct wl_global_listener *listener)
138 wl_list_remove(&listener->link);
142 WL_EXPORT struct wl_proxy *
143 wl_proxy_create_for_id(struct wl_display *display,
144 const struct wl_interface *interface, uint32_t id)
146 struct wl_proxy *proxy;
148 proxy = malloc(sizeof *proxy);
152 proxy->object.interface = interface;
153 proxy->object.implementation = NULL;
154 proxy->object.id = id;
155 proxy->display = display;
156 wl_hash_table_insert(display->objects, proxy->object.id, proxy);
161 WL_EXPORT struct wl_proxy *
162 wl_proxy_create(struct wl_proxy *factory,
163 const struct wl_interface *interface)
165 return wl_proxy_create_for_id(factory->display, interface,
166 wl_display_allocate_id(factory->display));
170 wl_proxy_destroy(struct wl_proxy *proxy)
172 wl_hash_table_remove(proxy->display->objects, proxy->object.id);
177 wl_proxy_add_listener(struct wl_proxy *proxy,
178 void (**implementation)(void), void *data)
180 if (proxy->object.implementation) {
181 fprintf(stderr, "proxy already has listener\n");
185 proxy->object.implementation = implementation;
186 proxy->user_data = data;
192 wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
194 struct wl_closure *closure;
197 va_start(ap, opcode);
198 closure = wl_connection_vmarshal(proxy->display->connection,
199 &proxy->object, opcode, ap,
200 &proxy->object.interface->methods[opcode]);
203 wl_closure_send(closure, proxy->display->connection);
206 wl_closure_print(closure, &proxy->object, true);
208 wl_closure_destroy(closure);
211 /* Can't do this, there may be more than one instance of an
214 wl_display_get_global(struct wl_display *display,
215 const char *interface, uint32_t version)
217 struct wl_global *global;
219 wl_list_for_each(global, &display->global_list, link)
220 if (strcmp(interface, global->interface) == 0 &&
221 version <= global->version)
228 display_handle_error(void *data,
229 struct wl_display *display, struct wl_object *object,
230 uint32_t code, const char *message)
232 fprintf(stderr, "%s@%d: error %d: %s\n",
233 object->interface->name, object->id, code, message);
238 display_handle_global(void *data,
239 struct wl_display *display,
240 uint32_t id, const char *interface, uint32_t version)
242 struct wl_global_listener *listener;
243 struct wl_global *global;
245 if (strcmp(interface, "wl_display") == 0)
246 wl_hash_table_insert(display->objects,
247 id, &display->proxy.object);
249 global = malloc(sizeof *global);
251 global->interface = strdup(interface);
252 global->version = version;
253 wl_list_insert(display->global_list.prev, &global->link);
255 wl_list_for_each(listener, &display->global_listener_list, link)
256 (*listener->handler)(display,
257 id, interface, version, listener->data);
261 display_handle_global_remove(void *data,
262 struct wl_display *display, uint32_t id)
264 struct wl_global *global;
266 wl_list_for_each(global, &display->global_list, link)
267 if (global->id == id) {
268 wl_list_remove(&global->link);
275 display_handle_range(void *data,
276 struct wl_display *display, uint32_t range)
278 display->next_range = range;
282 display_handle_key(void *data,
283 struct wl_display *display, uint32_t key, uint32_t time)
285 struct wl_sync_handler *sync_handler;
286 struct wl_frame_handler *frame_handler;
288 sync_handler = container_of(display->sync_list.next,
289 struct wl_sync_handler, link);
290 if (!wl_list_empty(&display->sync_list) && sync_handler->key == key) {
291 wl_list_remove(&sync_handler->link);
292 sync_handler->func(sync_handler->data);
297 frame_handler = container_of(display->frame_list. next,
298 struct wl_frame_handler, link);
299 if (!wl_list_empty(&display->frame_list) &&
300 frame_handler->key == key) {
301 wl_list_remove(&frame_handler->link);
302 frame_handler->func(frame_handler->surface,
303 frame_handler->data, time);
308 fprintf(stderr, "unsolicited sync event, client gone?\n");
311 static const struct wl_display_listener display_listener = {
312 display_handle_error,
313 display_handle_global,
314 display_handle_global_remove,
315 display_handle_range,
320 connect_to_socket(struct wl_display *display, const char *name)
322 struct sockaddr_un addr;
324 const char *runtime_dir;
327 display->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
331 runtime_dir = getenv("XDG_RUNTIME_DIR");
332 if (runtime_dir == NULL) {
335 "XDG_RUNTIME_DIR not set, falling back to %s\n",
340 name = getenv("WAYLAND_DISPLAY");
344 memset(&addr, 0, sizeof addr);
345 addr.sun_family = AF_LOCAL;
347 snprintf(addr.sun_path, sizeof addr.sun_path,
348 "%s/%s", runtime_dir, name) + 1;
350 size = offsetof (struct sockaddr_un, sun_path) + name_size;
352 if (connect(display->fd, (struct sockaddr *) &addr, size) < 0) {
360 WL_EXPORT struct wl_display *
361 wl_display_connect(const char *name)
363 struct wl_display *display;
365 char *connection, *end;
368 debug = getenv("WAYLAND_DEBUG");
372 display = malloc(sizeof *display);
376 memset(display, 0, sizeof *display);
377 connection = getenv("WAYLAND_SOCKET");
379 display->fd = strtol(connection, &end, 0);
384 flags = fcntl(display->fd, F_GETFD);
386 fcntl(display->fd, F_SETFD, flags | FD_CLOEXEC);
387 } else if (connect_to_socket(display, name) < 0) {
392 display->objects = wl_hash_table_create();
393 if (display->objects == NULL) {
398 wl_list_init(&display->global_listener_list);
399 wl_list_init(&display->global_list);
401 display->proxy.object.interface = &wl_display_interface;
402 display->proxy.object.id = 1;
403 display->proxy.display = display;
405 wl_list_init(&display->sync_list);
406 wl_list_init(&display->frame_list);
408 display->proxy.object.implementation =
409 (void(**)(void)) &display_listener;
410 display->proxy.user_data = display;
412 display->connection = wl_connection_create(display->fd,
415 if (display->connection == NULL) {
416 wl_hash_table_destroy(display->objects);
422 wl_display_bind(display, 1, "wl_display", 1);
428 wl_display_destroy(struct wl_display *display)
430 struct wl_global *global, *gnext;
431 struct wl_global_listener *listener, *lnext;
433 wl_connection_destroy(display->connection);
434 wl_hash_table_destroy(display->objects);
435 wl_list_for_each_safe(global, gnext,
436 &display->global_list, link)
438 wl_list_for_each_safe(listener, lnext,
439 &display->global_listener_list, link)
447 wl_display_get_fd(struct wl_display *display,
448 wl_display_update_func_t update, void *data)
450 display->update = update;
451 display->update_data = data;
453 display->update(display->mask, display->update_data);
459 wl_display_sync_callback(struct wl_display *display,
460 wl_display_sync_func_t func, void *data)
462 struct wl_sync_handler *handler;
464 handler = malloc(sizeof *handler);
468 handler->func = func;
469 handler->key = display->key++;
470 handler->data = data;
472 wl_list_insert(display->sync_list.prev, &handler->link);
473 wl_display_sync(display, handler->key);
479 wl_display_frame_callback(struct wl_display *display,
480 struct wl_surface *surface,
481 wl_display_frame_func_t func, void *data)
483 struct wl_frame_handler *handler;
485 handler = malloc(sizeof *handler);
489 handler->func = func;
490 handler->key = display->key++;
491 handler->data = data;
492 handler->surface = surface;
494 wl_list_insert(display->frame_list.prev, &handler->link);
495 wl_display_frame(display, handler->surface, handler->key);
501 handle_event(struct wl_display *display,
502 uint32_t id, uint32_t opcode, uint32_t size)
505 struct wl_proxy *proxy;
506 struct wl_closure *closure;
507 const struct wl_message *message;
509 wl_connection_copy(display->connection, p, size);
511 proxy = &display->proxy;
513 proxy = wl_hash_table_lookup(display->objects, id);
515 if (proxy == NULL || proxy->object.implementation == NULL) {
516 wl_connection_consume(display->connection, size);
520 message = &proxy->object.interface->events[opcode];
521 closure = wl_connection_demarshal(display->connection,
522 size, display->objects, message);
524 if (closure == NULL) {
525 fprintf(stderr, "Error demarshalling event: %m\n");
530 wl_closure_print(closure, &proxy->object, false);
532 wl_closure_invoke(closure, &proxy->object,
533 proxy->object.implementation[opcode],
536 wl_closure_destroy(closure);
540 wl_display_iterate(struct wl_display *display, uint32_t mask)
542 uint32_t p[2], object, opcode, size;
545 mask &= display->mask;
548 "wl_display_iterate called with unsolicited flags");
552 len = wl_connection_data(display->connection, mask);
557 wl_connection_copy(display->connection, p, sizeof p);
559 opcode = p[1] & 0xffff;
564 handle_event(display, object, opcode, size);
569 fprintf(stderr, "read error: %m\n");
575 wl_display_flush(struct wl_display *display)
577 while (display->mask & WL_DISPLAY_WRITABLE)
578 wl_display_iterate (display, WL_DISPLAY_WRITABLE);
582 wl_display_allocate_id(struct wl_display *display)
584 if (display->id_count == 0) {
585 display->id_count = 256;
586 display->id = display->next_range;
591 return display->id++;
595 wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
597 proxy->user_data = user_data;
601 wl_proxy_get_user_data(struct wl_proxy *proxy)
603 return proxy->user_data;