2 * Copyright (c) 2013, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <murphy/common.h>
42 #include "window-manager.h"
45 static uint32_t oid_hash(const void *);
46 static uint32_t wid_hash(const void *);
47 static uint32_t lid_hash(const void *);
48 static int id_compare(const void *, const void *);
50 static const char *get_display_name(mrp_wayland_t *w);
51 static void display_io_watch(mrp_io_watch_t *, int, mrp_io_event_t, void *);
52 static void object_create(mrp_wayland_interface_t *, uint32_t, uint32_t);
53 static void global_available_callback(void *, struct wl_registry *, uint32_t,
54 const char *, uint32_t);
55 static void global_remove_callback(void *, struct wl_registry *, uint32_t);
57 static mrp_wayland_t **instances;
58 static size_t ninstance;
61 mrp_wayland_t *mrp_wayland_create(const char *display_name, mrp_mainloop_t *ml)
64 mrp_htbl_config_t icfg, ocfg, wcfg, lcfg, acfg;
66 MRP_ASSERT(ml, "invalid argument");
68 if (!(wl = mrp_allocz(sizeof(mrp_wayland_t))))
69 mrp_log_error("can't allocate memory for wayland");
71 memset(&icfg, 0, sizeof(icfg));
72 icfg.nentry = MRP_WAYLAND_INTERFACE_MAX;
73 icfg.comp = mrp_string_comp;
74 icfg.hash = mrp_string_hash;
75 icfg.nbucket = MRP_WAYLAND_INTERFACE_BUCKETS;
77 memset(&ocfg, 0, sizeof(ocfg));
78 ocfg.nentry = MRP_WAYLAND_OUTPUT_MAX;
79 ocfg.comp = id_compare;
81 ocfg.nbucket = MRP_WAYLAND_OUTPUT_BUCKETS;
83 memset(&wcfg, 0, sizeof(wcfg));
84 wcfg.nentry = MRP_WAYLAND_WINDOW_MAX;
85 wcfg.comp = id_compare;
87 wcfg.nbucket = MRP_WAYLAND_WINDOW_BUCKETS;
89 memset(&lcfg, 0, sizeof(lcfg));
90 lcfg.nentry = MRP_WAYLAND_LAYER_MAX + MRP_WAYLAND_LAYER_BUILTIN;
91 lcfg.comp = id_compare;
93 lcfg.nbucket = MRP_WAYLAND_LAYER_BUCKETS;
95 memset(&acfg, 0, sizeof(acfg));
96 acfg.nentry = MRP_WAYLAND_AREA_MAX;
97 acfg.comp = mrp_string_comp;
98 acfg.hash = mrp_string_hash;
99 acfg.nbucket = MRP_WAYLAND_AREA_BUCKETS;
101 wl->display_name = display_name ? mrp_strdup(display_name) : NULL;
104 wl->registry_listener.global = global_available_callback;
105 wl->registry_listener.global_remove = global_remove_callback;
107 wl->interfaces = mrp_htbl_create(&icfg);
108 wl->outputs = mrp_htbl_create(&ocfg);
109 wl->windows = mrp_htbl_create(&wcfg);
110 wl->layers = mrp_htbl_create(&lcfg);
111 wl->areas = mrp_htbl_create(&acfg);
113 instances = mrp_reallocz(instances, ninstance, ninstance + 2);
114 instances[ninstance++] = wl;
120 void mrp_wayland_destroy(mrp_wayland_t *wl)
125 for (i = 0; i < ninstance; i++) {
126 if (instances[i] == wl) {
127 if (i < ninstance-1) {
128 memmove(instances + i, instances + i + 1,
129 (ninstance - (i + 1)) * sizeof(*instances));
131 instances[--ninstance] = NULL;
138 mrp_wayland_t *mrp_wayland_iterate(void **cursor)
145 if (i >= 0 && i < (ptrdiff_t)ninstance) {
146 *cursor = NULL + (i + 1);
154 bool mrp_wayland_connect(mrp_wayland_t *wl)
156 #define IO_EVENTS MRP_IO_EVENT_IN | MRP_IO_EVENT_ERR | MRP_IO_EVENT_HUP
158 struct wl_display *display;
159 struct wl_registry *registry;
163 MRP_ASSERT(wl, "invalid argument");
164 MRP_ASSERT(wl->ml, "no mainloop");
167 return true; /* we are already connected */
169 if (!(display = wl_display_connect(wl->display_name))) {
170 mrp_debug("attempt to connect to display '%s' failed",
171 get_display_name(wl));
175 fd = wl_display_get_fd(display);
177 MRP_ASSERT(fd >= 0, "fd for wayland display < 0");
179 if (!(registry = wl_display_get_registry(display))) {
180 mrp_log_error("can't get registry for display '%s'",
181 get_display_name(wl));
182 wl_display_disconnect(display);
186 if (wl_registry_add_listener(registry, &wl->registry_listener, wl) < 0) {
187 mrp_log_error("can't add listener for registry (display '%s')",
188 get_display_name(wl));
189 wl_registry_destroy(registry);
190 wl_display_disconnect(display);
194 if (!(iow = mrp_add_io_watch(wl->ml,fd,IO_EVENTS,display_io_watch,wl))) {
195 mrp_log_error("can't add io watch for display '%s')",
196 get_display_name(wl));
197 wl_registry_destroy(registry);
198 wl_display_disconnect(display);
203 wl->display = display;
204 wl->registry = registry;
206 mrp_log_info("connecting to wayland display '%s'", get_display_name(wl));
208 wl_display_roundtrip(display);
210 mrp_debug("queried interfaces");
212 wl_display_roundtrip(display);
214 mrp_log_info("display '%s' is up and running", get_display_name(wl));
221 void mrp_wayland_flush(mrp_wayland_t *wl)
223 MRP_ASSERT(wl, "invalid argument");
226 mrp_debug("calling wl_display_flush()");
227 wl_display_flush(wl->display);
232 static int update_layers(void *key, void *object, void *ud)
234 mrp_wayland_window_manager_t *wm = (mrp_wayland_window_manager_t *)ud;
235 mrp_wayland_layer_t *layer = (mrp_wayland_layer_t *)object;
239 mrp_debug("register window manager to layer %u/'%s'",
240 layer->layerid, layer->name);
244 return MRP_HTBL_ITER_MORE;
248 void mrp_wayland_register_window_manager(mrp_wayland_t *wl,
249 mrp_wayland_window_manager_t *wm)
253 mrp_htbl_foreach(wl->layers, update_layers, wm);
255 if (wl->window_manager_update_callback) {
256 wl->window_manager_update_callback(wl,
257 MRP_WAYLAND_WINDOW_MANAGER_CREATE,
263 bool mrp_wayland_register_interface(mrp_wayland_t *wl,
264 mrp_wayland_factory_t *factory)
266 mrp_wayland_interface_t *wif;
269 MRP_ASSERT(wl && factory, "invalid argument");
270 MRP_ASSERT(factory->size >= sizeof(mrp_wayland_object_t),
271 "invalid object size in factory");
272 MRP_ASSERT(factory->interface, "missing factory interface");
274 name = factory->interface->name;
276 MRP_ASSERT(name, "broken factory interface");
278 if (!(wif = mrp_allocz(sizeof(mrp_wayland_interface_t)))) {
279 mrp_log_error("can't allocate memory for wayland interface '%s'",
285 wif->name = mrp_strdup(name);
286 wif->object_factory = *factory;
288 mrp_list_init(&wif->object_list);
290 if (!mrp_htbl_insert(wl->interfaces, (void *)wif->name, wif)) {
291 mrp_log_error("failed to add interface '%s' to hashtable. "
292 "Perhaps already registered ...", wif->name);
293 mrp_free((void *)wif->name);
298 mrp_log_info("registered wayland interface '%s'", wif->name);
303 void mrp_wayland_register_window_manager_update_callback(mrp_wayland_t *wl,
304 mrp_wayland_window_manager_update_callback_t callback)
306 MRP_ASSERT(wl, "invalid aruments");
308 mrp_debug("registering window_manager_update_callback");
310 wl->window_manager_update_callback = callback;
313 void mrp_wayland_register_output_update_callback(mrp_wayland_t *wl,
314 mrp_wayland_output_update_callback_t callback)
316 MRP_ASSERT(wl, "invalid aruments");
318 mrp_debug("registering output_update_callback");
320 wl->output_update_callback = callback;
323 void mrp_wayland_register_window_update_callback(mrp_wayland_t *wl,
324 mrp_wayland_window_update_callback_t callback)
326 MRP_ASSERT(wl, "invalid aruments");
328 mrp_debug("registering window_update_callback");
330 wl->window_update_callback = callback;
333 void mrp_wayland_register_layer_update_callback(mrp_wayland_t *wl,
334 mrp_wayland_layer_update_callback_t callback)
336 MRP_ASSERT(wl, "invalid aruments");
338 mrp_debug("registering layer_update_callback");
340 wl->layer_update_callback = callback;
343 void mrp_wayland_register_area_update_callback(mrp_wayland_t *wl,
344 mrp_wayland_area_update_callback_t callback)
346 MRP_ASSERT(wl, "invalid aruments");
348 mrp_debug("registering area_update_callback");
350 wl->area_update_callback = callback;
353 void mrp_wayland_set_scripting_data(mrp_wayland_t *wl, void *data)
355 MRP_ASSERT(wl, "invalid argument");
357 mrp_debug("%sset scripting data", data ? "" : "re");
359 wl->scripting_data = data;
362 void mrp_wayland_create_scripting_windows(mrp_wayland_t *wl, bool create)
364 MRP_ASSERT(wl, "invalid argument");
366 mrp_debug("%screate scripting windows", create ? "" : "do not ");
368 wl->create_scripting_windows = create;
372 void mrp_wayland_create_scripting_outputs(mrp_wayland_t *wl, bool create)
374 MRP_ASSERT(wl, "invalid argument");
376 mrp_debug("%screate scripting outputs", create ? "" : "do not ");
378 wl->create_scripting_outputs = create;
382 void mrp_wayland_create_scripting_areas(mrp_wayland_t *wl, bool create)
384 MRP_ASSERT(wl, "invalid argument");
386 mrp_debug("%screate scripting areas", create ? "" : "do not ");
388 wl->create_scripting_areas = create;
392 void mrp_wayland_create_scripting_layers(mrp_wayland_t *wl, bool create)
394 MRP_ASSERT(wl, "invalid argument");
396 mrp_debug("%screate scripting layers", create ? "" : "do not ");
398 wl->create_scripting_layers = create;
402 static uint32_t oid_hash(const void *pkey)
404 uint32_t key = *(uint32_t *)pkey;
406 return key % MRP_WAYLAND_OUTPUT_BUCKETS;
409 static uint32_t wid_hash(const void *pkey)
411 uint32_t key = *(uint32_t *)pkey;
413 return key % MRP_WAYLAND_WINDOW_BUCKETS;
416 static uint32_t lid_hash(const void *pkey)
418 uint32_t key = *(uint32_t *)pkey;
420 return key % MRP_WAYLAND_LAYER_BUCKETS;
423 static int id_compare(const void *pkey1, const void *pkey2)
425 int32_t key1 = *(int32_t *)pkey1;
426 int32_t key2 = *(int32_t *)pkey2;
428 return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
431 static const char *get_display_name(mrp_wayland_t *wl)
433 const char *display_name;
435 MRP_ASSERT(wl, "invalid argument");
437 if (wl->display_name)
438 return wl->display_name;
440 if ((display_name = getenv("WAYLAND_DISPLAY")) != NULL)
446 static void display_io_watch(mrp_io_watch_t *iow,
448 mrp_io_event_t events,
451 mrp_wayland_t *wl = (mrp_wayland_t *)ud;
458 MRP_ASSERT(wl, "invalid user data");
459 MRP_ASSERT(iow == wl->iow, "mismatching io watch");
464 if ((events & MRP_IO_EVENT_HUP)) {
465 mrp_log_info("display '%s' is gone", get_display_name(wl));
467 wl_registry_destroy(wl->registry);
468 wl_display_disconnect(wl->display);
476 if ((events & MRP_IO_EVENT_ERR)) {
477 mrp_log_error("I/O error on display '%s'", get_display_name(wl));
481 if ((events & MRP_IO_EVENT_IN)) {
482 events &= ~MRP_IO_EVENT_IN;
484 mrp_debug("dispatching inputs from display '%s'",get_display_name(wl));
486 if (wl_display_dispatch(wl->display) < 0) {
487 mrp_log_error("failed to dispatch events of display '%s'",
488 get_display_name(wl));
491 wl_display_flush(wl->display);
497 p += snprintf(p, e-p, "%s%s", p > evlist ? " " : "", w); \
499 # define CHECK_EVENT(e) \
500 if ((events & MRP_IO_EVENT_ ## e)) { \
503 events &= ~MRP_IO_EVENT_ ## e; \
506 e = (p = evlist) + (sizeof(evlist) - 1);
512 snprintf(evnam, sizeof(evnam), "<unknown 0x%x>", events);
516 mrp_debug("unhandled io events: %s", evlist);
523 static void object_create(mrp_wayland_interface_t *wif,
528 mrp_wayland_factory_t *factory;
529 mrp_wayland_object_t *obj;
530 struct wl_proxy *proxy;
532 MRP_ASSERT(wif, "invalid argument");
535 factory = &wif->object_factory;
537 if (!(obj = mrp_allocz(factory->size))) {
538 mrp_log_error("can't allocate %zd byte memory for %u/'%s' object",
539 factory->size, (unsigned int)name, wif->name);
543 proxy = wl_registry_bind(wl->registry, name, factory->interface, 1);
546 mrp_log_error("failed to create proxy for object %u/'%s' on "
547 "display '%s'", name, wif->name, get_display_name(wl));
552 mrp_list_init(&obj->interface_link);
553 obj->interface = wif;
555 obj->version = version;
558 if (factory->constructor) {
559 if (!factory->constructor(wl, obj)) {
560 mrp_log_error("failed to construct object %u/'%s' on "
561 "display '%s'",name,wif->name, get_display_name(wl));
562 wl_proxy_destroy(proxy);
567 /* TODO: register the object by name */
569 mrp_debug("object %u/'%s' on display '%s' created", name, wif->name,
570 get_display_name(wl));
574 static void global_available_callback(void *data,
575 struct wl_registry *registry,
577 const char *interface,
580 mrp_wayland_t *wl = (mrp_wayland_t *)data;
581 mrp_wayland_interface_t *wif;
583 MRP_ASSERT(wl && registry && interface, "invalid argument");
584 MRP_ASSERT(registry == wl->registry, "confused with data structures");
586 wif = mrp_htbl_lookup(wl->interfaces, (void *)interface);
588 mrp_debug("object %u/%s is up%s", name, interface,
589 wif ? "" : " (interface unknown)");
592 MRP_ASSERT(wif->wl == wl, "confused with data structures");
593 object_create(wif, name, version);
597 static void global_remove_callback(void *data,
598 struct wl_registry *wl_registry,
602 MRP_UNUSED(wl_registry);
604 mrp_debug("object %u is down", name);