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>
43 #include "window-manager.h"
44 #include "input-manager.h"
47 static uint32_t oid_hash(const void *);
48 static uint32_t wid_hash(const void *);
49 static uint32_t lid_hash(const void *);
50 static uint32_t ltype_hash(const void *);
51 static uint32_t did_hash(const void *);
52 static int id_compare(const void *, const void *);
53 static int ltype_compare(const void *, const void *);
55 static bool same_display_name(const char *name1, const char *name2);
56 static const char *get_display_name(mrp_wayland_t *w);
57 static void display_io_watch(mrp_io_watch_t *, int, mrp_io_event_t, void *);
58 static void object_create(mrp_wayland_interface_t *, uint32_t, uint32_t);
59 static void global_available_callback(void *, struct wl_registry *, uint32_t,
60 const char *, uint32_t);
61 static void global_remove_callback(void *, struct wl_registry *, uint32_t);
63 static mrp_wayland_t **instances;
64 static size_t ninstance;
67 mrp_wayland_t *mrp_wayland_create(const char *display_name, mrp_mainloop_t *ml)
70 mrp_htbl_config_t icfg, oxcfg,oicfg, wcfg, licfg,ltcfg, acfg, dncfg,dicfg;
73 MRP_ASSERT(ml, "invalid argument");
75 for (i = 0; i < ninstance; i++) {
78 if (same_display_name(display_name, wl->display_name))
82 if (!(wl = mrp_allocz(sizeof(mrp_wayland_t))))
83 mrp_log_error("can't allocate memory for wayland");
85 memset(&icfg, 0, sizeof(icfg));
86 icfg.nentry = MRP_WAYLAND_INTERFACE_MAX;
87 icfg.comp = mrp_string_comp;
88 icfg.hash = mrp_string_hash;
89 icfg.nbucket = MRP_WAYLAND_INTERFACE_BUCKETS;
91 memset(&wcfg, 0, sizeof(wcfg));
92 wcfg.nentry = MRP_WAYLAND_WINDOW_MAX;
93 wcfg.comp = id_compare;
95 wcfg.nbucket = MRP_WAYLAND_WINDOW_BUCKETS;
97 memset(&licfg, 0, sizeof(licfg));
98 licfg.nentry = MRP_WAYLAND_LAYER_MAX + MRP_WAYLAND_LAYER_BUILTIN;
99 licfg.comp = id_compare;
100 licfg.hash = lid_hash;
101 licfg.nbucket = MRP_WAYLAND_LAYER_BUCKETS;
103 memset(<cfg, 0, sizeof(ltcfg));
104 ltcfg.nentry = MRP_WAYLAND_LAYER_MAX + MRP_WAYLAND_LAYER_BUILTIN;
105 ltcfg.comp = ltype_compare;
106 ltcfg.hash = ltype_hash;
107 ltcfg.nbucket = MRP_WAYLAND_LAYER_BUCKETS;
109 memset(&acfg, 0, sizeof(acfg));
110 acfg.nentry = MRP_WAYLAND_AREA_MAX;
111 acfg.comp = mrp_string_comp;
112 acfg.hash = mrp_string_hash;
113 acfg.nbucket = MRP_WAYLAND_AREA_BUCKETS;
115 memset(&oxcfg, 0, sizeof(oxcfg));
116 oxcfg.nentry = MRP_WAYLAND_OUTPUT_MAX;
117 oxcfg.comp = id_compare;
118 oxcfg.hash = oid_hash;
119 oxcfg.nbucket = MRP_WAYLAND_OUTPUT_BUCKETS;
121 memset(&oicfg, 0, sizeof(oicfg));
122 oicfg.nentry = MRP_WAYLAND_OUTPUT_MAX;
123 oicfg.comp = id_compare;
124 oicfg.hash = oid_hash;
125 oicfg.nbucket = MRP_WAYLAND_OUTPUT_BUCKETS;
127 memset(&dncfg, 0, sizeof(dncfg));
128 dncfg.nentry = MRP_WAYLAND_DEVICE_MAX;
129 dncfg.comp = mrp_string_comp;
130 dncfg.hash = mrp_string_hash;
131 dncfg.nbucket = MRP_WAYLAND_DEVICE_BUCKETS;
133 memset(&dicfg, 0, sizeof(dicfg));
134 dicfg.nentry = MRP_WAYLAND_DEVICE_MAX;
135 dicfg.comp = id_compare;
136 dicfg.hash = did_hash;
137 dicfg.nbucket = MRP_WAYLAND_DEVICE_BUCKETS;
139 wl->display_name = display_name ? mrp_strdup(display_name) : NULL;
142 wl->registry_listener.global = global_available_callback;
143 wl->registry_listener.global_remove = global_remove_callback;
145 wl->interfaces = mrp_htbl_create(&icfg);
146 wl->windows = mrp_htbl_create(&wcfg);
147 wl->areas = mrp_htbl_create(&acfg);
149 wl->outputs.by_index = mrp_htbl_create(&oxcfg);
150 wl->outputs.by_id = mrp_htbl_create(&oicfg);
152 wl->devices.by_name = mrp_htbl_create(&dncfg);
153 wl->devices.by_id = mrp_htbl_create(&dicfg);
155 wl->layers.by_id = mrp_htbl_create(&licfg);
156 wl->layers.by_type = mrp_htbl_create(<cfg);
159 instances = mrp_reallocz(instances, ninstance, ninstance + 2);
160 instances[ninstance++] = wl;
166 void mrp_wayland_destroy(mrp_wayland_t *wl)
171 for (i = 0; i < ninstance; i++) {
172 if (instances[i] == wl) {
173 if (i < ninstance-1) {
174 memmove(instances + i, instances + i + 1,
175 (ninstance - (i + 1)) * sizeof(*instances));
177 instances[--ninstance] = NULL;
184 mrp_wayland_t *mrp_wayland_iterate(void **cursor)
191 if (i >= 0 && i < (ptrdiff_t)ninstance) {
192 *cursor = NULL + (i + 1);
200 bool mrp_wayland_disconnect(mrp_wayland_t *wl)
205 /* destroy resource */
207 wl_registry_destroy(wl->registry);
211 /* disconnect from display */
213 wl_display_disconnect(wl->display);
220 mrp_del_io_watch(wl->iow);
227 bool mrp_wayland_connect(mrp_wayland_t *wl)
229 #define IO_EVENTS MRP_IO_EVENT_IN | MRP_IO_EVENT_ERR | MRP_IO_EVENT_HUP
231 struct wl_display *display;
232 struct wl_registry *registry;
236 MRP_ASSERT(wl, "invalid argument");
237 MRP_ASSERT(wl->ml, "no mainloop");
240 return true; /* we are already connected */
242 if (!(display = wl_display_connect(wl->display_name))) {
243 mrp_log_error("attempt to connect to display '%s' failed",
244 get_display_name(wl));
248 fd = wl_display_get_fd(display);
250 MRP_ASSERT(fd >= 0, "fd for wayland display < 0");
252 if (!(registry = wl_display_get_registry(display))) {
253 mrp_log_error("can't get registry for display '%s'",
254 get_display_name(wl));
255 wl_display_disconnect(display);
259 if (wl_registry_add_listener(registry, &wl->registry_listener, wl) < 0) {
260 mrp_log_error("can't add listener for registry (display '%s')",
261 get_display_name(wl));
262 wl_registry_destroy(registry);
263 wl_display_disconnect(display);
267 if (!(iow = mrp_add_io_watch(wl->ml,fd,IO_EVENTS,display_io_watch,wl))) {
268 mrp_log_error("can't add io watch for display '%s')",
269 get_display_name(wl));
270 wl_registry_destroy(registry);
271 wl_display_disconnect(display);
276 wl->display = display;
277 wl->registry = registry;
279 mrp_log_info("connecting to wayland display '%s'", get_display_name(wl));
281 wl_display_roundtrip(display);
283 mrp_debug("queried interfaces");
285 wl_display_roundtrip(display);
287 mrp_log_info("display '%s' is up and running", get_display_name(wl));
294 void mrp_wayland_flush(mrp_wayland_t *wl)
296 MRP_ASSERT(wl, "invalid argument");
299 mrp_debug("calling wl_display_flush()");
300 wl_display_flush(wl->display);
305 static int update_layers(void *key, void *object, void *ud)
307 mrp_wayland_window_manager_t *wm = (mrp_wayland_window_manager_t *)ud;
308 mrp_wayland_layer_t *layer = (mrp_wayland_layer_t *)object;
312 mrp_debug("register window manager to layer %u/'%s'",
313 layer->layerid, layer->name);
317 return MRP_HTBL_ITER_MORE;
321 void mrp_wayland_register_window_manager(mrp_wayland_t *wl,
322 mrp_wayland_window_manager_t *wm)
326 mrp_htbl_foreach(wl->layers.by_id, update_layers, wm);
328 if (wl->window_manager_update_callback) {
329 wl->window_manager_update_callback(wl,
330 MRP_WAYLAND_WINDOW_MANAGER_CREATE,
336 static int update_devices(void *key, void *object, void *ud)
338 mrp_wayland_input_manager_t *im = (mrp_wayland_input_manager_t *)ud;
339 mrp_wayland_input_device_t *device = (mrp_wayland_input_device_t *)object;
343 mrp_debug("register input manager to device '%s'", device->name);
347 return MRP_HTBL_ITER_MORE;
351 void mrp_wayland_register_input_manager(mrp_wayland_t *wl,
352 mrp_wayland_input_manager_t *im)
356 mrp_htbl_foreach(wl->devices.by_name, update_devices, im);
358 if (wl->input_manager_update_callback) {
359 wl->input_manager_update_callback(wl, MRP_WAYLAND_INPUT_MANAGER_CREATE,
365 bool mrp_wayland_register_interface(mrp_wayland_t *wl,
366 mrp_wayland_factory_t *factory)
368 mrp_wayland_interface_t *wif;
371 MRP_ASSERT(wl && factory, "invalid argument");
372 MRP_ASSERT(factory->size >= sizeof(mrp_wayland_object_t),
373 "invalid object size in factory");
374 MRP_ASSERT(factory->interface, "missing factory interface");
376 name = factory->interface->name;
378 MRP_ASSERT(name, "broken factory interface");
380 if (!(wif = mrp_allocz(sizeof(mrp_wayland_interface_t)))) {
381 mrp_log_error("can't allocate memory for wayland interface '%s'",
387 wif->name = mrp_strdup(name);
388 wif->object_factory = *factory;
390 mrp_list_init(&wif->object_list);
392 if (!mrp_htbl_insert(wl->interfaces, (void *)wif->name, wif)) {
393 mrp_log_error("failed to add interface '%s' to hashtable. "
394 "Perhaps already registered ...", wif->name);
395 mrp_free((void *)wif->name);
400 mrp_log_info("registered wayland interface '%s'", wif->name);
405 void mrp_wayland_register_window_manager_update_callback(mrp_wayland_t *wl,
406 mrp_wayland_window_manager_update_callback_t callback)
408 MRP_ASSERT(wl, "invalid aruments");
410 mrp_debug("registering window_manager_update_callback");
412 wl->window_manager_update_callback = callback;
415 void mrp_wayland_register_output_update_callback(mrp_wayland_t *wl,
416 mrp_wayland_output_update_callback_t callback)
418 MRP_ASSERT(wl, "invalid aruments");
420 mrp_debug("registering output_update_callback");
422 wl->output_update_callback = callback;
425 void mrp_wayland_register_window_update_callback(mrp_wayland_t *wl,
426 mrp_wayland_window_update_callback_t callback)
428 MRP_ASSERT(wl, "invalid aruments");
430 mrp_debug("registering window_update_callback");
432 wl->window_update_callback = callback;
435 void mrp_wayland_register_window_hint_callback(mrp_wayland_t *wl,
436 mrp_wayland_window_hint_callback_t callback)
438 MRP_ASSERT(wl, "invalid aruments");
440 mrp_debug("registering window_hint_callback");
442 wl->window_hint_callback = callback;
445 void mrp_wayland_register_layer_update_callback(mrp_wayland_t *wl,
446 mrp_wayland_layer_update_callback_t callback)
448 MRP_ASSERT(wl, "invalid aruments");
450 mrp_debug("registering layer_update_callback");
452 wl->layer_update_callback = callback;
455 void mrp_wayland_register_area_update_callback(mrp_wayland_t *wl,
456 mrp_wayland_area_update_callback_t callback)
458 MRP_ASSERT(wl, "invalid aruments");
460 mrp_debug("registering area_update_callback");
462 wl->area_update_callback = callback;
465 void mrp_wayland_set_scripting_window_data(mrp_wayland_t *wl, void *data)
467 MRP_ASSERT(wl, "invalid argument");
469 mrp_debug("%sset scripting data", data ? "" : "re");
471 wl->scripting_window_data = data;
474 void mrp_wayland_register_input_manager_update_callback(mrp_wayland_t *wl,
475 mrp_wayland_input_manager_update_callback_t callback)
477 MRP_ASSERT(wl, "invalid aruments");
479 mrp_debug("registering input_manager_update_callback");
481 wl->input_manager_update_callback = callback;
484 void mrp_wayland_register_input_update_callback(mrp_wayland_t *wl,
485 mrp_wayland_input_update_callback_t callback)
487 MRP_ASSERT(wl, "invalid aruments");
489 mrp_debug("registering input_update_callback");
491 wl->input_update_callback = callback;
494 void mrp_wayland_register_code_update_callback(mrp_wayland_t *wl,
495 mrp_wayland_code_update_callback_t callback)
497 MRP_ASSERT(wl, "invalid aruments");
499 mrp_debug("registering code_update_callback");
501 wl->code_update_callback = callback;
504 void mrp_wayland_set_scripting_input_data(mrp_wayland_t *wl, void *data)
506 MRP_ASSERT(wl, "invalid argument");
508 mrp_debug("%sset scripting data", data ? "" : "re");
510 wl->scripting_input_data = data;
513 void mrp_wayland_create_scripting_windows(mrp_wayland_t *wl, bool create)
515 MRP_ASSERT(wl, "invalid argument");
517 mrp_debug("%screate scripting windows", create ? "" : "do not ");
519 wl->create_scripting_windows = create;
523 void mrp_wayland_create_scripting_outputs(mrp_wayland_t *wl, bool create)
525 MRP_ASSERT(wl, "invalid argument");
527 mrp_debug("%screate scripting outputs", create ? "" : "do not ");
529 wl->create_scripting_outputs = create;
533 void mrp_wayland_create_scripting_areas(mrp_wayland_t *wl, bool create)
535 MRP_ASSERT(wl, "invalid argument");
537 mrp_debug("%screate scripting areas", create ? "" : "do not ");
539 wl->create_scripting_areas = create;
543 void mrp_wayland_create_scripting_layers(mrp_wayland_t *wl, bool create)
545 MRP_ASSERT(wl, "invalid argument");
547 mrp_debug("%screate scripting layers", create ? "" : "do not ");
549 wl->create_scripting_layers = create;
553 void mrp_wayland_create_scripting_inputs(mrp_wayland_t *wl, bool create)
555 MRP_ASSERT(wl, "invalid argument");
557 mrp_debug("%screate scripting inputs", create ? "" : "do not ");
559 wl->create_scripting_inputs = create;
562 static uint32_t oid_hash(const void *pkey)
564 uint32_t key = *(uint32_t *)pkey;
566 return key % MRP_WAYLAND_OUTPUT_BUCKETS;
569 static uint32_t wid_hash(const void *pkey)
571 uint32_t key = *(uint32_t *)pkey;
573 return key % MRP_WAYLAND_WINDOW_BUCKETS;
576 static uint32_t lid_hash(const void *pkey)
578 uint32_t key = *(uint32_t *)pkey;
580 return key % MRP_WAYLAND_LAYER_BUCKETS;
583 static uint32_t ltype_hash(const void *pkey)
585 uint32_t type = (uint32_t)(*(mrp_wayland_layer_type_t *)pkey);
588 key = (type & 0xff) + ((type / 10) & 0xff) + ((type & 0xfffff000) >> 8);
590 return key % MRP_WAYLAND_LAYER_BUCKETS;
593 static uint32_t did_hash(const void *pkey)
595 uint32_t key = *(uint32_t *)pkey;
597 return key % MRP_WAYLAND_DEVICE_BUCKETS;
600 static int id_compare(const void *pkey1, const void *pkey2)
602 int32_t key1 = *(int32_t *)pkey1;
603 int32_t key2 = *(int32_t *)pkey2;
605 return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
608 static int ltype_compare(const void *pkey1, const void *pkey2)
610 mrp_wayland_layer_type_t key1 = *(mrp_wayland_layer_type_t *)pkey1;
611 mrp_wayland_layer_type_t key2 = *(mrp_wayland_layer_type_t *)pkey2;
613 return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
617 static bool same_display_name(const char *name1, const char *name2)
619 if (!name1 && !name2)
620 return true; /* if none is specified */
622 if (name1 && name2 && !strcmp(name1, name2))
623 return true; /* if both are specified and match */
628 static const char *get_display_name(mrp_wayland_t *wl)
630 const char *display_name;
632 MRP_ASSERT(wl, "invalid argument");
634 if (wl->display_name)
635 return wl->display_name;
637 if ((display_name = getenv("WAYLAND_DISPLAY")) != NULL)
643 static void display_io_watch(mrp_io_watch_t *iow,
645 mrp_io_event_t events,
648 mrp_wayland_t *wl = (mrp_wayland_t *)ud;
655 MRP_ASSERT(wl, "invalid user data");
656 MRP_ASSERT(iow == wl->iow, "mismatching io watch");
661 if ((events & MRP_IO_EVENT_HUP)) {
662 mrp_log_info("display '%s' is gone", get_display_name(wl));
664 wl_registry_destroy(wl->registry);
665 wl_display_disconnect(wl->display);
673 if ((events & MRP_IO_EVENT_ERR)) {
674 mrp_log_error("I/O error on display '%s'", get_display_name(wl));
678 if ((events & MRP_IO_EVENT_IN)) {
679 events &= ~MRP_IO_EVENT_IN;
681 mrp_debug("dispatching inputs from display '%s'",get_display_name(wl));
683 if (wl_display_dispatch(wl->display) < 0) {
684 mrp_log_error("failed to dispatch events of display '%s'",
685 get_display_name(wl));
688 wl_display_flush(wl->display);
694 p += snprintf(p, e-p, "%s%s", p > evlist ? " " : "", w); \
696 # define CHECK_EVENT(e) \
697 if ((events & MRP_IO_EVENT_ ## e)) { \
700 events &= ~MRP_IO_EVENT_ ## e; \
703 e = (p = evlist) + (sizeof(evlist) - 1);
709 snprintf(evnam, sizeof(evnam), "<unknown 0x%x>", events);
713 mrp_debug("unhandled io events: %s", evlist);
720 static void object_create(mrp_wayland_interface_t *wif,
725 mrp_wayland_factory_t *factory;
726 mrp_wayland_object_t *obj;
727 struct wl_proxy *proxy;
729 MRP_ASSERT(wif, "invalid argument");
732 factory = &wif->object_factory;
734 if (!(obj = mrp_allocz(factory->size))) {
735 mrp_log_error("can't allocate %zd byte memory for %u/'%s' object",
736 factory->size, (unsigned int)name, wif->name);
740 proxy = wl_registry_bind(wl->registry, name, factory->interface, 1);
743 mrp_log_error("failed to create proxy for object %u/'%s' on "
744 "display '%s'", name, wif->name, get_display_name(wl));
749 mrp_list_init(&obj->interface_link);
750 obj->interface = wif;
752 obj->version = version;
755 if (factory->constructor) {
756 if (!factory->constructor(wl, obj)) {
757 mrp_log_error("failed to construct object %u/'%s' on "
758 "display '%s'",name,wif->name, get_display_name(wl));
759 wl_proxy_destroy(proxy);
764 mrp_list_append(&wif->object_list, &obj->interface_link);
765 /* TODO: register the object by name as well*/
767 mrp_debug("object %u/'%s' on display '%s' created", name, wif->name,
768 get_display_name(wl));
772 static void global_available_callback(void *data,
773 struct wl_registry *registry,
775 const char *interface,
778 mrp_wayland_t *wl = (mrp_wayland_t *)data;
779 mrp_wayland_interface_t *wif;
781 MRP_ASSERT(wl && registry && interface, "invalid argument");
782 MRP_ASSERT(registry == wl->registry, "confused with data structures");
784 wif = mrp_htbl_lookup(wl->interfaces, (void *)interface);
786 mrp_debug("object %u/%s is up%s", name, interface,
787 wif ? "" : " (interface unknown)");
790 MRP_ASSERT(wif->wl == wl, "confused with data structures");
791 object_create(wif, name, version);
795 static void global_remove_callback(void *data,
796 struct wl_registry *wl_registry,
800 MRP_UNUSED(wl_registry);
802 mrp_debug("object %u is down", name);