packaging: do not install ico-homescreen.service.
[profile/ivi/murphy.git] / src / plugins / system-controller / wayland / wayland.c
1 /*
2  * Copyright (c) 2013, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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.
16  *
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.
28  */
29
30 #include <stdint.h>
31 #include <stdbool.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include <murphy/common.h>
38
39 #include "wayland.h"
40 #include "output.h"
41 #include "layer.h"
42 #include "input.h"
43 #include "window-manager.h"
44 #include "input-manager.h"
45
46
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 *);
54
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);
62
63 static mrp_wayland_t **instances;
64 static size_t ninstance;
65
66
67 mrp_wayland_t *mrp_wayland_create(const char *display_name, mrp_mainloop_t *ml)
68 {
69     mrp_wayland_t *wl;
70     mrp_htbl_config_t icfg, oxcfg,oicfg, wcfg, licfg,ltcfg, acfg, dncfg,dicfg;
71     size_t i;
72
73     MRP_ASSERT(ml, "invalid argument");
74
75     for (i = 0;  i < ninstance;  i++) {
76         wl = instances[i];
77
78         if (same_display_name(display_name, wl->display_name))
79             return wl;
80     }
81
82     if (!(wl = mrp_allocz(sizeof(mrp_wayland_t))))
83         mrp_log_error("can't allocate memory for wayland");
84     else {
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;
90
91         memset(&wcfg, 0, sizeof(wcfg));
92         wcfg.nentry = MRP_WAYLAND_WINDOW_MAX;
93         wcfg.comp = id_compare;
94         wcfg.hash = wid_hash;
95         wcfg.nbucket = MRP_WAYLAND_WINDOW_BUCKETS;
96
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;
102
103         memset(&ltcfg, 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;
108
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;
114
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;
120
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;
126
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;
132
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;
138
139         wl->display_name = display_name ? mrp_strdup(display_name) : NULL;
140         wl->ml = ml;
141
142         wl->registry_listener.global = global_available_callback;
143         wl->registry_listener.global_remove = global_remove_callback;
144
145         wl->interfaces = mrp_htbl_create(&icfg);
146         wl->windows = mrp_htbl_create(&wcfg);
147         wl->areas = mrp_htbl_create(&acfg);
148
149         wl->outputs.by_index = mrp_htbl_create(&oxcfg);
150         wl->outputs.by_id = mrp_htbl_create(&oicfg);
151
152         wl->devices.by_name = mrp_htbl_create(&dncfg);
153         wl->devices.by_id = mrp_htbl_create(&dicfg);
154
155         wl->layers.by_id = mrp_htbl_create(&licfg);
156         wl->layers.by_type = mrp_htbl_create(&ltcfg);
157
158
159         instances = mrp_reallocz(instances, ninstance, ninstance + 2);
160         instances[ninstance++] = wl;
161     }
162
163     return wl;
164 }
165
166 void mrp_wayland_destroy(mrp_wayland_t *wl)
167 {
168     size_t i;
169
170     if (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));
176                 }
177                 instances[--ninstance] = NULL;
178                 break;
179             }
180         }
181     }
182 }
183
184 mrp_wayland_t *mrp_wayland_iterate(void **cursor)
185 {
186     ptrdiff_t i;
187
188     if (cursor) {
189         i = *cursor - NULL;
190
191         if (i >= 0 && i < (ptrdiff_t)ninstance) {
192             *cursor = NULL + (i + 1);
193             return instances[i];
194         }
195     }
196
197     return NULL;
198 }
199
200 bool mrp_wayland_disconnect(mrp_wayland_t *wl)
201 {
202     if (!wl)
203         return FALSE;
204
205     /* destroy resource */
206     if (wl->registry) {
207         wl_registry_destroy(wl->registry);
208         wl->registry = NULL;
209     }
210
211     /* disconnect from display */
212     if (wl->display) {
213         wl_display_disconnect(wl->display);
214         wl->display = NULL;
215     }
216
217     /* io watch */
218
219     if (wl->iow) {
220         mrp_del_io_watch(wl->iow);
221         wl->iow = NULL;
222     }
223
224     return TRUE;
225 }
226
227 bool mrp_wayland_connect(mrp_wayland_t *wl)
228 {
229 #define IO_EVENTS MRP_IO_EVENT_IN | MRP_IO_EVENT_ERR | MRP_IO_EVENT_HUP
230
231     struct wl_display *display;
232     struct wl_registry *registry;
233     mrp_io_watch_t *iow;
234     int fd;
235
236     MRP_ASSERT(wl, "invalid argument");
237     MRP_ASSERT(wl->ml, "no mainloop");
238
239     if (wl->iow)
240         return true; /* we are already connected */
241
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));
245         return false;
246     }
247
248     fd = wl_display_get_fd(display);
249
250     MRP_ASSERT(fd >= 0, "fd for wayland display < 0");
251
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);
256         return false;
257     }
258
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);
264         return false;
265     }
266
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);
272         return false;
273     }
274
275     wl->iow = iow;
276     wl->display = display;
277     wl->registry = registry;
278
279     mrp_log_info("connecting to wayland display '%s'", get_display_name(wl));
280
281     wl_display_roundtrip(display);
282
283     mrp_debug("queried interfaces");
284
285     wl_display_roundtrip(display);
286
287     mrp_log_info("display '%s' is up and running", get_display_name(wl));
288
289     return true;
290
291 #undef IO_EVENTS
292 }
293
294 void mrp_wayland_flush(mrp_wayland_t *wl)
295 {
296     MRP_ASSERT(wl, "invalid argument");
297
298     if (wl->display) {
299         mrp_debug("calling wl_display_flush()");
300         wl_display_flush(wl->display);
301     }
302 }
303
304
305 static int update_layers(void *key, void *object, void *ud)
306 {
307     mrp_wayland_window_manager_t *wm = (mrp_wayland_window_manager_t *)ud;
308     mrp_wayland_layer_t *layer = (mrp_wayland_layer_t *)object;
309
310     MRP_UNUSED(key);
311
312     mrp_debug("register window manager to layer %u/'%s'",
313               layer->layerid, layer->name);
314
315     layer->wm = wm;
316
317     return MRP_HTBL_ITER_MORE;
318 }
319
320
321 void mrp_wayland_register_window_manager(mrp_wayland_t *wl,
322                                          mrp_wayland_window_manager_t *wm)
323 {
324     wl->wm = wm;
325
326     mrp_htbl_foreach(wl->layers.by_id, update_layers, wm);
327
328     if (wl->window_manager_update_callback) {
329         wl->window_manager_update_callback(wl,
330                                            MRP_WAYLAND_WINDOW_MANAGER_CREATE,
331                                            wm);
332     }
333 }
334
335
336 static int update_devices(void *key, void *object, void *ud)
337 {
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;
340
341     MRP_UNUSED(key);
342
343     mrp_debug("register input manager to device '%s'", device->name);
344
345     device->im = im;
346
347     return MRP_HTBL_ITER_MORE;
348 }
349
350
351 void mrp_wayland_register_input_manager(mrp_wayland_t *wl,
352                                         mrp_wayland_input_manager_t *im)
353 {
354     wl->im = im;
355
356     mrp_htbl_foreach(wl->devices.by_name, update_devices, im);
357
358     if (wl->input_manager_update_callback) {
359         wl->input_manager_update_callback(wl, MRP_WAYLAND_INPUT_MANAGER_CREATE,
360                                           im);
361     }
362 }
363
364
365 bool mrp_wayland_register_interface(mrp_wayland_t *wl,
366                                     mrp_wayland_factory_t *factory)
367 {
368     mrp_wayland_interface_t *wif;
369     const char *name;
370
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");
375
376     name = factory->interface->name;
377
378     MRP_ASSERT(name, "broken factory interface");
379
380     if (!(wif = mrp_allocz(sizeof(mrp_wayland_interface_t)))) {
381         mrp_log_error("can't allocate memory for wayland interface '%s'",
382                       name);
383         return false;
384     }
385
386     wif->wl = wl;
387     wif->name = mrp_strdup(name);
388     wif->object_factory = *factory;
389
390     mrp_list_init(&wif->object_list);
391
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);
396         mrp_free(wif);
397         return false;
398     }
399
400     mrp_log_info("registered wayland interface '%s'", wif->name);
401
402     return true;
403 }
404
405 void mrp_wayland_register_window_manager_update_callback(mrp_wayland_t *wl,
406                          mrp_wayland_window_manager_update_callback_t callback)
407 {
408     MRP_ASSERT(wl, "invalid aruments");
409
410     mrp_debug("registering window_manager_update_callback");
411
412     wl->window_manager_update_callback = callback;
413 }
414
415 void mrp_wayland_register_output_update_callback(mrp_wayland_t *wl,
416                                mrp_wayland_output_update_callback_t callback)
417 {
418     MRP_ASSERT(wl, "invalid aruments");
419
420     mrp_debug("registering output_update_callback");
421
422     wl->output_update_callback = callback;
423 }
424
425 void mrp_wayland_register_window_update_callback(mrp_wayland_t *wl,
426                                mrp_wayland_window_update_callback_t callback)
427 {
428     MRP_ASSERT(wl, "invalid aruments");
429
430     mrp_debug("registering window_update_callback");
431
432     wl->window_update_callback = callback;
433 }
434
435 void mrp_wayland_register_window_hint_callback(mrp_wayland_t *wl,
436                                mrp_wayland_window_hint_callback_t callback)
437 {
438     MRP_ASSERT(wl, "invalid aruments");
439
440     mrp_debug("registering window_hint_callback");
441
442     wl->window_hint_callback = callback;
443 }
444
445 void mrp_wayland_register_layer_update_callback(mrp_wayland_t *wl,
446                                mrp_wayland_layer_update_callback_t callback)
447 {
448     MRP_ASSERT(wl, "invalid aruments");
449
450     mrp_debug("registering layer_update_callback");
451
452     wl->layer_update_callback = callback;
453 }
454
455 void mrp_wayland_register_area_update_callback(mrp_wayland_t *wl,
456                                mrp_wayland_area_update_callback_t callback)
457 {
458     MRP_ASSERT(wl, "invalid aruments");
459
460     mrp_debug("registering area_update_callback");
461
462     wl->area_update_callback = callback;
463 }
464
465 void mrp_wayland_set_scripting_window_data(mrp_wayland_t *wl, void *data)
466 {
467     MRP_ASSERT(wl, "invalid argument");
468
469     mrp_debug("%sset scripting data", data ? "" : "re");
470
471     wl->scripting_window_data = data;
472 }
473
474 void mrp_wayland_register_input_manager_update_callback(mrp_wayland_t *wl,
475                           mrp_wayland_input_manager_update_callback_t callback)
476 {
477     MRP_ASSERT(wl, "invalid aruments");
478
479     mrp_debug("registering input_manager_update_callback");
480
481     wl->input_manager_update_callback = callback;
482 }
483
484 void mrp_wayland_register_input_update_callback(mrp_wayland_t *wl,
485                                   mrp_wayland_input_update_callback_t callback)
486 {
487     MRP_ASSERT(wl, "invalid aruments");
488
489     mrp_debug("registering input_update_callback");
490
491     wl->input_update_callback = callback;
492 }
493
494 void mrp_wayland_register_code_update_callback(mrp_wayland_t *wl,
495                                    mrp_wayland_code_update_callback_t callback)
496 {
497     MRP_ASSERT(wl, "invalid aruments");
498
499     mrp_debug("registering code_update_callback");
500
501     wl->code_update_callback = callback;
502 }
503
504 void mrp_wayland_set_scripting_input_data(mrp_wayland_t *wl, void *data)
505 {
506     MRP_ASSERT(wl, "invalid argument");
507
508     mrp_debug("%sset scripting data", data ? "" : "re");
509
510     wl->scripting_input_data = data;
511 }
512
513 void mrp_wayland_create_scripting_windows(mrp_wayland_t *wl, bool create)
514 {
515     MRP_ASSERT(wl, "invalid argument");
516
517     mrp_debug("%screate scripting windows", create ? "" : "do not ");
518
519     wl->create_scripting_windows = create;
520 }
521
522
523 void mrp_wayland_create_scripting_outputs(mrp_wayland_t *wl, bool create)
524 {
525     MRP_ASSERT(wl, "invalid argument");
526
527     mrp_debug("%screate scripting outputs", create ? "" : "do not ");
528
529     wl->create_scripting_outputs = create;
530 }
531
532
533 void mrp_wayland_create_scripting_areas(mrp_wayland_t *wl, bool create)
534 {
535     MRP_ASSERT(wl, "invalid argument");
536
537     mrp_debug("%screate scripting areas", create ? "" : "do not ");
538
539     wl->create_scripting_areas = create;
540 }
541
542
543 void mrp_wayland_create_scripting_layers(mrp_wayland_t *wl, bool create)
544 {
545     MRP_ASSERT(wl, "invalid argument");
546
547     mrp_debug("%screate scripting layers", create ? "" : "do not ");
548
549     wl->create_scripting_layers = create;
550 }
551
552
553 void mrp_wayland_create_scripting_inputs(mrp_wayland_t *wl, bool create)
554 {
555     MRP_ASSERT(wl, "invalid argument");
556
557     mrp_debug("%screate scripting inputs", create ? "" : "do not ");
558
559     wl->create_scripting_inputs = create;
560 }
561
562 static uint32_t oid_hash(const void *pkey)
563 {
564     uint32_t key = *(uint32_t *)pkey;
565
566     return key % MRP_WAYLAND_OUTPUT_BUCKETS;
567 }
568
569 static uint32_t wid_hash(const void *pkey)
570 {
571     uint32_t key = *(uint32_t *)pkey;
572
573     return key % MRP_WAYLAND_WINDOW_BUCKETS;
574 }
575
576 static uint32_t lid_hash(const void *pkey)
577 {
578     uint32_t key = *(uint32_t *)pkey;
579
580     return key % MRP_WAYLAND_LAYER_BUCKETS;
581 }
582
583 static uint32_t ltype_hash(const void *pkey)
584 {
585     uint32_t type = (uint32_t)(*(mrp_wayland_layer_type_t *)pkey);
586     uint32_t key;
587
588     key  = (type & 0xff) + ((type / 10) & 0xff) + ((type & 0xfffff000) >> 8);
589
590     return key % MRP_WAYLAND_LAYER_BUCKETS;
591 }
592
593 static uint32_t did_hash(const void *pkey)
594 {
595     uint32_t key = *(uint32_t *)pkey;
596
597     return key % MRP_WAYLAND_DEVICE_BUCKETS;
598 }
599
600 static int id_compare(const void *pkey1, const void *pkey2)
601 {
602     int32_t key1 = *(int32_t *)pkey1;
603     int32_t key2 = *(int32_t *)pkey2;
604
605     return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
606 }
607
608 static int ltype_compare(const void *pkey1, const void *pkey2)
609 {
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;
612
613     return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1);
614 }
615
616
617 static bool same_display_name(const char *name1, const char *name2)
618 {
619     if (!name1 && !name2)
620         return true;            /* if none is specified */
621
622     if (name1 && name2 && !strcmp(name1, name2))
623         return true;            /* if both are specified and match */
624
625     return false;
626 }
627
628 static const char *get_display_name(mrp_wayland_t *wl)
629 {
630     const char *display_name;
631
632     MRP_ASSERT(wl, "invalid argument");
633
634     if (wl->display_name)
635         return wl->display_name;
636
637     if ((display_name = getenv("WAYLAND_DISPLAY")) != NULL)
638         return display_name;
639
640     return "wayland-0";
641 }
642
643 static void display_io_watch(mrp_io_watch_t *iow,
644                              int fd,
645                              mrp_io_event_t events,
646                              void *ud)
647 {
648     mrp_wayland_t *wl = (mrp_wayland_t *)ud;
649     char evnam[32];
650     char evlist[1024];
651     char *p, *e;
652
653     MRP_UNUSED(fd);
654
655     MRP_ASSERT(wl, "invalid user data");
656     MRP_ASSERT(iow == wl->iow, "mismatching io watch");
657
658     if (!wl->display)
659         return;
660
661     if ((events & MRP_IO_EVENT_HUP)) {
662         mrp_log_info("display '%s' is gone", get_display_name(wl));
663
664         wl_registry_destroy(wl->registry);
665         wl_display_disconnect(wl->display);
666
667         wl->registry = NULL;
668         wl->display = NULL;
669
670         return;
671     }
672
673     if ((events & MRP_IO_EVENT_ERR)) {
674         mrp_log_error("I/O error on display '%s'", get_display_name(wl));
675         return;
676     }
677
678     if ((events & MRP_IO_EVENT_IN)) {
679         events &= ~MRP_IO_EVENT_IN;
680
681         mrp_debug("dispatching inputs from display '%s'",get_display_name(wl));
682
683         if (wl_display_dispatch(wl->display) < 0) {
684             mrp_log_error("failed to dispatch events of display '%s'",
685                           get_display_name(wl));
686         }
687
688         wl_display_flush(wl->display);
689     }
690
691     if (events) {
692 #       define PRINT(w)                                                    \
693             if (p < e) {                                                   \
694                 p += snprintf(p, e-p, "%s%s", p > evlist ? " " : "", w);   \
695             }
696 #       define CHECK_EVENT(e)                                              \
697             if ((events & MRP_IO_EVENT_ ## e)) {                           \
698                 char *evnam = #e;                                          \
699                 PRINT(evnam);                                              \
700                 events &= ~MRP_IO_EVENT_ ## e;                             \
701             }
702
703         e = (p = evlist) + (sizeof(evlist) - 1);
704
705         CHECK_EVENT(PRI);
706         CHECK_EVENT(OUT);
707
708         if (events) {
709             snprintf(evnam, sizeof(evnam), "<unknown 0x%x>", events);
710             PRINT(evnam);
711         }
712
713         mrp_debug("unhandled io events: %s", evlist);
714
715 #       undef CHECK_EVENT
716 #       undef PRINT
717     }
718 }
719
720 static void object_create(mrp_wayland_interface_t *wif,
721                           uint32_t name,
722                           uint32_t version)
723 {
724     mrp_wayland_t *wl;
725     mrp_wayland_factory_t *factory;
726     mrp_wayland_object_t *obj;
727     struct wl_proxy *proxy;
728
729     MRP_ASSERT(wif, "invalid argument");
730
731     wl = wif->wl;
732     factory = &wif->object_factory;
733
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);
737         return;
738     }
739
740     proxy = wl_registry_bind(wl->registry, name, factory->interface, 1);
741
742     if (!proxy) {
743         mrp_log_error("failed to create proxy for object %u/'%s' on "
744                       "display '%s'", name, wif->name, get_display_name(wl));
745         mrp_free(obj);
746         return;
747     }
748
749     mrp_list_init(&obj->interface_link);
750     obj->interface = wif;
751     obj->name = name;
752     obj->version = version;
753     obj->proxy = proxy;
754
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);
760             mrp_free(obj);
761         }
762     }
763
764     mrp_list_append(&wif->object_list, &obj->interface_link);
765     /* TODO: register the object by name as well*/
766
767     mrp_debug("object %u/'%s' on display '%s' created", name, wif->name,
768               get_display_name(wl));
769 }
770
771
772 static void global_available_callback(void *data,
773                                       struct wl_registry *registry,
774                                       uint32_t name,
775                                       const char *interface,
776                                       uint32_t version)
777 {
778     mrp_wayland_t *wl = (mrp_wayland_t *)data;
779     mrp_wayland_interface_t *wif;
780
781     MRP_ASSERT(wl && registry && interface, "invalid argument");
782     MRP_ASSERT(registry == wl->registry, "confused with data structures");
783
784     wif = mrp_htbl_lookup(wl->interfaces, (void *)interface);
785
786     mrp_debug("object %u/%s is up%s", name, interface,
787               wif ? "" : " (interface unknown)");
788
789     if (wif) {
790         MRP_ASSERT(wif->wl == wl, "confused with data structures");
791         object_create(wif, name, version);
792     }
793 }
794
795 static void global_remove_callback(void *data,
796                                    struct wl_registry *wl_registry,
797                                    uint32_t name)
798 {
799     MRP_UNUSED(data);
800     MRP_UNUSED(wl_registry);
801
802     mrp_debug("object %u is down", name);
803 }