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
30 #include <sys/socket.h>
37 #include "connection.h"
38 #include "wayland-util.h"
39 #include "wayland-client.h"
41 struct wl_global_listener {
42 wl_display_global_func_t handler;
48 struct wl_object object;
49 struct wl_display *display;
53 struct wl_sync_handler {
54 wl_display_sync_func_t func;
60 struct wl_frame_handler {
61 wl_display_frame_func_t func;
64 struct wl_surface *surface;
76 struct wl_proxy proxy;
77 struct wl_connection *connection;
79 uint32_t id, id_count, next_range;
81 struct wl_hash_table *objects;
82 struct wl_list global_listener_list;
83 struct wl_list global_list;
85 struct wl_visual *argb_visual;
86 struct wl_visual *premultiplied_argb_visual;
87 struct wl_visual *rgb_visual;
89 wl_display_update_func_t update;
92 wl_display_global_func_t global_handler;
93 void *global_handler_data;
95 struct wl_list sync_list, frame_list;
99 static int wl_debug = 0;
102 connection_update(struct wl_connection *connection,
103 uint32_t mask, void *data)
105 struct wl_display *display = data;
107 display->mask = mask;
109 return display->update(display->mask,
110 display->update_data);
115 WL_EXPORT struct wl_global_listener *
116 wl_display_add_global_listener(struct wl_display *display,
117 wl_display_global_func_t handler, void *data)
119 struct wl_global_listener *listener;
121 listener = malloc(sizeof *listener);
122 if (listener == NULL)
125 listener->handler = handler;
126 listener->data = data;
127 wl_list_insert(display->global_listener_list.prev, &listener->link);
133 wl_display_remove_global_listener(struct wl_display *display,
134 struct wl_global_listener *listener)
136 wl_list_remove(&listener->link);
140 WL_EXPORT struct wl_proxy *
141 wl_proxy_create_for_id(struct wl_display *display,
142 const struct wl_interface *interface, uint32_t id)
144 struct wl_proxy *proxy;
146 proxy = malloc(sizeof *proxy);
150 proxy->object.interface = interface;
151 proxy->object.implementation = NULL;
152 proxy->object.id = id;
153 proxy->display = display;
154 wl_hash_table_insert(display->objects, proxy->object.id, proxy);
159 WL_EXPORT struct wl_proxy *
160 wl_proxy_create(struct wl_proxy *factory,
161 const struct wl_interface *interface)
163 return wl_proxy_create_for_id(factory->display, interface,
164 wl_display_allocate_id(factory->display));
168 wl_proxy_destroy(struct wl_proxy *proxy)
170 wl_hash_table_remove(proxy->display->objects, proxy->object.id);
175 wl_proxy_add_listener(struct wl_proxy *proxy,
176 void (**implementation)(void), void *data)
178 if (proxy->object.implementation) {
179 fprintf(stderr, "proxy already has listener\n");
183 proxy->object.implementation = implementation;
184 proxy->user_data = data;
190 wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
192 struct wl_closure *closure;
195 va_start(ap, opcode);
196 closure = wl_connection_vmarshal(proxy->display->connection,
197 &proxy->object, opcode, ap,
198 &proxy->object.interface->methods[opcode]);
201 wl_closure_send(closure, proxy->display->connection);
204 fprintf(stderr, " -> ");
205 wl_closure_print(closure, &proxy->object);
208 wl_closure_destroy(closure);
212 add_visual(struct wl_display *display, uint32_t id)
214 struct wl_visual *visual;
216 visual = (struct wl_visual *)
217 wl_proxy_create_for_id(display, &wl_visual_interface, id);
218 if (display->argb_visual == NULL)
219 display->argb_visual = visual;
220 else if (display->premultiplied_argb_visual == NULL)
221 display->premultiplied_argb_visual = visual;
223 display->rgb_visual = visual;
226 WL_EXPORT struct wl_visual *
227 wl_display_get_argb_visual(struct wl_display *display)
229 return display->argb_visual;
232 WL_EXPORT struct wl_visual *
233 wl_display_get_premultiplied_argb_visual(struct wl_display *display)
235 return display->premultiplied_argb_visual;
238 WL_EXPORT struct wl_visual *
239 wl_display_get_rgb_visual(struct wl_display *display)
241 return display->rgb_visual;
244 /* Can't do this, there may be more than one instance of an
247 wl_display_get_global(struct wl_display *display,
248 const char *interface, uint32_t version)
250 struct wl_global *global;
252 wl_list_for_each(global, &display->global_list, link)
253 if (strcmp(interface, global->interface) == 0 &&
254 version <= global->version)
261 display_handle_invalid_object(void *data,
262 struct wl_display *display, uint32_t id)
264 fprintf(stderr, "sent request to invalid object\n");
269 display_handle_invalid_method(void *data,
270 struct wl_display *display,
271 uint32_t id, uint32_t opcode)
273 fprintf(stderr, "sent invalid request opcode\n");
278 display_handle_no_memory(void *data,
279 struct wl_display *display)
281 fprintf(stderr, "server out of memory\n");
286 display_handle_global(void *data,
287 struct wl_display *display,
288 uint32_t id, const char *interface, uint32_t version)
290 struct wl_global_listener *listener;
291 struct wl_global *global;
293 if (strcmp(interface, "display") == 0)
294 wl_hash_table_insert(display->objects,
295 id, &display->proxy.object);
296 else if (strcmp(interface, "visual") == 0)
297 add_visual(display, id);
299 global = malloc(sizeof *global);
301 global->interface = strdup(interface);
302 global->version = version;
303 wl_list_insert(display->global_list.prev, &global->link);
305 wl_list_for_each(listener, &display->global_listener_list, link)
306 (*listener->handler)(display,
307 id, interface, version, listener->data);
311 display_handle_range(void *data,
312 struct wl_display *display, uint32_t range)
314 display->next_range = range;
318 display_handle_key(void *data,
319 struct wl_display *display, uint32_t key, uint32_t time)
321 struct wl_sync_handler *sync_handler;
322 struct wl_frame_handler *frame_handler;
324 sync_handler = container_of(display->sync_list.next,
325 struct wl_sync_handler, link);
326 if (!wl_list_empty(&display->sync_list) && sync_handler->key == key) {
327 wl_list_remove(&sync_handler->link);
328 sync_handler->func(sync_handler->data);
333 frame_handler = container_of(display->frame_list. next,
334 struct wl_frame_handler, link);
335 if (!wl_list_empty(&display->frame_list) &&
336 frame_handler->key == key) {
337 wl_list_remove(&frame_handler->link);
338 frame_handler->func(frame_handler->surface,
339 frame_handler->data, time);
344 fprintf(stderr, "unsolicited sync event, client gone?\n");
347 static const struct wl_display_listener display_listener = {
348 display_handle_invalid_object,
349 display_handle_invalid_method,
350 display_handle_no_memory,
351 display_handle_global,
352 display_handle_range,
357 connect_to_socket(struct wl_display *display, const char *name)
359 struct sockaddr_un addr;
361 const char *runtime_dir;
364 display->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
368 runtime_dir = getenv("XDG_RUNTIME_DIR");
369 if (runtime_dir == NULL) {
372 "XDG_RUNTIME_DIR not set, falling back to %s\n",
377 name = getenv("WAYLAND_DISPLAY");
381 memset(&addr, 0, sizeof addr);
382 addr.sun_family = AF_LOCAL;
384 snprintf(addr.sun_path, sizeof addr.sun_path,
385 "%s/%s", runtime_dir, name) + 1;
387 size = offsetof (struct sockaddr_un, sun_path) + name_size;
389 if (connect(display->fd, (struct sockaddr *) &addr, size) < 0) {
397 WL_EXPORT struct wl_display *
398 wl_display_connect(const char *name)
400 struct wl_display *display;
402 char *connection, *end;
405 debug = getenv("WAYLAND_DEBUG");
409 display = malloc(sizeof *display);
413 memset(display, 0, sizeof *display);
414 connection = getenv("WAYLAND_SOCKET");
416 display->fd = strtol(connection, &end, 0);
421 flags = fcntl(display->fd, F_GETFD);
423 fcntl(display->fd, F_SETFD, flags | FD_CLOEXEC);
424 } else if (connect_to_socket(display, name) < 0) {
429 display->objects = wl_hash_table_create();
430 if (display->objects == NULL) {
435 wl_list_init(&display->global_listener_list);
436 wl_list_init(&display->global_list);
438 display->proxy.object.interface = &wl_display_interface;
439 display->proxy.object.id = 1;
440 display->proxy.display = display;
442 wl_list_init(&display->sync_list);
443 wl_list_init(&display->frame_list);
445 display->proxy.object.implementation =
446 (void(**)(void)) &display_listener;
447 display->proxy.user_data = display;
449 display->connection = wl_connection_create(display->fd,
452 if (display->connection == NULL) {
453 wl_hash_table_destroy(display->objects);
459 wl_display_bind(display, 1, "display", 1);
465 wl_display_destroy(struct wl_display *display)
467 wl_connection_destroy(display->connection);
468 wl_hash_table_destroy(display->objects);
474 wl_display_get_fd(struct wl_display *display,
475 wl_display_update_func_t update, void *data)
477 display->update = update;
478 display->update_data = data;
480 display->update(display->mask, display->update_data);
486 wl_display_sync_callback(struct wl_display *display,
487 wl_display_sync_func_t func, void *data)
489 struct wl_sync_handler *handler;
491 handler = malloc(sizeof *handler);
495 handler->func = func;
496 handler->key = display->key++;
497 handler->data = data;
499 wl_list_insert(display->sync_list.prev, &handler->link);
500 wl_display_sync(display, handler->key);
506 wl_display_frame_callback(struct wl_display *display,
507 struct wl_surface *surface,
508 wl_display_frame_func_t func, void *data)
510 struct wl_frame_handler *handler;
512 handler = malloc(sizeof *handler);
516 handler->func = func;
517 handler->key = display->key++;
518 handler->data = data;
519 handler->surface = surface;
521 wl_list_insert(display->frame_list.prev, &handler->link);
522 wl_display_frame(display, handler->surface, handler->key);
528 handle_event(struct wl_display *display,
529 uint32_t id, uint32_t opcode, uint32_t size)
532 struct wl_proxy *proxy;
533 struct wl_closure *closure;
534 const struct wl_message *message;
536 wl_connection_copy(display->connection, p, size);
538 proxy = &display->proxy;
540 proxy = wl_hash_table_lookup(display->objects, id);
542 if (proxy == NULL || proxy->object.implementation == NULL) {
543 wl_connection_consume(display->connection, size);
547 message = &proxy->object.interface->events[opcode];
548 closure = wl_connection_demarshal(display->connection,
549 size, display->objects, message);
552 wl_closure_print(closure, &proxy->object);
554 wl_closure_invoke(closure, &proxy->object,
555 proxy->object.implementation[opcode],
558 wl_closure_destroy(closure);
562 wl_display_iterate(struct wl_display *display, uint32_t mask)
564 uint32_t p[2], object, opcode, size;
567 mask &= display->mask;
570 "wl_display_iterate called with unsolicited flags");
574 len = wl_connection_data(display->connection, mask);
579 wl_connection_copy(display->connection, p, sizeof p);
581 opcode = p[1] & 0xffff;
586 handle_event(display, object, opcode, size);
591 fprintf(stderr, "read error: %m\n");
597 wl_display_allocate_id(struct wl_display *display)
599 if (display->id_count == 0) {
600 display->id_count = 256;
601 display->id = display->next_range;
606 return display->id++;
610 wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
612 proxy->user_data = user_data;
616 wl_proxy_get_user_data(struct wl_proxy *proxy)
618 return proxy->user_data;