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