1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #include "../../SDL_internal.h"
23 
24 #if SDL_VIDEO_DRIVER_WAYLAND
25 
26 #include "SDL_stdinc.h"
27 #include "SDL_assert.h"
28 
29 #include "../../core/unix/SDL_poll.h"
30 #include "../../events/SDL_sysevents.h"
31 #include "../../events/SDL_events_c.h"
32 #include "../../events/scancodes_xfree86.h"
33 
34 #include "SDL_waylandvideo.h"
35 #include "SDL_waylandevents_c.h"
36 #include "SDL_waylandwindow.h"
37 
38 #include "SDL_waylanddyn.h"
39 
40 #include "pointer-constraints-unstable-v1-client-protocol.h"
41 #include "relative-pointer-unstable-v1-client-protocol.h"
42 #include "xdg-shell-client-protocol.h"
43 #include "xdg-shell-unstable-v6-client-protocol.h"
44 
45 #ifdef SDL_INPUT_LINUXEV
46 #include <linux/input.h>
47 #else
48 #define BTN_LEFT    (0x110)
49 #define BTN_RIGHT   (0x111)
50 #define BTN_MIDDLE  (0x112)
51 #define BTN_SIDE    (0x113)
52 #define BTN_EXTRA   (0x114)
53 #endif
54 #include <sys/select.h>
55 #include <sys/mman.h>
56 #include <poll.h>
57 #include <unistd.h>
58 #include <xkbcommon/xkbcommon.h>
59 
60 struct SDL_WaylandInput {
61     SDL_VideoData *display;
62     struct wl_seat *seat;
63     struct wl_pointer *pointer;
64     struct wl_touch *touch;
65     struct wl_keyboard *keyboard;
66     SDL_WaylandDataDevice *data_device;
67     struct zwp_relative_pointer_v1 *relative_pointer;
68     struct zwp_confined_pointer_v1 *confined_pointer;
69     SDL_WindowData *pointer_focus;
70     SDL_WindowData *keyboard_focus;
71 
72     /* Last motion location */
73     wl_fixed_t sx_w;
74     wl_fixed_t sy_w;
75 
76     double dx_frac;
77     double dy_frac;
78 
79     struct {
80         struct xkb_keymap *keymap;
81         struct xkb_state *state;
82     } xkb;
83 
84     /* information about axis events on current frame */
85     struct {
86         SDL_bool is_x_discrete;
87         float x;
88 
89         SDL_bool is_y_discrete;
90         float y;
91     } pointer_curr_axis_info;
92 };
93 
94 struct SDL_WaylandTouchPoint {
95     SDL_TouchID id;
96     float x;
97     float y;
98     struct wl_surface* surface;
99 
100     struct SDL_WaylandTouchPoint* prev;
101     struct SDL_WaylandTouchPoint* next;
102 };
103 
104 struct SDL_WaylandTouchPointList {
105     struct SDL_WaylandTouchPoint* head;
106     struct SDL_WaylandTouchPoint* tail;
107 };
108 
109 static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
110 
111 static void
touch_add(SDL_TouchID id,float x,float y,struct wl_surface * surface)112 touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
113 {
114     struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
115 
116     tp->id = id;
117     tp->x = x;
118     tp->y = y;
119     tp->surface = surface;
120 
121     if (touch_points.tail) {
122         touch_points.tail->next = tp;
123         tp->prev = touch_points.tail;
124     } else {
125         touch_points.head = tp;
126         tp->prev = NULL;
127     }
128 
129     touch_points.tail = tp;
130     tp->next = NULL;
131 }
132 
133 static void
touch_update(SDL_TouchID id,float x,float y)134 touch_update(SDL_TouchID id, float x, float y)
135 {
136     struct SDL_WaylandTouchPoint* tp = touch_points.head;
137 
138     while (tp) {
139         if (tp->id == id) {
140             tp->x = x;
141             tp->y = y;
142         }
143 
144         tp = tp->next;
145     }
146 }
147 
148 static void
touch_del(SDL_TouchID id,float * x,float * y,struct wl_surface ** surface)149 touch_del(SDL_TouchID id, float* x, float* y, struct wl_surface **surface)
150 {
151     struct SDL_WaylandTouchPoint* tp = touch_points.head;
152 
153     while (tp) {
154         if (tp->id == id) {
155             *x = tp->x;
156             *y = tp->y;
157             *surface = tp->surface;
158 
159             if (tp->prev) {
160                 tp->prev->next = tp->next;
161             } else {
162                 touch_points.head = tp->next;
163             }
164 
165             if (tp->next) {
166                 tp->next->prev = tp->prev;
167             } else {
168                 touch_points.tail = tp->prev;
169             }
170 
171             {
172                 struct SDL_WaylandTouchPoint *next = tp->next;
173                 SDL_free(tp);
174                 tp = next;
175             }
176         } else {
177             tp = tp->next;
178         }
179     }
180 }
181 
182 static struct wl_surface*
touch_surface(SDL_TouchID id)183 touch_surface(SDL_TouchID id)
184 {
185     struct SDL_WaylandTouchPoint* tp = touch_points.head;
186 
187     while (tp) {
188         if (tp->id == id) {
189             return tp->surface;
190         }
191 
192         tp = tp->next;
193     }
194 
195     return NULL;
196 }
197 
198 void
Wayland_PumpEvents(_THIS)199 Wayland_PumpEvents(_THIS)
200 {
201     SDL_VideoData *d = _this->driverdata;
202     int err;
203 
204     WAYLAND_wl_display_flush(d->display);
205 
206     if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
207         err = WAYLAND_wl_display_dispatch(d->display);
208     } else {
209         err = WAYLAND_wl_display_dispatch_pending(d->display);
210     }
211     if (err == -1 && !d->display_disconnected) {
212         /* Something has failed with the Wayland connection -- for example,
213          * the compositor may have shut down and closed its end of the socket,
214          * or there is a library-specific error. No recovery is possible. */
215         d->display_disconnected = 1;
216         /* Only send a single quit message, as application shutdown might call
217          * SDL_PumpEvents */
218         SDL_SendQuit();
219     }
220 }
221 
222 static void
pointer_handle_motion(void * data,struct wl_pointer * pointer,uint32_t time,wl_fixed_t sx_w,wl_fixed_t sy_w)223 pointer_handle_motion(void *data, struct wl_pointer *pointer,
224                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
225 {
226     struct SDL_WaylandInput *input = data;
227     SDL_WindowData *window = input->pointer_focus;
228     input->sx_w = sx_w;
229     input->sy_w = sy_w;
230     if (input->pointer_focus) {
231         const int sx = wl_fixed_to_int(sx_w);
232         const int sy = wl_fixed_to_int(sy_w);
233         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
234     }
235 }
236 
237 static void
pointer_handle_enter(void * data,struct wl_pointer * pointer,uint32_t serial,struct wl_surface * surface,wl_fixed_t sx_w,wl_fixed_t sy_w)238 pointer_handle_enter(void *data, struct wl_pointer *pointer,
239                      uint32_t serial, struct wl_surface *surface,
240                      wl_fixed_t sx_w, wl_fixed_t sy_w)
241 {
242     struct SDL_WaylandInput *input = data;
243     SDL_WindowData *window;
244 
245     if (!surface) {
246         /* enter event for a window we've just destroyed */
247         return;
248     }
249 
250     /* This handler will be called twice in Wayland 1.4
251      * Once for the window surface which has valid user data
252      * and again for the mouse cursor surface which does not have valid user data
253      * We ignore the later
254      */
255 
256     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
257 
258     if (window) {
259         input->pointer_focus = window;
260         SDL_SetMouseFocus(window->sdlwindow);
261         /* In the case of e.g. a pointer confine warp, we may receive an enter
262          * event with no following motion event, but with the new coordinates
263          * as part of the enter event. */
264         pointer_handle_motion(data, pointer, serial, sx_w, sy_w);
265     }
266 }
267 
268 static void
pointer_handle_leave(void * data,struct wl_pointer * pointer,uint32_t serial,struct wl_surface * surface)269 pointer_handle_leave(void *data, struct wl_pointer *pointer,
270                      uint32_t serial, struct wl_surface *surface)
271 {
272     struct SDL_WaylandInput *input = data;
273 
274     if (input->pointer_focus) {
275         SDL_SetMouseFocus(NULL);
276         input->pointer_focus = NULL;
277     }
278 }
279 
280 static SDL_bool
ProcessHitTest(struct SDL_WaylandInput * input,uint32_t serial)281 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
282 {
283     SDL_WindowData *window_data = input->pointer_focus;
284     SDL_Window *window = window_data->sdlwindow;
285 
286     if (window->hit_test) {
287         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
288         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
289 
290         static const uint32_t directions_wl[] = {
291             WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
292             WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
293             WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
294             WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
295         };
296 
297         /* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs
298            WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */
299         const uint32_t *directions_zxdg = directions_wl;
300 
301         switch (rc) {
302             case SDL_HITTEST_DRAGGABLE:
303                 if (input->display->shell.xdg) {
304                     xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial);
305                 } else if (input->display->shell.zxdg) {
306                     zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial);
307                 } else {
308                     wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial);
309                 }
310                 return SDL_TRUE;
311 
312             case SDL_HITTEST_RESIZE_TOPLEFT:
313             case SDL_HITTEST_RESIZE_TOP:
314             case SDL_HITTEST_RESIZE_TOPRIGHT:
315             case SDL_HITTEST_RESIZE_RIGHT:
316             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
317             case SDL_HITTEST_RESIZE_BOTTOM:
318             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
319             case SDL_HITTEST_RESIZE_LEFT:
320                 if (input->display->shell.xdg) {
321                     xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
322                 } else if (input->display->shell.zxdg) {
323                     zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
324                 } else {
325                     wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
326                 }
327                 return SDL_TRUE;
328 
329             default: return SDL_FALSE;
330         }
331     }
332 
333     return SDL_FALSE;
334 }
335 
336 static void
pointer_handle_button_common(struct SDL_WaylandInput * input,uint32_t serial,uint32_t time,uint32_t button,uint32_t state_w)337 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
338                              uint32_t time, uint32_t button, uint32_t state_w)
339 {
340     SDL_WindowData *window = input->pointer_focus;
341     enum wl_pointer_button_state state = state_w;
342     uint32_t sdl_button;
343 
344     if  (input->pointer_focus) {
345         switch (button) {
346             case BTN_LEFT:
347                 sdl_button = SDL_BUTTON_LEFT;
348                 if (ProcessHitTest(input, serial)) {
349                     return;  /* don't pass this event on to app. */
350                 }
351                 break;
352             case BTN_MIDDLE:
353                 sdl_button = SDL_BUTTON_MIDDLE;
354                 break;
355             case BTN_RIGHT:
356                 sdl_button = SDL_BUTTON_RIGHT;
357                 break;
358             case BTN_SIDE:
359                 sdl_button = SDL_BUTTON_X1;
360                 break;
361             case BTN_EXTRA:
362                 sdl_button = SDL_BUTTON_X2;
363                 break;
364             default:
365                 return;
366         }
367 
368         Wayland_data_device_set_serial(input->data_device, serial);
369 
370         SDL_SendMouseButton(window->sdlwindow, 0,
371                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
372     }
373 }
374 
375 static void
pointer_handle_button(void * data,struct wl_pointer * pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state_w)376 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
377                       uint32_t time, uint32_t button, uint32_t state_w)
378 {
379     struct SDL_WaylandInput *input = data;
380 
381     pointer_handle_button_common(input, serial, time, button, state_w);
382 }
383 
384 static void
pointer_handle_axis_common_v1(struct SDL_WaylandInput * input,uint32_t time,uint32_t axis,wl_fixed_t value)385 pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
386                               uint32_t time, uint32_t axis, wl_fixed_t value)
387 {
388     SDL_WindowData *window = input->pointer_focus;
389     enum wl_pointer_axis a = axis;
390     float x, y;
391 
392     if (input->pointer_focus) {
393         switch (a) {
394             case WL_POINTER_AXIS_VERTICAL_SCROLL:
395                 x = 0;
396                 y = 0 - (float)wl_fixed_to_double(value);
397                 break;
398             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
399                 x = 0 - (float)wl_fixed_to_double(value);
400                 y = 0;
401                 break;
402             default:
403                 return;
404         }
405 
406         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
407     }
408 }
409 
410 static void
pointer_handle_axis_common(struct SDL_WaylandInput * input,SDL_bool discrete,uint32_t axis,wl_fixed_t value)411 pointer_handle_axis_common(struct SDL_WaylandInput *input, SDL_bool discrete,
412                            uint32_t axis, wl_fixed_t value)
413 {
414     enum wl_pointer_axis a = axis;
415 
416     if (input->pointer_focus) {
417         switch (a) {
418             case WL_POINTER_AXIS_VERTICAL_SCROLL:
419                 if (discrete) {
420                     /* this is a discrete axis event so we process it and flag
421                      * to ignore future continuous axis events in this frame */
422                     input->pointer_curr_axis_info.is_y_discrete = SDL_TRUE;
423                 } else if(input->pointer_curr_axis_info.is_y_discrete) {
424                     /* this is a continuous axis event and we have already
425                      * processed a discrete axis event before so we ignore it */
426                     break;
427                 }
428                 input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
429                 break;
430             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
431                 if (discrete) {
432                     /* this is a discrete axis event so we process it and flag
433                      * to ignore future continuous axis events in this frame */
434                     input->pointer_curr_axis_info.is_x_discrete = SDL_TRUE;
435                 } else if(input->pointer_curr_axis_info.is_x_discrete) {
436                     /* this is a continuous axis event and we have already
437                      * processed a discrete axis event before so we ignore it */
438                     break;
439                 }
440                 input->pointer_curr_axis_info.x = 0 - (float)wl_fixed_to_double(value);
441                 break;
442         }
443     }
444 }
445 
446 static void
pointer_handle_axis(void * data,struct wl_pointer * pointer,uint32_t time,uint32_t axis,wl_fixed_t value)447 pointer_handle_axis(void *data, struct wl_pointer *pointer,
448                     uint32_t time, uint32_t axis, wl_fixed_t value)
449 {
450     struct SDL_WaylandInput *input = data;
451 
452     if(wl_seat_get_version(input->seat) >= 5)
453         pointer_handle_axis_common(input, SDL_FALSE, axis, value);
454     else
455         pointer_handle_axis_common_v1(input, time, axis, value);
456 }
457 
458 static void
pointer_handle_frame(void * data,struct wl_pointer * pointer)459 pointer_handle_frame(void *data, struct wl_pointer *pointer)
460 {
461     struct SDL_WaylandInput *input = data;
462     SDL_WindowData *window = input->pointer_focus;
463     float x = input->pointer_curr_axis_info.x, y = input->pointer_curr_axis_info.y;
464 
465     /* clear pointer_curr_axis_info for next frame */
466     memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
467 
468     if(x == 0.0f && y == 0.0f)
469         return;
470     else
471         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
472 }
473 
474 static void
pointer_handle_axis_source(void * data,struct wl_pointer * pointer,uint32_t axis_source)475 pointer_handle_axis_source(void *data, struct wl_pointer *pointer,
476                            uint32_t axis_source)
477 {
478     /* unimplemented */
479 }
480 
481 static void
pointer_handle_axis_stop(void * data,struct wl_pointer * pointer,uint32_t time,uint32_t axis)482 pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
483                          uint32_t time, uint32_t axis)
484 {
485     /* unimplemented */
486 }
487 
488 static void
pointer_handle_axis_discrete(void * data,struct wl_pointer * pointer,uint32_t axis,int32_t discrete)489 pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
490                              uint32_t axis, int32_t discrete)
491 {
492     struct SDL_WaylandInput *input = data;
493 
494     pointer_handle_axis_common(input, SDL_TRUE, axis, wl_fixed_from_int(discrete));
495 }
496 
497 
498 static const struct wl_pointer_listener pointer_listener = {
499     pointer_handle_enter,
500     pointer_handle_leave,
501     pointer_handle_motion,
502     pointer_handle_button,
503     pointer_handle_axis,
504     pointer_handle_frame,           // Version 5
505     pointer_handle_axis_source,     // Version 5
506     pointer_handle_axis_stop,       // Version 5
507     pointer_handle_axis_discrete,   // Version 5
508 };
509 
510 static void
touch_handler_down(void * data,struct wl_touch * touch,unsigned int serial,unsigned int timestamp,struct wl_surface * surface,int id,wl_fixed_t fx,wl_fixed_t fy)511 touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
512                    unsigned int timestamp, struct wl_surface *surface,
513                    int id, wl_fixed_t fx, wl_fixed_t fy)
514 {
515     SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
516     const double dblx = wl_fixed_to_double(fx);
517     const double dbly = wl_fixed_to_double(fy);
518     const float x = dblx / window_data->sdlwindow->w;
519     const float y = dbly / window_data->sdlwindow->h;
520 
521     touch_add(id, x, y, surface);
522 
523     SDL_SendTouch(1, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f);
524 }
525 
526 static void
touch_handler_up(void * data,struct wl_touch * touch,unsigned int serial,unsigned int timestamp,int id)527 touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
528                  unsigned int timestamp, int id)
529 {
530     float x = 0, y = 0;
531     struct wl_surface *surface = NULL;
532     SDL_Window *window = NULL;
533 
534     touch_del(id, &x, &y, &surface);
535 
536     if (surface) {
537         SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
538         window = window_data->sdlwindow;
539     }
540 
541     SDL_SendTouch(1, (SDL_FingerID)id, window, SDL_FALSE, x, y, 0.0f);
542 }
543 
544 static void
touch_handler_motion(void * data,struct wl_touch * touch,unsigned int timestamp,int id,wl_fixed_t fx,wl_fixed_t fy)545 touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
546                      int id, wl_fixed_t fx, wl_fixed_t fy)
547 {
548     SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
549     const double dblx = wl_fixed_to_double(fx);
550     const double dbly = wl_fixed_to_double(fy);
551     const float x = dblx / window_data->sdlwindow->w;
552     const float y = dbly / window_data->sdlwindow->h;
553 
554     touch_update(id, x, y);
555     SDL_SendTouchMotion(1, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f);
556 }
557 
558 static void
touch_handler_frame(void * data,struct wl_touch * touch)559 touch_handler_frame(void *data, struct wl_touch *touch)
560 {
561 
562 }
563 
564 static void
touch_handler_cancel(void * data,struct wl_touch * touch)565 touch_handler_cancel(void *data, struct wl_touch *touch)
566 {
567 
568 }
569 
570 static const struct wl_touch_listener touch_listener = {
571     touch_handler_down,
572     touch_handler_up,
573     touch_handler_motion,
574     touch_handler_frame,
575     touch_handler_cancel,
576     NULL, /* shape */
577     NULL, /* orientation */
578 };
579 
580 static void
keyboard_handle_keymap(void * data,struct wl_keyboard * keyboard,uint32_t format,int fd,uint32_t size)581 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
582                        uint32_t format, int fd, uint32_t size)
583 {
584     struct SDL_WaylandInput *input = data;
585     char *map_str;
586 
587     if (!data) {
588         close(fd);
589         return;
590     }
591 
592     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
593         close(fd);
594         return;
595     }
596 
597     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
598     if (map_str == MAP_FAILED) {
599         close(fd);
600         return;
601     }
602 
603     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
604                                                 map_str,
605                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
606                                                 0);
607     munmap(map_str, size);
608     close(fd);
609 
610     if (!input->xkb.keymap) {
611         fprintf(stderr, "failed to compile keymap\n");
612         return;
613     }
614 
615     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
616     if (!input->xkb.state) {
617         fprintf(stderr, "failed to create XKB state\n");
618         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
619         input->xkb.keymap = NULL;
620         return;
621     }
622 }
623 
624 static void
keyboard_handle_enter(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)625 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
626                       uint32_t serial, struct wl_surface *surface,
627                       struct wl_array *keys)
628 {
629     struct SDL_WaylandInput *input = data;
630     SDL_WindowData *window;
631 
632     if (!surface) {
633         /* enter event for a window we've just destroyed */
634         return;
635     }
636 
637     window = wl_surface_get_user_data(surface);
638 
639     if (window) {
640         input->keyboard_focus = window;
641         window->keyboard_device = input;
642         SDL_SetKeyboardFocus(window->sdlwindow);
643     }
644 }
645 
646 static void
keyboard_handle_leave(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface)647 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
648                       uint32_t serial, struct wl_surface *surface)
649 {
650     SDL_SetKeyboardFocus(NULL);
651 }
652 
653 static void
keyboard_handle_key(void * data,struct wl_keyboard * keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state_w)654 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
655                     uint32_t serial, uint32_t time, uint32_t key,
656                     uint32_t state_w)
657 {
658     struct SDL_WaylandInput *input = data;
659     SDL_WindowData *window = input->keyboard_focus;
660     enum wl_keyboard_key_state state = state_w;
661     const xkb_keysym_t *syms;
662     uint32_t scancode;
663     char text[8];
664     int size;
665 
666     if (key < SDL_arraysize(xfree86_scancode_table2)) {
667         scancode = xfree86_scancode_table2[key];
668 
669         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
670         if (scancode != SDL_SCANCODE_UNKNOWN)
671             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
672                                 SDL_PRESSED : SDL_RELEASED, scancode);
673     }
674 
675     if (!window || window->keyboard_device != input || !input->xkb.state)
676         return;
677 
678     // TODO can this happen?
679     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
680         return;
681 
682     if (state) {
683         size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
684 
685         if (size > 0) {
686             text[size] = 0;
687 
688             Wayland_data_device_set_serial(input->data_device, serial);
689 
690             SDL_SendKeyboardText(text);
691         }
692     }
693 }
694 
695 static void
keyboard_handle_modifiers(void * data,struct wl_keyboard * keyboard,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)696 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
697                           uint32_t serial, uint32_t mods_depressed,
698                           uint32_t mods_latched, uint32_t mods_locked,
699                           uint32_t group)
700 {
701     struct SDL_WaylandInput *input = data;
702 
703     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
704                           mods_locked, 0, 0, group);
705 }
706 
707 static void
keyboard_handle_repeat_info(void * data,struct wl_keyboard * wl_keyboard,int32_t rate,int32_t delay)708 keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
709                             int32_t rate, int32_t delay)
710 {
711     /* unimplemented */
712 }
713 
714 static const struct wl_keyboard_listener keyboard_listener = {
715     keyboard_handle_keymap,
716     keyboard_handle_enter,
717     keyboard_handle_leave,
718     keyboard_handle_key,
719     keyboard_handle_modifiers,
720     keyboard_handle_repeat_info,    // Version 4
721 };
722 
723 static void
seat_handle_capabilities(void * data,struct wl_seat * seat,enum wl_seat_capability caps)724 seat_handle_capabilities(void *data, struct wl_seat *seat,
725                          enum wl_seat_capability caps)
726 {
727     struct SDL_WaylandInput *input = data;
728 
729     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
730         input->pointer = wl_seat_get_pointer(seat);
731         memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
732         input->display->pointer = input->pointer;
733         wl_pointer_set_user_data(input->pointer, input);
734         wl_pointer_add_listener(input->pointer, &pointer_listener,
735                                 input);
736     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
737         wl_pointer_destroy(input->pointer);
738         input->pointer = NULL;
739         input->display->pointer = NULL;
740     }
741 
742     if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
743         SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
744         input->touch = wl_seat_get_touch(seat);
745         wl_touch_set_user_data(input->touch, input);
746         wl_touch_add_listener(input->touch, &touch_listener,
747                                  input);
748     } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
749         SDL_DelTouch(1);
750         wl_touch_destroy(input->touch);
751         input->touch = NULL;
752     }
753 
754     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
755         input->keyboard = wl_seat_get_keyboard(seat);
756         wl_keyboard_set_user_data(input->keyboard, input);
757         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
758                                  input);
759     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
760         wl_keyboard_destroy(input->keyboard);
761         input->keyboard = NULL;
762     }
763 }
764 
765 static void
seat_handle_name(void * data,struct wl_seat * wl_seat,const char * name)766 seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
767 {
768     /* unimplemented */
769 }
770 
771 static const struct wl_seat_listener seat_listener = {
772     seat_handle_capabilities,
773     seat_handle_name,           // Version 2
774 };
775 
776 static void
data_source_handle_target(void * data,struct wl_data_source * wl_data_source,const char * mime_type)777 data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
778                           const char *mime_type)
779 {
780 }
781 
782 static void
data_source_handle_send(void * data,struct wl_data_source * wl_data_source,const char * mime_type,int32_t fd)783 data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
784                         const char *mime_type, int32_t fd)
785 {
786     Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
787 }
788 
789 static void
data_source_handle_cancelled(void * data,struct wl_data_source * wl_data_source)790 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
791 {
792     Wayland_data_source_destroy(data);
793 }
794 
795 static void
data_source_handle_dnd_drop_performed(void * data,struct wl_data_source * wl_data_source)796 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
797 {
798 }
799 
800 static void
data_source_handle_dnd_finished(void * data,struct wl_data_source * wl_data_source)801 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
802 {
803 }
804 
805 static void
data_source_handle_action(void * data,struct wl_data_source * wl_data_source,uint32_t dnd_action)806 data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
807                           uint32_t dnd_action)
808 {
809 }
810 
811 static const struct wl_data_source_listener data_source_listener = {
812     data_source_handle_target,
813     data_source_handle_send,
814     data_source_handle_cancelled,
815     data_source_handle_dnd_drop_performed, // Version 3
816     data_source_handle_dnd_finished,       // Version 3
817     data_source_handle_action,             // Version 3
818 };
819 
820 SDL_WaylandDataSource*
Wayland_data_source_create(_THIS)821 Wayland_data_source_create(_THIS)
822 {
823     SDL_WaylandDataSource *data_source = NULL;
824     SDL_VideoData *driver_data = NULL;
825     struct wl_data_source *id = NULL;
826 
827     if (_this == NULL || _this->driverdata == NULL) {
828         SDL_SetError("Video driver uninitialized");
829     } else {
830         driver_data = _this->driverdata;
831 
832         if (driver_data->data_device_manager != NULL) {
833             id = wl_data_device_manager_create_data_source(
834                      driver_data->data_device_manager);
835         }
836 
837         if (id == NULL) {
838             SDL_SetError("Wayland unable to create data source");
839         } else {
840             data_source = SDL_calloc(1, sizeof *data_source);
841             if (data_source == NULL) {
842                 SDL_OutOfMemory();
843                 wl_data_source_destroy(id);
844             } else {
845                 WAYLAND_wl_list_init(&(data_source->mimes));
846                 data_source->source = id;
847                 wl_data_source_set_user_data(id, data_source);
848                 wl_data_source_add_listener(id, &data_source_listener,
849                                             data_source);
850             }
851         }
852     }
853     return data_source;
854 }
855 
856 static void
data_offer_handle_offer(void * data,struct wl_data_offer * wl_data_offer,const char * mime_type)857 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
858                         const char *mime_type)
859 {
860     SDL_WaylandDataOffer *offer = data;
861     Wayland_data_offer_add_mime(offer, mime_type);
862 }
863 
864 static void
data_offer_handle_source_actions(void * data,struct wl_data_offer * wl_data_offer,uint32_t source_actions)865 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
866                                  uint32_t source_actions)
867 {
868 }
869 
870 static void
data_offer_handle_actions(void * data,struct wl_data_offer * wl_data_offer,uint32_t dnd_action)871 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
872                           uint32_t dnd_action)
873 {
874 }
875 
876 static const struct wl_data_offer_listener data_offer_listener = {
877     data_offer_handle_offer,
878     data_offer_handle_source_actions, // Version 3
879     data_offer_handle_actions,        // Version 3
880 };
881 
882 static void
data_device_handle_data_offer(void * data,struct wl_data_device * wl_data_device,struct wl_data_offer * id)883 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
884                               struct wl_data_offer *id)
885 {
886     SDL_WaylandDataOffer *data_offer = NULL;
887 
888     data_offer = SDL_calloc(1, sizeof *data_offer);
889     if (data_offer == NULL) {
890         SDL_OutOfMemory();
891     } else {
892         data_offer->offer = id;
893         data_offer->data_device = data;
894         WAYLAND_wl_list_init(&(data_offer->mimes));
895         wl_data_offer_set_user_data(id, data_offer);
896         wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
897     }
898 }
899 
900 static void
data_device_handle_enter(void * data,struct wl_data_device * wl_data_device,uint32_t serial,struct wl_surface * surface,wl_fixed_t x,wl_fixed_t y,struct wl_data_offer * id)901 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
902                          uint32_t serial, struct wl_surface *surface,
903                          wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
904 {
905     SDL_WaylandDataDevice *data_device = data;
906     SDL_bool has_mime = SDL_FALSE;
907     uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
908 
909     data_device->drag_serial = serial;
910 
911     if (id != NULL) {
912         data_device->drag_offer = wl_data_offer_get_user_data(id);
913 
914         /* TODO: SDL Support more mime types */
915         has_mime = Wayland_data_offer_has_mime(
916             data_device->drag_offer, FILE_MIME);
917 
918         /* If drag_mime is NULL this will decline the offer */
919         wl_data_offer_accept(id, serial,
920                              (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
921 
922         /* SDL only supports "copy" style drag and drop */
923         if (has_mime == SDL_TRUE) {
924             dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
925         }
926         if (wl_data_offer_get_version(data_device->drag_offer->offer) >= 3) {
927             wl_data_offer_set_actions(data_device->drag_offer->offer,
928                                       dnd_action, dnd_action);
929         }
930     }
931 }
932 
933 static void
data_device_handle_leave(void * data,struct wl_data_device * wl_data_device)934 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
935 {
936     SDL_WaylandDataDevice *data_device = data;
937     SDL_WaylandDataOffer *offer = NULL;
938 
939     if (data_device->selection_offer != NULL) {
940         data_device->selection_offer = NULL;
941         Wayland_data_offer_destroy(offer);
942     }
943 }
944 
945 static void
data_device_handle_motion(void * data,struct wl_data_device * wl_data_device,uint32_t time,wl_fixed_t x,wl_fixed_t y)946 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
947                           uint32_t time, wl_fixed_t x, wl_fixed_t y)
948 {
949 }
950 
951 static void
data_device_handle_drop(void * data,struct wl_data_device * wl_data_device)952 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
953 {
954     SDL_WaylandDataDevice *data_device = data;
955     void *buffer = NULL;
956     size_t length = 0;
957 
958     const char *current_uri = NULL;
959     const char *last_char = NULL;
960     char *current_char = NULL;
961 
962     if (data_device->drag_offer != NULL) {
963         /* TODO: SDL Support more mime types */
964         buffer = Wayland_data_offer_receive(data_device->drag_offer,
965                                             &length, FILE_MIME, SDL_FALSE);
966 
967         /* uri-list */
968         current_uri = (const char *)buffer;
969         last_char = (const char *)buffer + length;
970         for (current_char = buffer; current_char < last_char; ++current_char) {
971             if (*current_char == '\n' || *current_char == 0) {
972                 if (*current_uri != 0 && *current_uri != '#') {
973                     *current_char = 0;
974                     SDL_SendDropFile(NULL, current_uri);
975                 }
976                 current_uri = (const char *)current_char + 1;
977             }
978         }
979 
980         SDL_free(buffer);
981     }
982 }
983 
984 static void
data_device_handle_selection(void * data,struct wl_data_device * wl_data_device,struct wl_data_offer * id)985 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
986                              struct wl_data_offer *id)
987 {
988     SDL_WaylandDataDevice *data_device = data;
989     SDL_WaylandDataOffer *offer = NULL;
990 
991     if (id != NULL) {
992         offer = wl_data_offer_get_user_data(id);
993     }
994 
995     if (data_device->selection_offer != offer) {
996         Wayland_data_offer_destroy(data_device->selection_offer);
997         data_device->selection_offer = offer;
998     }
999 
1000     SDL_SendClipboardUpdate();
1001 }
1002 
1003 static const struct wl_data_device_listener data_device_listener = {
1004     data_device_handle_data_offer,
1005     data_device_handle_enter,
1006     data_device_handle_leave,
1007     data_device_handle_motion,
1008     data_device_handle_drop,
1009     data_device_handle_selection
1010 };
1011 
1012 void
Wayland_display_add_input(SDL_VideoData * d,uint32_t id,uint32_t version)1013 Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
1014 {
1015     struct SDL_WaylandInput *input;
1016     SDL_WaylandDataDevice *data_device = NULL;
1017 
1018     input = SDL_calloc(1, sizeof *input);
1019     if (input == NULL)
1020         return;
1021 
1022     input->display = d;
1023     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
1024     input->sx_w = wl_fixed_from_int(0);
1025     input->sy_w = wl_fixed_from_int(0);
1026     d->input = input;
1027 
1028     if (d->data_device_manager != NULL) {
1029         data_device = SDL_calloc(1, sizeof *data_device);
1030         if (data_device == NULL) {
1031             return;
1032         }
1033 
1034         data_device->data_device = wl_data_device_manager_get_data_device(
1035             d->data_device_manager, input->seat
1036         );
1037         data_device->video_data = d;
1038 
1039         if (data_device->data_device == NULL) {
1040             SDL_free(data_device);
1041         } else {
1042             wl_data_device_set_user_data(data_device->data_device, data_device);
1043             wl_data_device_add_listener(data_device->data_device,
1044                                         &data_device_listener, data_device);
1045             input->data_device = data_device;
1046         }
1047     }
1048 
1049     wl_seat_add_listener(input->seat, &seat_listener, input);
1050     wl_seat_set_user_data(input->seat, input);
1051 
1052     WAYLAND_wl_display_flush(d->display);
1053 }
1054 
Wayland_display_destroy_input(SDL_VideoData * d)1055 void Wayland_display_destroy_input(SDL_VideoData *d)
1056 {
1057     struct SDL_WaylandInput *input = d->input;
1058 
1059     if (!input)
1060         return;
1061 
1062     if (input->data_device != NULL) {
1063         Wayland_data_device_clear_selection(input->data_device);
1064         if (input->data_device->selection_offer != NULL) {
1065             Wayland_data_offer_destroy(input->data_device->selection_offer);
1066         }
1067         if (input->data_device->drag_offer != NULL) {
1068             Wayland_data_offer_destroy(input->data_device->drag_offer);
1069         }
1070         if (input->data_device->data_device != NULL) {
1071             wl_data_device_release(input->data_device->data_device);
1072         }
1073         SDL_free(input->data_device);
1074     }
1075 
1076     if (input->keyboard)
1077         wl_keyboard_destroy(input->keyboard);
1078 
1079     if (input->pointer)
1080         wl_pointer_destroy(input->pointer);
1081 
1082     if (input->touch) {
1083         SDL_DelTouch(1);
1084         wl_touch_destroy(input->touch);
1085     }
1086 
1087     if (input->seat)
1088         wl_seat_destroy(input->seat);
1089 
1090     if (input->xkb.state)
1091         WAYLAND_xkb_state_unref(input->xkb.state);
1092 
1093     if (input->xkb.keymap)
1094         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
1095 
1096     SDL_free(input);
1097     d->input = NULL;
1098 }
1099 
Wayland_get_data_device(struct SDL_WaylandInput * input)1100 SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
1101 {
1102     if (input == NULL) {
1103         return NULL;
1104     }
1105 
1106     return input->data_device;
1107 }
1108 
1109 /* !!! FIXME: just merge these into display_handle_global(). */
Wayland_display_add_relative_pointer_manager(SDL_VideoData * d,uint32_t id)1110 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
1111 {
1112     d->relative_pointer_manager =
1113         wl_registry_bind(d->registry, id,
1114                          &zwp_relative_pointer_manager_v1_interface, 1);
1115 }
1116 
Wayland_display_destroy_relative_pointer_manager(SDL_VideoData * d)1117 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
1118 {
1119     if (d->relative_pointer_manager)
1120         zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
1121 }
1122 
Wayland_display_add_pointer_constraints(SDL_VideoData * d,uint32_t id)1123 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
1124 {
1125     d->pointer_constraints =
1126         wl_registry_bind(d->registry, id,
1127                          &zwp_pointer_constraints_v1_interface, 1);
1128 }
1129 
Wayland_display_destroy_pointer_constraints(SDL_VideoData * d)1130 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
1131 {
1132     if (d->pointer_constraints)
1133         zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
1134 }
1135 
1136 static void
relative_pointer_handle_relative_motion(void * data,struct zwp_relative_pointer_v1 * pointer,uint32_t time_hi,uint32_t time_lo,wl_fixed_t dx_w,wl_fixed_t dy_w,wl_fixed_t dx_unaccel_w,wl_fixed_t dy_unaccel_w)1137 relative_pointer_handle_relative_motion(void *data,
1138                                         struct zwp_relative_pointer_v1 *pointer,
1139                                         uint32_t time_hi,
1140                                         uint32_t time_lo,
1141                                         wl_fixed_t dx_w,
1142                                         wl_fixed_t dy_w,
1143                                         wl_fixed_t dx_unaccel_w,
1144                                         wl_fixed_t dy_unaccel_w)
1145 {
1146     struct SDL_WaylandInput *input = data;
1147     SDL_VideoData *d = input->display;
1148     SDL_WindowData *window = input->pointer_focus;
1149     double dx_unaccel;
1150     double dy_unaccel;
1151     double dx;
1152     double dy;
1153 
1154     dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
1155     dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
1156 
1157     /* Add left over fraction from last event. */
1158     dx_unaccel += input->dx_frac;
1159     dy_unaccel += input->dy_frac;
1160 
1161     input->dx_frac = modf(dx_unaccel, &dx);
1162     input->dy_frac = modf(dy_unaccel, &dy);
1163 
1164     if (input->pointer_focus && d->relative_mouse_mode) {
1165         SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
1166     }
1167 }
1168 
1169 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
1170     relative_pointer_handle_relative_motion,
1171 };
1172 
1173 static void
locked_pointer_locked(void * data,struct zwp_locked_pointer_v1 * locked_pointer)1174 locked_pointer_locked(void *data,
1175                       struct zwp_locked_pointer_v1 *locked_pointer)
1176 {
1177 }
1178 
1179 static void
locked_pointer_unlocked(void * data,struct zwp_locked_pointer_v1 * locked_pointer)1180 locked_pointer_unlocked(void *data,
1181                         struct zwp_locked_pointer_v1 *locked_pointer)
1182 {
1183 }
1184 
1185 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
1186     locked_pointer_locked,
1187     locked_pointer_unlocked,
1188 };
1189 
1190 static void
lock_pointer_to_window(SDL_Window * window,struct SDL_WaylandInput * input)1191 lock_pointer_to_window(SDL_Window *window,
1192                        struct SDL_WaylandInput *input)
1193 {
1194     SDL_WindowData *w = window->driverdata;
1195     SDL_VideoData *d = input->display;
1196     struct zwp_locked_pointer_v1 *locked_pointer;
1197 
1198     if (w->locked_pointer)
1199         return;
1200 
1201     locked_pointer =
1202         zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
1203                                                 w->surface,
1204                                                 input->pointer,
1205                                                 NULL,
1206                                                 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1207     zwp_locked_pointer_v1_add_listener(locked_pointer,
1208                                        &locked_pointer_listener,
1209                                        window);
1210 
1211     w->locked_pointer = locked_pointer;
1212 }
1213 
Wayland_input_lock_pointer(struct SDL_WaylandInput * input)1214 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
1215 {
1216     SDL_VideoDevice *vd = SDL_GetVideoDevice();
1217     SDL_VideoData *d = input->display;
1218     SDL_Window *window;
1219     struct zwp_relative_pointer_v1 *relative_pointer;
1220 
1221     if (!d->relative_pointer_manager)
1222         return -1;
1223 
1224     if (!d->pointer_constraints)
1225         return -1;
1226 
1227     if (!input->pointer)
1228         return -1;
1229 
1230     if (!input->relative_pointer) {
1231         relative_pointer =
1232             zwp_relative_pointer_manager_v1_get_relative_pointer(
1233                 d->relative_pointer_manager,
1234                 input->pointer);
1235         zwp_relative_pointer_v1_add_listener(relative_pointer,
1236                                              &relative_pointer_listener,
1237                                              input);
1238         input->relative_pointer = relative_pointer;
1239     }
1240 
1241     for (window = vd->windows; window; window = window->next)
1242         lock_pointer_to_window(window, input);
1243 
1244     d->relative_mouse_mode = 1;
1245 
1246     return 0;
1247 }
1248 
Wayland_input_unlock_pointer(struct SDL_WaylandInput * input)1249 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
1250 {
1251     SDL_VideoDevice *vd = SDL_GetVideoDevice();
1252     SDL_VideoData *d = input->display;
1253     SDL_Window *window;
1254     SDL_WindowData *w;
1255 
1256     for (window = vd->windows; window; window = window->next) {
1257         w = window->driverdata;
1258         if (w->locked_pointer)
1259             zwp_locked_pointer_v1_destroy(w->locked_pointer);
1260         w->locked_pointer = NULL;
1261     }
1262 
1263     zwp_relative_pointer_v1_destroy(input->relative_pointer);
1264     input->relative_pointer = NULL;
1265 
1266     d->relative_mouse_mode = 0;
1267 
1268     return 0;
1269 }
1270 
1271 static void
confined_pointer_confined(void * data,struct zwp_confined_pointer_v1 * confined_pointer)1272 confined_pointer_confined(void *data,
1273                           struct zwp_confined_pointer_v1 *confined_pointer)
1274 {
1275 }
1276 
1277 static void
confined_pointer_unconfined(void * data,struct zwp_confined_pointer_v1 * confined_pointer)1278 confined_pointer_unconfined(void *data,
1279                             struct zwp_confined_pointer_v1 *confined_pointer)
1280 {
1281 }
1282 
1283 static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
1284     confined_pointer_confined,
1285     confined_pointer_unconfined,
1286 };
1287 
Wayland_input_confine_pointer(SDL_Window * window,struct SDL_WaylandInput * input)1288 int Wayland_input_confine_pointer(SDL_Window *window, struct SDL_WaylandInput *input)
1289 {
1290     SDL_WindowData *w = window->driverdata;
1291     SDL_VideoData *d = input->display;
1292     struct zwp_confined_pointer_v1 *confined_pointer;
1293 
1294     if (!d->pointer_constraints)
1295         return -1;
1296 
1297     if (!input->pointer)
1298         return -1;
1299 
1300     /* A confine may already be active, in which case we should destroy it and
1301      * create a new one. */
1302     if (input->confined_pointer)
1303         Wayland_input_unconfine_pointer(input);
1304 
1305     confined_pointer =
1306         zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
1307                                                    w->surface,
1308                                                    input->pointer,
1309                                                    NULL,
1310                                                    ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1311     zwp_confined_pointer_v1_add_listener(confined_pointer,
1312                                          &confined_pointer_listener,
1313                                          window);
1314 
1315     input->confined_pointer = confined_pointer;
1316     return 0;
1317 }
1318 
Wayland_input_unconfine_pointer(struct SDL_WaylandInput * input)1319 int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input)
1320 {
1321     if (input->confined_pointer) {
1322         zwp_confined_pointer_v1_destroy(input->confined_pointer);
1323         input->confined_pointer = NULL;
1324     }
1325 
1326     return 0;
1327 }
1328 
1329 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
1330 
1331 /* vi: set ts=4 sw=4 expandtab: */
1332