• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012 Collabora, Ltd.
3  * Copyright © 2013 Ran Benita <ran234@gmail.com>
4  * Copyright © 2016 Daniel Stone <daniel@fooishbar.org>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <locale.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/mman.h>
36 #include <unistd.h>
37 
38 #include "xkbcommon/xkbcommon.h"
39 #include "tools-common.h"
40 
41 #include <wayland-client.h>
42 #include "xdg-shell-client-protocol.h"
43 #include <wayland-util.h>
44 
45 #define MAX(a, b) ((a) > (b) ? (a) : (b))
46 
47 struct interactive_dpy {
48     struct wl_display *dpy;
49     struct wl_compositor *compositor;
50     struct xdg_wm_base *shell;
51     struct wl_shm *shm;
52     uint32_t shm_format;
53 
54     struct xkb_context *ctx;
55 
56     struct wl_surface *wl_surf;
57     struct xdg_surface *xdg_surf;
58     struct xdg_toplevel *xdg_top;
59 
60     struct wl_list seats;
61 };
62 
63 struct interactive_seat {
64     struct interactive_dpy *inter;
65 
66     struct wl_seat *wl_seat;
67     struct wl_keyboard *wl_kbd;
68     struct wl_pointer *wl_pointer;
69     uint32_t version; /* ... of wl_seat */
70     uint32_t global_name; /* an ID of sorts */
71     char *name_str; /* a descriptor */
72 
73     struct xkb_keymap *keymap;
74     struct xkb_state *state;
75 
76     struct wl_list link;
77 };
78 
79 static bool terminate;
80 
81 #ifdef HAVE_MKOSTEMP
82 static int
create_tmpfile_cloexec(char * tmpname)83 create_tmpfile_cloexec(char *tmpname)
84 {
85     int fd = mkostemp(tmpname, O_CLOEXEC);
86     if (fd >= 0)
87         unlink(tmpname);
88     return fd;
89 }
90 #else
91 /* The following utility functions are taken from Weston's
92  * shared/os-compatibility.c. */
93 static int
os_fd_set_cloexec(int fd)94 os_fd_set_cloexec(int fd)
95 {
96     long flags;
97 
98     if (fd == -1)
99         return -1;
100 
101     flags = fcntl(fd, F_GETFD);
102     if (flags == -1)
103         return -1;
104 
105     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
106         return -1;
107 
108     return 0;
109 }
110 
111 static int
set_cloexec_or_close(int fd)112 set_cloexec_or_close(int fd)
113 {
114     if (os_fd_set_cloexec(fd) != 0) {
115         close(fd);
116         return -1;
117     }
118     return fd;
119 }
120 
121 static int
create_tmpfile_cloexec(char * tmpname)122 create_tmpfile_cloexec(char *tmpname)
123 {
124     int fd = mkstemp(tmpname);
125     if (fd >= 0) {
126         fd = set_cloexec_or_close(fd);
127         unlink(tmpname);
128     }
129     return fd;
130 }
131 #endif
132 
133 /*
134  * Create a new, unique, anonymous file of the given size, and
135  * return the file descriptor for it. The file descriptor is set
136  * CLOEXEC. The file is immediately suitable for mmap()'ing
137  * the given size at offset zero.
138  *
139  * The file should not have a permanent backing store like a disk,
140  * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
141  *
142  * The file name is deleted from the file system.
143  *
144  * The file is suitable for buffer sharing between processes by
145  * transmitting the file descriptor over Unix sockets using the
146  * SCM_RIGHTS methods.
147  *
148  * If the C library implements posix_fallocate(), it is used to
149  * guarantee that disk space is available for the file at the
150  * given size. If disk space is insufficent, errno is set to ENOSPC.
151  * If posix_fallocate() is not supported, program may receive
152  * SIGBUS on accessing mmap()'ed file contents instead.
153  */
154 static int
os_create_anonymous_file(off_t size)155 os_create_anonymous_file(off_t size)
156 {
157     static const char template[] = "/weston-shared-XXXXXX";
158     const char *path;
159     char *name;
160     int fd;
161     int ret;
162 
163     path = getenv("XDG_RUNTIME_DIR");
164     if (!path) {
165         errno = ENOENT;
166         return -1;
167     }
168 
169     name = malloc(strlen(path) + sizeof(template));
170     if (!name)
171         return -1;
172 
173     strcpy(name, path);
174     strcat(name, template);
175 
176     fd = create_tmpfile_cloexec(name);
177 
178     free(name);
179 
180     if (fd < 0)
181         return -1;
182 
183 #ifdef HAVE_POSIX_FALLOCATE
184     ret = posix_fallocate(fd, 0, size);
185     if (ret != 0) {
186         close(fd);
187         errno = ret;
188         return -1;
189     }
190 #else
191     ret = ftruncate(fd, size);
192     if (ret < 0) {
193         close(fd);
194         return -1;
195     }
196 #endif
197 
198     return fd;
199 }
200 
201 static void
buffer_release(void * data,struct wl_buffer * buffer)202 buffer_release(void *data, struct wl_buffer *buffer)
203 {
204     wl_buffer_destroy(buffer);
205 }
206 
207 static const struct wl_buffer_listener buffer_listener = {
208     buffer_release
209 };
210 
211 static void
buffer_create(struct interactive_dpy * inter,uint32_t width,uint32_t height)212 buffer_create(struct interactive_dpy *inter, uint32_t width, uint32_t height)
213 {
214     struct wl_shm_pool *pool;
215     struct wl_buffer *buf;
216     struct wl_region *opaque;
217     uint32_t stride;
218     size_t size;
219     void *map;
220     int fd;
221 
222     switch (inter->shm_format) {
223     case WL_SHM_FORMAT_ARGB8888:
224     case WL_SHM_FORMAT_XRGB8888:
225     case WL_SHM_FORMAT_ABGR8888:
226     case WL_SHM_FORMAT_XBGR8888:
227         stride = width * 4;
228         break;
229     case WL_SHM_FORMAT_RGB565:
230     case WL_SHM_FORMAT_BGR565:
231         stride = width * 2;
232         break;
233     default:
234         fprintf(stderr, "Unsupported SHM format %d\n", inter->shm_format);
235         exit(1);
236     }
237 
238     size = stride * height;
239     fd = os_create_anonymous_file(size);
240     if (fd < 0) {
241         fprintf(stderr, "Couldn't create surface buffer\n");
242         exit(1);
243     }
244 
245     map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
246     if (map == MAP_FAILED) {
247         fprintf(stderr, "Couldn't mmap surface buffer\n");
248         exit(1);
249     }
250     memset(map, 0xff, size);
251     munmap(map, size);
252 
253     pool = wl_shm_create_pool(inter->shm, fd, size);
254     buf = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
255                                     inter->shm_format);
256     wl_buffer_add_listener(buf, &buffer_listener, inter);
257 
258     wl_surface_attach(inter->wl_surf, buf, 0, 0);
259     wl_surface_damage(inter->wl_surf, 0, 0, width, height);
260 
261     opaque = wl_compositor_create_region(inter->compositor);
262     wl_region_add(opaque, 0, 0, width, height);
263     wl_surface_set_opaque_region(inter->wl_surf, opaque);
264     wl_region_destroy(opaque);
265 
266     wl_shm_pool_destroy(pool);
267     close(fd);
268 }
269 
270 static void
surface_configure(void * data,struct xdg_surface * surface,uint32_t serial)271 surface_configure(void *data, struct xdg_surface *surface,
272                   uint32_t serial)
273 {
274     struct interactive_dpy *inter = data;
275 
276     xdg_surface_ack_configure(inter->xdg_surf, serial);
277     wl_surface_commit(inter->wl_surf);
278 }
279 
280 static const struct xdg_surface_listener surface_listener = {
281     surface_configure,
282 };
283 
284 static void
toplevel_configure(void * data,struct xdg_toplevel * toplevel,int32_t width,int32_t height,struct wl_array * states)285 toplevel_configure(void *data, struct xdg_toplevel *toplevel,
286                    int32_t width, int32_t height, struct wl_array *states)
287 {
288     struct interactive_dpy *inter = data;
289 
290     if (width == 0)
291         width = 200;
292     if (height == 0)
293         height = 200;
294 
295     buffer_create(inter, width, height);
296 }
297 
298 static void
toplevel_close(void * data,struct xdg_toplevel * toplevel)299 toplevel_close(void *data, struct xdg_toplevel *toplevel)
300 {
301     terminate = true;
302 }
303 
304 static const struct xdg_toplevel_listener toplevel_listener = {
305     toplevel_configure,
306     toplevel_close
307 };
308 
surface_create(struct interactive_dpy * inter)309 static void surface_create(struct interactive_dpy *inter)
310 {
311     inter->wl_surf = wl_compositor_create_surface(inter->compositor);
312     inter->xdg_surf = xdg_wm_base_get_xdg_surface(inter->shell, inter->wl_surf);
313     xdg_surface_add_listener(inter->xdg_surf, &surface_listener, inter);
314     inter->xdg_top = xdg_surface_get_toplevel(inter->xdg_surf);
315     xdg_toplevel_add_listener(inter->xdg_top, &toplevel_listener, inter);
316     xdg_toplevel_set_title(inter->xdg_top, "xkbcommon event tester");
317     xdg_toplevel_set_app_id(inter->xdg_top,
318                             "org.xkbcommon.test.interactive-wayland");
319     wl_surface_commit(inter->wl_surf);
320 }
321 
322 static void
shell_ping(void * data,struct xdg_wm_base * shell,uint32_t serial)323 shell_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
324 {
325     xdg_wm_base_pong(shell, serial);
326 }
327 
328 static const struct xdg_wm_base_listener shell_listener = {
329     shell_ping
330 };
331 
332 static void
kbd_keymap(void * data,struct wl_keyboard * wl_kbd,uint32_t format,int fd,uint32_t size)333 kbd_keymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format,
334            int fd, uint32_t size)
335 {
336     struct interactive_seat *seat = data;
337     void *buf;
338 
339     buf = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
340     if (buf == MAP_FAILED) {
341         fprintf(stderr, "Failed to mmap keymap: %d\n", errno);
342         close(fd);
343         return;
344     }
345 
346     seat->keymap = xkb_keymap_new_from_buffer(seat->inter->ctx, buf, size - 1,
347                                               XKB_KEYMAP_FORMAT_TEXT_V1,
348                                               XKB_KEYMAP_COMPILE_NO_FLAGS);
349     munmap(buf, size);
350     close(fd);
351     if (!seat->keymap) {
352         fprintf(stderr, "Failed to compile keymap!\n");
353         return;
354     }
355 
356     seat->state = xkb_state_new(seat->keymap);
357     if (!seat->state) {
358         fprintf(stderr, "Failed to create XKB state!\n");
359         return;
360     }
361 }
362 
363 static void
kbd_enter(void * data,struct wl_keyboard * wl_kbd,uint32_t serial,struct wl_surface * surf,struct wl_array * keys)364 kbd_enter(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
365           struct wl_surface *surf, struct wl_array *keys)
366 {
367 }
368 
369 static void
kbd_leave(void * data,struct wl_keyboard * wl_kbd,uint32_t serial,struct wl_surface * surf)370 kbd_leave(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
371           struct wl_surface *surf)
372 {
373 }
374 
375 static void
kbd_key(void * data,struct wl_keyboard * wl_kbd,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)376 kbd_key(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time,
377         uint32_t key, uint32_t state)
378 {
379     struct interactive_seat *seat = data;
380 
381     if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
382         return;
383 
384     printf("%s: ", seat->name_str);
385     tools_print_keycode_state(seat->state, NULL, key + 8,
386                               XKB_CONSUMED_MODE_XKB);
387 
388     /* Exit on ESC. */
389     if (xkb_state_key_get_one_sym(seat->state, key + 8) == XKB_KEY_Escape)
390         terminate = true;
391 }
392 
393 static void
kbd_modifiers(void * data,struct wl_keyboard * wl_kbd,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)394 kbd_modifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
395               uint32_t mods_depressed, uint32_t mods_latched,
396               uint32_t mods_locked, uint32_t group)
397 {
398     struct interactive_seat *seat = data;
399 
400     xkb_state_update_mask(seat->state, mods_depressed, mods_latched,
401                           mods_locked, 0, 0, group);
402 }
403 
404 static void
kbd_repeat_info(void * data,struct wl_keyboard * wl_kbd,int32_t rate,int32_t delay)405 kbd_repeat_info(void *data, struct wl_keyboard *wl_kbd, int32_t rate,
406                 int32_t delay)
407 {
408 }
409 
410 static const struct wl_keyboard_listener kbd_listener = {
411     kbd_keymap,
412     kbd_enter,
413     kbd_leave,
414     kbd_key,
415     kbd_modifiers,
416     kbd_repeat_info
417 };
418 
419 static void
pointer_enter(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surf,wl_fixed_t fsx,wl_fixed_t fsy)420 pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
421               struct wl_surface *surf, wl_fixed_t fsx, wl_fixed_t fsy)
422 {
423 }
424 
425 static void
pointer_leave(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surf)426 pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
427               struct wl_surface *surf)
428 {
429 }
430 
431 static void
pointer_motion(void * data,struct wl_pointer * wl_pointer,uint32_t time,wl_fixed_t fsx,wl_fixed_t fsy)432 pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
433                wl_fixed_t fsx, wl_fixed_t fsy)
434 {
435 }
436 
437 static void
pointer_button(void * data,struct wl_pointer * wl_pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state)438 pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
439                uint32_t time, uint32_t button, uint32_t state)
440 {
441     struct interactive_seat *seat = data;
442 
443     xdg_toplevel_move(seat->inter->xdg_top, seat->wl_seat, serial);
444 }
445 
446 static void
pointer_axis(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis,wl_fixed_t value)447 pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
448              uint32_t axis, wl_fixed_t value)
449 {
450 }
451 
452 static void
pointer_frame(void * data,struct wl_pointer * wl_pointer)453 pointer_frame(void *data, struct wl_pointer *wl_pointer)
454 {
455 }
456 
457 static void
pointer_axis_source(void * data,struct wl_pointer * wl_pointer,uint32_t source)458 pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t source)
459 {
460 }
461 
462 static void
pointer_axis_stop(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis)463 pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time,
464                   uint32_t axis)
465 {
466 }
467 
468 static void
pointer_axis_discrete(void * data,struct wl_pointer * wl_pointer,uint32_t time,int32_t discrete)469 pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t time,
470                       int32_t discrete)
471 {
472 }
473 
474 static const struct wl_pointer_listener pointer_listener = {
475     pointer_enter,
476     pointer_leave,
477     pointer_motion,
478     pointer_button,
479     pointer_axis,
480     pointer_frame,
481     pointer_axis_source,
482     pointer_axis_stop,
483     pointer_axis_discrete
484 };
485 
486 static void
seat_capabilities(void * data,struct wl_seat * wl_seat,uint32_t caps)487 seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t caps)
488 {
489     struct interactive_seat *seat = data;
490 
491     if (!seat->wl_kbd && (caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
492         seat->wl_kbd = wl_seat_get_keyboard(seat->wl_seat);
493         wl_keyboard_add_listener(seat->wl_kbd, &kbd_listener, seat);
494     }
495     else if (seat->wl_kbd && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
496         if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
497             wl_keyboard_release(seat->wl_kbd);
498         else
499             wl_keyboard_destroy(seat->wl_kbd);
500 
501         xkb_state_unref(seat->state);
502         xkb_keymap_unref(seat->keymap);
503 
504         seat->state = NULL;
505         seat->keymap = NULL;
506         seat->wl_kbd = NULL;
507     }
508 
509     if (!seat->wl_pointer && (caps & WL_SEAT_CAPABILITY_POINTER)) {
510         seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat);
511         wl_pointer_add_listener(seat->wl_pointer, &pointer_listener,
512                                 seat);
513     }
514     else if (seat->wl_pointer && !(caps & WL_SEAT_CAPABILITY_POINTER)) {
515         if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
516             wl_pointer_release(seat->wl_pointer);
517         else
518             wl_pointer_destroy(seat->wl_pointer);
519         seat->wl_pointer = NULL;
520     }
521 }
522 
523 static void
seat_name(void * data,struct wl_seat * wl_seat,const char * name)524 seat_name(void *data, struct wl_seat *wl_seat, const char *name)
525 {
526     struct interactive_seat *seat = data;
527 
528     free(seat->name_str);
529     seat->name_str = strdup(name);
530 }
531 
532 static const struct wl_seat_listener seat_listener = {
533     seat_capabilities,
534     seat_name
535 };
536 
537 static void
seat_create(struct interactive_dpy * inter,struct wl_registry * registry,uint32_t name,uint32_t version)538 seat_create(struct interactive_dpy *inter, struct wl_registry *registry,
539             uint32_t name, uint32_t version)
540 {
541     int ret;
542     struct interactive_seat *seat = calloc(1, sizeof(*seat));
543 
544     seat->global_name = name;
545     seat->inter = inter;
546     seat->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface,
547                                      MAX(version, 5));
548     wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
549     ret = asprintf(&seat->name_str, "seat:%d",
550                    wl_proxy_get_id((struct wl_proxy *) seat->wl_seat));
551     assert(ret >= 0);
552     wl_list_insert(&inter->seats, &seat->link);
553 }
554 
555 static void
seat_destroy(struct interactive_seat * seat)556 seat_destroy(struct interactive_seat *seat)
557 {
558     if (seat->wl_kbd) {
559         if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
560             wl_keyboard_release(seat->wl_kbd);
561         else
562             wl_keyboard_destroy(seat->wl_kbd);
563 
564         xkb_state_unref(seat->state);
565         xkb_keymap_unref(seat->keymap);
566     }
567 
568     if (seat->wl_pointer) {
569         if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
570             wl_pointer_release(seat->wl_pointer);
571         else
572             wl_pointer_destroy(seat->wl_pointer);
573     }
574 
575     if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
576         wl_seat_release(seat->wl_seat);
577     else
578         wl_seat_destroy(seat->wl_seat);
579 
580     free(seat->name_str);
581     wl_list_remove(&seat->link);
582     free(seat);
583 }
584 
585 static void
registry_global(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version)586 registry_global(void *data, struct wl_registry *registry, uint32_t name,
587                 const char *interface, uint32_t version)
588 {
589     struct interactive_dpy *inter = data;
590 
591     if (strcmp(interface, "wl_seat") == 0) {
592         seat_create(inter, registry, name, version);
593     }
594     else if (strcmp(interface, "xdg_wm_base") == 0) {
595         inter->shell = wl_registry_bind(registry, name,
596                                         &xdg_wm_base_interface,
597                                         MAX(version, 2));
598         xdg_wm_base_add_listener(inter->shell, &shell_listener, inter);
599     }
600     else if (strcmp(interface, "wl_compositor") == 0) {
601         inter->compositor = wl_registry_bind(registry, name,
602                                              &wl_compositor_interface,
603                                              MAX(version, 1));
604     }
605     else if (strcmp(interface, "wl_shm") == 0) {
606         inter->shm = wl_registry_bind(registry, name, &wl_shm_interface,
607                                       MAX(version, 1));
608     }
609 }
610 
611 static void
registry_delete(void * data,struct wl_registry * registry,uint32_t name)612 registry_delete(void *data, struct wl_registry *registry, uint32_t name)
613 {
614     struct interactive_dpy *inter = data;
615     struct interactive_seat *seat, *tmp;
616 
617     wl_list_for_each_safe(seat, tmp, &inter->seats, link) {
618         if (seat->global_name != name)
619             continue;
620 
621         seat_destroy(seat);
622     }
623 }
624 
625 static const struct wl_registry_listener registry_listener = {
626     registry_global,
627     registry_delete
628 };
629 
630 static void
dpy_disconnect(struct interactive_dpy * inter)631 dpy_disconnect(struct interactive_dpy *inter)
632 {
633     struct interactive_seat *seat, *tmp;
634 
635     wl_list_for_each_safe(seat, tmp, &inter->seats, link)
636         seat_destroy(seat);
637 
638     if (inter->xdg_surf)
639         xdg_surface_destroy(inter->xdg_surf);
640     if (inter->xdg_top)
641         xdg_toplevel_destroy(inter->xdg_top);
642     if (inter->wl_surf)
643         wl_surface_destroy(inter->wl_surf);
644     if (inter->shell)
645         xdg_wm_base_destroy(inter->shell);
646     if (inter->compositor)
647         wl_compositor_destroy(inter->compositor);
648     if (inter->shm)
649         wl_shm_destroy(inter->shm);
650 
651     /* Do one last roundtrip to try to destroy our wl_buffer. */
652     wl_display_roundtrip(inter->dpy);
653 
654     xkb_context_unref(inter->ctx);
655     wl_display_disconnect(inter->dpy);
656 }
657 
658 int
main(int argc,char * argv[])659 main(int argc, char *argv[])
660 {
661     int ret;
662     struct interactive_dpy inter;
663     struct wl_registry *registry;
664 
665     if (argc != 1) {
666         ret = strcmp(argv[1], "--help");
667         fprintf(ret ? stderr : stdout, "Usage: %s [--help]\n", argv[0]);
668         if (ret)
669             fprintf(stderr, "unrecognized option: %s\n", argv[1]);
670         return ret ? EXIT_INVALID_USAGE : EXIT_SUCCESS;
671     }
672 
673     setlocale(LC_ALL, "");
674 
675     memset(&inter, 0, sizeof(inter));
676     wl_list_init(&inter.seats);
677 
678     inter.dpy = wl_display_connect(NULL);
679     if (!inter.dpy) {
680         fprintf(stderr, "Couldn't connect to Wayland server\n");
681         ret = -1;
682         goto err_out;
683     }
684 
685     inter.ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
686     if (!inter.ctx) {
687         ret = -1;
688         fprintf(stderr, "Couldn't create xkb context\n");
689         goto err_out;
690     }
691 
692     registry = wl_display_get_registry(inter.dpy);
693     wl_registry_add_listener(registry, &registry_listener, &inter);
694 
695     /* The first roundtrip gets the list of advertised globals. */
696     wl_display_roundtrip(inter.dpy);
697 
698     /* The second roundtrip dispatches the events sent after binding, e.g.
699      * after binding to wl_seat globals in the first roundtrip, we will get
700      * the wl_seat::capabilities event in this roundtrip. */
701     wl_display_roundtrip(inter.dpy);
702 
703     if (!inter.shell || !inter.shm || !inter.compositor) {
704         fprintf(stderr, "Required Wayland interfaces %s%s%s unsupported\n",
705                 (inter.shell) ? "" : "xdg_shell ",
706                 (inter.shm) ? "" : "wl_shm",
707                 (inter.compositor) ? "" : "wl_compositor");
708         ret = -1;
709         goto err_conn;
710     }
711 
712     surface_create(&inter);
713 
714     tools_disable_stdin_echo();
715     do {
716         ret = wl_display_dispatch(inter.dpy);
717     } while (ret >= 0 && !terminate);
718     tools_enable_stdin_echo();
719 
720     wl_registry_destroy(registry);
721 err_conn:
722     dpy_disconnect(&inter);
723 err_out:
724     exit(ret >= 0 ? EXIT_SUCCESS : EXIT_FAILURE);
725 }
726