1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2021 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_timer.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 "pointer-constraints-unstable-v1-client-protocol.h"
39 #include "relative-pointer-unstable-v1-client-protocol.h"
40 #include "xdg-shell-client-protocol.h"
41 #include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
42 #include "text-input-unstable-v3-client-protocol.h"
43 
44 #ifdef HAVE_LIBDECOR_H
45 #include <libdecor.h>
46 #endif
47 
48 #ifdef SDL_INPUT_LINUXEV
49 #include <linux/input.h>
50 #else
51 #define BTN_LEFT    (0x110)
52 #define BTN_RIGHT   (0x111)
53 #define BTN_MIDDLE  (0x112)
54 #define BTN_SIDE    (0x113)
55 #define BTN_EXTRA   (0x114)
56 #endif
57 #include <sys/select.h>
58 #include <sys/mman.h>
59 #include <poll.h>
60 #include <unistd.h>
61 #include <errno.h>
62 #include <xkbcommon/xkbcommon.h>
63 #include <xkbcommon/xkbcommon-compose.h>
64 #include "../../events/imKStoUCS.h"
65 
66 /* Weston uses a ratio of 10 units per scroll tick */
67 #define WAYLAND_WHEEL_AXIS_UNIT 10
68 
69 struct SDL_WaylandTouchPoint {
70     SDL_TouchID id;
71     float x;
72     float y;
73     struct wl_surface* surface;
74 
75     struct SDL_WaylandTouchPoint* prev;
76     struct SDL_WaylandTouchPoint* next;
77 };
78 
79 struct SDL_WaylandTouchPointList {
80     struct SDL_WaylandTouchPoint* head;
81     struct SDL_WaylandTouchPoint* tail;
82 };
83 
84 static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
85 
86 static void
touch_add(SDL_TouchID id,float x,float y,struct wl_surface * surface)87 touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
88 {
89     struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
90 
91     tp->id = id;
92     tp->x = x;
93     tp->y = y;
94     tp->surface = surface;
95 
96     if (touch_points.tail) {
97         touch_points.tail->next = tp;
98         tp->prev = touch_points.tail;
99     } else {
100         touch_points.head = tp;
101         tp->prev = NULL;
102     }
103 
104     touch_points.tail = tp;
105     tp->next = NULL;
106 }
107 
108 static void
touch_update(SDL_TouchID id,float x,float y)109 touch_update(SDL_TouchID id, float x, float y)
110 {
111     struct SDL_WaylandTouchPoint* tp = touch_points.head;
112 
113     while (tp) {
114         if (tp->id == id) {
115             tp->x = x;
116             tp->y = y;
117         }
118 
119         tp = tp->next;
120     }
121 }
122 
123 static void
touch_del(SDL_TouchID id,float * x,float * y,struct wl_surface ** surface)124 touch_del(SDL_TouchID id, float* x, float* y, struct wl_surface **surface)
125 {
126     struct SDL_WaylandTouchPoint* tp = touch_points.head;
127 
128     while (tp) {
129         if (tp->id == id) {
130             *x = tp->x;
131             *y = tp->y;
132             *surface = tp->surface;
133 
134             if (tp->prev) {
135                 tp->prev->next = tp->next;
136             } else {
137                 touch_points.head = tp->next;
138             }
139 
140             if (tp->next) {
141                 tp->next->prev = tp->prev;
142             } else {
143                 touch_points.tail = tp->prev;
144             }
145 
146             {
147                 struct SDL_WaylandTouchPoint *next = tp->next;
148                 SDL_free(tp);
149                 tp = next;
150             }
151         } else {
152             tp = tp->next;
153         }
154     }
155 }
156 
157 static struct wl_surface*
touch_surface(SDL_TouchID id)158 touch_surface(SDL_TouchID id)
159 {
160     struct SDL_WaylandTouchPoint* tp = touch_points.head;
161 
162     while (tp) {
163         if (tp->id == id) {
164             return tp->surface;
165         }
166 
167         tp = tp->next;
168     }
169 
170     return NULL;
171 }
172 
173 /* Returns SDL_TRUE if a key repeat event was due */
174 static SDL_bool
keyboard_repeat_handle(SDL_WaylandKeyboardRepeat * repeat_info,uint32_t now)175 keyboard_repeat_handle(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t now)
176 {
177     SDL_bool ret = SDL_FALSE;
178     if (!repeat_info->is_key_down || !repeat_info->is_initialized) {
179         return ret;
180     }
181     while (repeat_info->next_repeat_ms <= now) {
182         if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
183             SDL_SendKeyboardKey(SDL_PRESSED, repeat_info->scancode);
184         }
185         if (repeat_info->text[0]) {
186             SDL_SendKeyboardText(repeat_info->text);
187         }
188         repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate;
189         ret = SDL_TRUE;
190     }
191     return ret;
192 }
193 
194 static void
keyboard_repeat_clear(SDL_WaylandKeyboardRepeat * repeat_info)195 keyboard_repeat_clear(SDL_WaylandKeyboardRepeat* repeat_info) {
196     if (!repeat_info->is_initialized) {
197         return;
198     }
199     repeat_info->is_key_down = SDL_FALSE;
200 }
201 
202 static void
keyboard_repeat_set(SDL_WaylandKeyboardRepeat * repeat_info,uint32_t scancode,SDL_bool has_text,char text[8])203 keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info,
204                     uint32_t scancode, SDL_bool has_text, char text[8]) {
205     if (!repeat_info->is_initialized || !repeat_info->repeat_rate) {
206         return;
207     }
208     repeat_info->is_key_down = SDL_TRUE;
209     repeat_info->next_repeat_ms = SDL_GetTicks() + repeat_info->repeat_delay;
210     repeat_info->scancode = scancode;
211     if (has_text) {
212         SDL_memcpy(repeat_info->text, text, 8);
213     } else {
214         repeat_info->text[0] = '\0';
215     }
216 }
217 
218 void
Wayland_SendWakeupEvent(_THIS,SDL_Window * window)219 Wayland_SendWakeupEvent(_THIS, SDL_Window *window)
220 {
221     SDL_VideoData *d = _this->driverdata;
222 
223     /* TODO: Maybe use a pipe to avoid the compositor roundtrip? */
224     wl_display_sync(d->display);
225     WAYLAND_wl_display_flush(d->display);
226 }
227 
228 int
Wayland_WaitEventTimeout(_THIS,int timeout)229 Wayland_WaitEventTimeout(_THIS, int timeout)
230 {
231     SDL_VideoData *d = _this->driverdata;
232     struct SDL_WaylandInput *input = d->input;
233     SDL_bool key_repeat_active = SDL_FALSE;
234 
235     WAYLAND_wl_display_flush(d->display);
236 
237 #ifdef SDL_USE_IME
238     if (d->text_input_manager == NULL && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
239         SDL_IME_PumpEvents();
240     }
241 #endif
242 
243     /* If key repeat is active, we'll need to cap our maximum wait time to handle repeats */
244     if (input && input->keyboard_repeat.is_initialized && input->keyboard_repeat.is_key_down) {
245         uint32_t now = SDL_GetTicks();
246         if (keyboard_repeat_handle(&input->keyboard_repeat, now)) {
247             /* A repeat key event was already due */
248             return 1;
249         } else {
250             uint32_t next_repeat_wait_time = (input->keyboard_repeat.next_repeat_ms - now) + 1;
251             if (timeout >= 0) {
252                 timeout = SDL_min(timeout, next_repeat_wait_time);
253             } else {
254                 timeout = next_repeat_wait_time;
255             }
256             key_repeat_active = SDL_TRUE;
257         }
258     }
259 
260     /* wl_display_prepare_read() will return -1 if the default queue is not empty.
261      * If the default queue is empty, it will prepare us for our SDL_IOReady() call. */
262     if (WAYLAND_wl_display_prepare_read(d->display) == 0) {
263         /* Use SDL_IOR_NO_RETRY to ensure SIGINT will break us out of our wait */
264         int err = SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_IOR_READ | SDL_IOR_NO_RETRY, timeout);
265         if (err > 0) {
266             /* There are new events available to read */
267             WAYLAND_wl_display_read_events(d->display);
268             WAYLAND_wl_display_dispatch_pending(d->display);
269             return 1;
270         } else if (err == 0) {
271             /* No events available within the timeout */
272             WAYLAND_wl_display_cancel_read(d->display);
273 
274             /* If key repeat is active, we might have woken up to generate a key event */
275             if (key_repeat_active) {
276                 uint32_t now = SDL_GetTicks();
277                 if (keyboard_repeat_handle(&input->keyboard_repeat, now)) {
278                     return 1;
279                 }
280             }
281 
282             return 0;
283         } else {
284             /* Error returned from poll()/select() */
285             WAYLAND_wl_display_cancel_read(d->display);
286 
287             if (errno == EINTR) {
288                 /* If the wait was interrupted by a signal, we may have generated a
289                  * SDL_QUIT event. Let the caller know to call SDL_PumpEvents(). */
290                 return 1;
291             } else {
292                 return err;
293             }
294         }
295     } else {
296         /* We already had pending events */
297         WAYLAND_wl_display_dispatch_pending(d->display);
298         return 1;
299     }
300 }
301 
302 void
Wayland_PumpEvents(_THIS)303 Wayland_PumpEvents(_THIS)
304 {
305     SDL_VideoData *d = _this->driverdata;
306     struct SDL_WaylandInput *input = d->input;
307     int err;
308 
309     WAYLAND_wl_display_flush(d->display);
310 
311 #ifdef SDL_USE_IME
312     if (d->text_input_manager == NULL && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
313         SDL_IME_PumpEvents();
314     }
315 #endif
316 
317     if (input) {
318         uint32_t now = SDL_GetTicks();
319         keyboard_repeat_handle(&input->keyboard_repeat, now);
320     }
321 
322     /* wl_display_prepare_read() will return -1 if the default queue is not empty.
323      * If the default queue is empty, it will prepare us for our SDL_IOReady() call. */
324     if (WAYLAND_wl_display_prepare_read(d->display) == 0) {
325         if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_IOR_READ, 0) > 0) {
326             WAYLAND_wl_display_read_events(d->display);
327         } else {
328             WAYLAND_wl_display_cancel_read(d->display);
329         }
330     }
331 
332     /* Dispatch any pre-existing pending events or new events we may have read */
333     err = WAYLAND_wl_display_dispatch_pending(d->display);
334 
335     if (err == -1 && !d->display_disconnected) {
336         /* Something has failed with the Wayland connection -- for example,
337          * the compositor may have shut down and closed its end of the socket,
338          * or there is a library-specific error. No recovery is possible. */
339         d->display_disconnected = 1;
340         /* Only send a single quit message, as application shutdown might call
341          * SDL_PumpEvents */
342         SDL_SendQuit();
343     }
344 }
345 
346 static void
pointer_handle_motion(void * data,struct wl_pointer * pointer,uint32_t time,wl_fixed_t sx_w,wl_fixed_t sy_w)347 pointer_handle_motion(void *data, struct wl_pointer *pointer,
348                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
349 {
350     struct SDL_WaylandInput *input = data;
351     SDL_WindowData *window = input->pointer_focus;
352     input->sx_w = sx_w;
353     input->sy_w = sy_w;
354     if (input->pointer_focus) {
355         const int sx = wl_fixed_to_int(sx_w);
356         const int sy = wl_fixed_to_int(sy_w);
357         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
358     }
359 }
360 
361 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)362 pointer_handle_enter(void *data, struct wl_pointer *pointer,
363                      uint32_t serial, struct wl_surface *surface,
364                      wl_fixed_t sx_w, wl_fixed_t sy_w)
365 {
366     struct SDL_WaylandInput *input = data;
367     SDL_WindowData *window;
368 
369     if (!surface) {
370         /* enter event for a window we've just destroyed */
371         return;
372     }
373 
374     /* check that this surface belongs to one of the SDL windows */
375     if (!SDL_WAYLAND_own_surface(surface)) {
376         return;
377     }
378 
379     /* This handler will be called twice in Wayland 1.4
380      * Once for the window surface which has valid user data
381      * and again for the mouse cursor surface which does not have valid user data
382      * We ignore the later
383      */
384 
385     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
386 
387     if (window) {
388         input->pointer_focus = window;
389         input->pointer_enter_serial = serial;
390         SDL_SetMouseFocus(window->sdlwindow);
391         /* In the case of e.g. a pointer confine warp, we may receive an enter
392          * event with no following motion event, but with the new coordinates
393          * as part of the enter event. */
394         pointer_handle_motion(data, pointer, serial, sx_w, sy_w);
395         /* If the cursor was changed while our window didn't have pointer
396          * focus, we might need to trigger another call to
397          * wl_pointer_set_cursor() for the new cursor to be displayed. */
398         SDL_SetCursor(NULL);
399     }
400 }
401 
402 static void
pointer_handle_leave(void * data,struct wl_pointer * pointer,uint32_t serial,struct wl_surface * surface)403 pointer_handle_leave(void *data, struct wl_pointer *pointer,
404                      uint32_t serial, struct wl_surface *surface)
405 {
406     struct SDL_WaylandInput *input = data;
407 
408     if (!surface || !SDL_WAYLAND_own_surface(surface)) {
409         return;
410     }
411 
412     if (input->pointer_focus) {
413         SDL_SetMouseFocus(NULL);
414         input->pointer_focus = NULL;
415     }
416 }
417 
418 static SDL_bool
ProcessHitTest(struct SDL_WaylandInput * input,uint32_t serial)419 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
420 {
421     SDL_WindowData *window_data = input->pointer_focus;
422     SDL_Window *window = window_data->sdlwindow;
423 
424     if (window->hit_test) {
425         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
426         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
427 
428         static const uint32_t directions[] = {
429             XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_TOP,
430             XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT,
431             XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM,
432             XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_LEFT
433         };
434 
435 #ifdef HAVE_LIBDECOR_H
436         /* ditto for libdecor. */
437         const uint32_t *directions_libdecor = directions;
438 #endif
439 
440         switch (rc) {
441             case SDL_HITTEST_DRAGGABLE:
442 #ifdef HAVE_LIBDECOR_H
443                 if (input->display->shell.libdecor) {
444                     if (window_data->shell_surface.libdecor.frame) {
445                         libdecor_frame_move(window_data->shell_surface.libdecor.frame, input->seat, serial);
446                     }
447                 } else
448 #endif
449                 if (input->display->shell.xdg) {
450                     if (window_data->shell_surface.xdg.roleobj.toplevel) {
451                         xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel,
452                                           input->seat,
453                                           serial);
454                     }
455                 }
456                 return SDL_TRUE;
457 
458             case SDL_HITTEST_RESIZE_TOPLEFT:
459             case SDL_HITTEST_RESIZE_TOP:
460             case SDL_HITTEST_RESIZE_TOPRIGHT:
461             case SDL_HITTEST_RESIZE_RIGHT:
462             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
463             case SDL_HITTEST_RESIZE_BOTTOM:
464             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
465             case SDL_HITTEST_RESIZE_LEFT:
466 #ifdef HAVE_LIBDECOR_H
467                 if (input->display->shell.libdecor) {
468                     if (window_data->shell_surface.libdecor.frame) {
469                         libdecor_frame_resize(window_data->shell_surface.libdecor.frame, input->seat, serial, directions_libdecor[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
470                     }
471                 } else
472 #endif
473                 if (input->display->shell.xdg) {
474                     if (window_data->shell_surface.xdg.roleobj.toplevel) {
475                         xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel,
476                                             input->seat,
477                                             serial,
478                                             directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
479                     }
480                 }
481                 return SDL_TRUE;
482 
483             default: return SDL_FALSE;
484         }
485     }
486 
487     return SDL_FALSE;
488 }
489 
490 static void
pointer_handle_button_common(struct SDL_WaylandInput * input,uint32_t serial,uint32_t time,uint32_t button,uint32_t state_w)491 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
492                              uint32_t time, uint32_t button, uint32_t state_w)
493 {
494     SDL_WindowData *window = input->pointer_focus;
495     enum wl_pointer_button_state state = state_w;
496     uint32_t sdl_button;
497 
498     if  (input->pointer_focus) {
499         switch (button) {
500             case BTN_LEFT:
501                 sdl_button = SDL_BUTTON_LEFT;
502                 if (ProcessHitTest(input, serial)) {
503                     return;  /* don't pass this event on to app. */
504                 }
505                 break;
506             case BTN_MIDDLE:
507                 sdl_button = SDL_BUTTON_MIDDLE;
508                 break;
509             case BTN_RIGHT:
510                 sdl_button = SDL_BUTTON_RIGHT;
511                 break;
512             case BTN_SIDE:
513                 sdl_button = SDL_BUTTON_X1;
514                 break;
515             case BTN_EXTRA:
516                 sdl_button = SDL_BUTTON_X2;
517                 break;
518             default:
519                 return;
520         }
521 
522         Wayland_data_device_set_serial(input->data_device, serial);
523 
524         SDL_SendMouseButton(window->sdlwindow, 0,
525                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
526     }
527 }
528 
529 static void
pointer_handle_button(void * data,struct wl_pointer * pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state_w)530 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
531                       uint32_t time, uint32_t button, uint32_t state_w)
532 {
533     struct SDL_WaylandInput *input = data;
534 
535     pointer_handle_button_common(input, serial, time, button, state_w);
536 }
537 
538 static void
pointer_handle_axis_common_v1(struct SDL_WaylandInput * input,uint32_t time,uint32_t axis,wl_fixed_t value)539 pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
540                               uint32_t time, uint32_t axis, wl_fixed_t value)
541 {
542     SDL_WindowData *window = input->pointer_focus;
543     enum wl_pointer_axis a = axis;
544     float x, y;
545 
546     if (input->pointer_focus) {
547         switch (a) {
548             case WL_POINTER_AXIS_VERTICAL_SCROLL:
549                 x = 0;
550                 y = 0 - (float)wl_fixed_to_double(value);
551                 break;
552             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
553                 x = 0 - (float)wl_fixed_to_double(value);
554                 y = 0;
555                 break;
556             default:
557                 return;
558         }
559 
560         x /= WAYLAND_WHEEL_AXIS_UNIT;
561         y /= WAYLAND_WHEEL_AXIS_UNIT;
562 
563         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
564     }
565 }
566 
567 static void
pointer_handle_axis_common(struct SDL_WaylandInput * input,SDL_bool discrete,uint32_t axis,wl_fixed_t value)568 pointer_handle_axis_common(struct SDL_WaylandInput *input, SDL_bool discrete,
569                            uint32_t axis, wl_fixed_t value)
570 {
571     enum wl_pointer_axis a = axis;
572 
573     if (input->pointer_focus) {
574         switch (a) {
575             case WL_POINTER_AXIS_VERTICAL_SCROLL:
576                 if (discrete) {
577                     /* this is a discrete axis event so we process it and flag
578                      * to ignore future continuous axis events in this frame */
579                     input->pointer_curr_axis_info.is_y_discrete = SDL_TRUE;
580                 } else if(input->pointer_curr_axis_info.is_y_discrete) {
581                     /* this is a continuous axis event and we have already
582                      * processed a discrete axis event before so we ignore it */
583                     break;
584                 }
585                 input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
586                 break;
587             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
588                 if (discrete) {
589                     /* this is a discrete axis event so we process it and flag
590                      * to ignore future continuous axis events in this frame */
591                     input->pointer_curr_axis_info.is_x_discrete = SDL_TRUE;
592                 } else if(input->pointer_curr_axis_info.is_x_discrete) {
593                     /* this is a continuous axis event and we have already
594                      * processed a discrete axis event before so we ignore it */
595                     break;
596                 }
597                 input->pointer_curr_axis_info.x = 0 - (float)wl_fixed_to_double(value);
598                 break;
599         }
600     }
601 }
602 
603 static void
pointer_handle_axis(void * data,struct wl_pointer * pointer,uint32_t time,uint32_t axis,wl_fixed_t value)604 pointer_handle_axis(void *data, struct wl_pointer *pointer,
605                     uint32_t time, uint32_t axis, wl_fixed_t value)
606 {
607     struct SDL_WaylandInput *input = data;
608 
609     if(wl_seat_get_version(input->seat) >= 5)
610         pointer_handle_axis_common(input, SDL_FALSE, axis, value);
611     else
612         pointer_handle_axis_common_v1(input, time, axis, value);
613 }
614 
615 static void
pointer_handle_frame(void * data,struct wl_pointer * pointer)616 pointer_handle_frame(void *data, struct wl_pointer *pointer)
617 {
618     struct SDL_WaylandInput *input = data;
619     SDL_WindowData *window = input->pointer_focus;
620     float x, y;
621 
622     if (input->pointer_curr_axis_info.is_x_discrete)
623         x = input->pointer_curr_axis_info.x;
624     else
625         x = input->pointer_curr_axis_info.x / WAYLAND_WHEEL_AXIS_UNIT;
626 
627     if (input->pointer_curr_axis_info.is_y_discrete)
628         y = input->pointer_curr_axis_info.y;
629     else
630         y = input->pointer_curr_axis_info.y / WAYLAND_WHEEL_AXIS_UNIT;
631 
632     /* clear pointer_curr_axis_info for next frame */
633     SDL_memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
634 
635     if(x == 0.0f && y == 0.0f)
636         return;
637     else
638         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
639 }
640 
641 static void
pointer_handle_axis_source(void * data,struct wl_pointer * pointer,uint32_t axis_source)642 pointer_handle_axis_source(void *data, struct wl_pointer *pointer,
643                            uint32_t axis_source)
644 {
645     /* unimplemented */
646 }
647 
648 static void
pointer_handle_axis_stop(void * data,struct wl_pointer * pointer,uint32_t time,uint32_t axis)649 pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
650                          uint32_t time, uint32_t axis)
651 {
652     /* unimplemented */
653 }
654 
655 static void
pointer_handle_axis_discrete(void * data,struct wl_pointer * pointer,uint32_t axis,int32_t discrete)656 pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
657                              uint32_t axis, int32_t discrete)
658 {
659     struct SDL_WaylandInput *input = data;
660 
661     pointer_handle_axis_common(input, SDL_TRUE, axis, wl_fixed_from_int(discrete));
662 }
663 
664 
665 static const struct wl_pointer_listener pointer_listener = {
666     pointer_handle_enter,
667     pointer_handle_leave,
668     pointer_handle_motion,
669     pointer_handle_button,
670     pointer_handle_axis,
671     pointer_handle_frame,           // Version 5
672     pointer_handle_axis_source,     // Version 5
673     pointer_handle_axis_stop,       // Version 5
674     pointer_handle_axis_discrete,   // Version 5
675 };
676 
677 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)678 touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
679                    unsigned int timestamp, struct wl_surface *surface,
680                    int id, wl_fixed_t fx, wl_fixed_t fy)
681 {
682     SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
683     const double dblx = wl_fixed_to_double(fx);
684     const double dbly = wl_fixed_to_double(fy);
685     const float x = dblx / window_data->sdlwindow->w;
686     const float y = dbly / window_data->sdlwindow->h;
687 
688     touch_add(id, x, y, surface);
689 
690     SDL_SendTouch((SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f);
691 }
692 
693 static void
touch_handler_up(void * data,struct wl_touch * touch,unsigned int serial,unsigned int timestamp,int id)694 touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
695                  unsigned int timestamp, int id)
696 {
697     float x = 0, y = 0;
698     struct wl_surface *surface = NULL;
699     SDL_Window *window = NULL;
700 
701     touch_del(id, &x, &y, &surface);
702 
703     if (surface) {
704         SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
705         window = window_data->sdlwindow;
706     }
707 
708     SDL_SendTouch((SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id, window, SDL_FALSE, x, y, 0.0f);
709 }
710 
711 static void
touch_handler_motion(void * data,struct wl_touch * touch,unsigned int timestamp,int id,wl_fixed_t fx,wl_fixed_t fy)712 touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
713                      int id, wl_fixed_t fx, wl_fixed_t fy)
714 {
715     SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
716     const double dblx = wl_fixed_to_double(fx);
717     const double dbly = wl_fixed_to_double(fy);
718     const float x = dblx / window_data->sdlwindow->w;
719     const float y = dbly / window_data->sdlwindow->h;
720 
721     touch_update(id, x, y);
722     SDL_SendTouchMotion((SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f);
723 }
724 
725 static void
touch_handler_frame(void * data,struct wl_touch * touch)726 touch_handler_frame(void *data, struct wl_touch *touch)
727 {
728 
729 }
730 
731 static void
touch_handler_cancel(void * data,struct wl_touch * touch)732 touch_handler_cancel(void *data, struct wl_touch *touch)
733 {
734 
735 }
736 
737 static const struct wl_touch_listener touch_listener = {
738     touch_handler_down,
739     touch_handler_up,
740     touch_handler_motion,
741     touch_handler_frame,
742     touch_handler_cancel,
743     NULL, /* shape */
744     NULL, /* orientation */
745 };
746 
747 static void
keyboard_handle_keymap(void * data,struct wl_keyboard * keyboard,uint32_t format,int fd,uint32_t size)748 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
749                        uint32_t format, int fd, uint32_t size)
750 {
751     struct SDL_WaylandInput *input = data;
752     char *map_str;
753     const char *locale;
754 
755     if (!data) {
756         close(fd);
757         return;
758     }
759 
760     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
761         close(fd);
762         return;
763     }
764 
765     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
766     if (map_str == MAP_FAILED) {
767         close(fd);
768         return;
769     }
770 
771     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
772                                                 map_str,
773                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
774                                                 0);
775     munmap(map_str, size);
776     close(fd);
777 
778     if (!input->xkb.keymap) {
779         fprintf(stderr, "failed to compile keymap\n");
780         return;
781     }
782 
783     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
784     if (!input->xkb.state) {
785         fprintf(stderr, "failed to create XKB state\n");
786         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
787         input->xkb.keymap = NULL;
788         return;
789     }
790 
791     /*
792      * See https://blogs.s-osg.org/compose-key-support-weston/
793      * for further explanation on dead keys in Wayland.
794      */
795 
796     /* Look up the preferred locale, falling back to "C" as default */
797     if (!(locale = SDL_getenv("LC_ALL")))
798         if (!(locale = SDL_getenv("LC_CTYPE")))
799             if (!(locale = SDL_getenv("LANG")))
800                 locale = "C";
801     /* Set up XKB compose table */
802     input->xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(input->display->xkb_context,
803                                               locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
804     if (input->xkb.compose_table) {
805         /* Set up XKB compose state */
806         input->xkb.compose_state = WAYLAND_xkb_compose_state_new(input->xkb.compose_table,
807                                               XKB_COMPOSE_STATE_NO_FLAGS);
808         if (!input->xkb.compose_state) {
809             fprintf(stderr, "could not create XKB compose state\n");
810             WAYLAND_xkb_compose_table_unref(input->xkb.compose_table);
811             input->xkb.compose_table = NULL;
812         }
813     }
814 }
815 
816 static void
keyboard_handle_enter(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)817 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
818                       uint32_t serial, struct wl_surface *surface,
819                       struct wl_array *keys)
820 {
821     struct SDL_WaylandInput *input = data;
822     SDL_WindowData *window;
823 
824     if (!surface) {
825         /* enter event for a window we've just destroyed */
826         return;
827     }
828 
829     if (!SDL_WAYLAND_own_surface(surface)) {
830         return;
831     }
832 
833     window = wl_surface_get_user_data(surface);
834 
835     if (window) {
836         input->keyboard_focus = window;
837         window->keyboard_device = input;
838         SDL_SetKeyboardFocus(window->sdlwindow);
839     }
840 #ifdef SDL_USE_IME
841     if (!input->text_input) {
842         SDL_IME_SetFocus(SDL_TRUE);
843     }
844 #endif
845 }
846 
847 static void
keyboard_handle_leave(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface)848 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
849                       uint32_t serial, struct wl_surface *surface)
850 {
851     struct SDL_WaylandInput *input = data;
852 
853     if (!surface || !SDL_WAYLAND_own_surface(surface)) {
854         return;
855     }
856 
857     /* Stop key repeat before clearing keyboard focus */
858     keyboard_repeat_clear(&input->keyboard_repeat);
859 
860     /* This will release any keys still pressed */
861     SDL_SetKeyboardFocus(NULL);
862 
863 #ifdef SDL_USE_IME
864     if (!input->text_input) {
865         SDL_IME_SetFocus(SDL_FALSE);
866     }
867 #endif
868 }
869 
870 static SDL_bool
keyboard_input_get_text(char text[8],const struct SDL_WaylandInput * input,uint32_t key,SDL_bool * handled_by_ime)871 keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime)
872 {
873     SDL_WindowData *window = input->keyboard_focus;
874     const xkb_keysym_t *syms;
875     xkb_keysym_t sym;
876 
877     if (!window || window->keyboard_device != input || !input->xkb.state) {
878         return SDL_FALSE;
879     }
880 
881     // TODO can this happen?
882     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
883         return SDL_FALSE;
884     }
885     sym = syms[0];
886 
887 #ifdef SDL_USE_IME
888     if (SDL_IME_ProcessKeyEvent(sym, key + 8)) {
889         *handled_by_ime = SDL_TRUE;
890         return SDL_TRUE;
891     }
892 #endif
893 
894     if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) {
895         switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) {
896             case XKB_COMPOSE_COMPOSING:
897                 *handled_by_ime = SDL_TRUE;
898                 return SDL_TRUE;
899             case XKB_COMPOSE_CANCELLED:
900             default:
901                 sym = XKB_KEY_NoSymbol;
902                 break;
903             case XKB_COMPOSE_NOTHING:
904                 break;
905             case XKB_COMPOSE_COMPOSED:
906                 sym = WAYLAND_xkb_compose_state_get_one_sym(input->xkb.compose_state);
907                 break;
908         }
909     }
910 
911     return WAYLAND_xkb_keysym_to_utf8(sym, text, 8) > 0;
912 }
913 
914 static void
keyboard_handle_key(void * data,struct wl_keyboard * keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state_w)915 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
916                     uint32_t serial, uint32_t time, uint32_t key,
917                     uint32_t state_w)
918 {
919     struct SDL_WaylandInput *input = data;
920     enum wl_keyboard_key_state state = state_w;
921     uint32_t scancode = SDL_SCANCODE_UNKNOWN;
922     char text[8];
923     SDL_bool has_text = SDL_FALSE;
924     SDL_bool handled_by_ime = SDL_FALSE;
925 
926     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
927         has_text = keyboard_input_get_text(text, input, key, &handled_by_ime);
928     }
929 
930     if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) {
931         scancode = xfree86_scancode_table2[key];
932 
933         if (scancode != SDL_SCANCODE_UNKNOWN) {
934             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
935                                 SDL_PRESSED : SDL_RELEASED, scancode);
936         }
937     }
938 
939     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
940         if (has_text && !(SDL_GetModState() & KMOD_CTRL)) {
941             Wayland_data_device_set_serial(input->data_device, serial);
942             if (!handled_by_ime) {
943                 SDL_SendKeyboardText(text);
944             }
945         }
946         keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text);
947     } else {
948         keyboard_repeat_clear(&input->keyboard_repeat);
949     }
950 }
951 
952 typedef struct Wayland_Keymap
953 {
954     xkb_layout_index_t layout;
955     SDL_Keycode keymap[SDL_NUM_SCANCODES];
956 } Wayland_Keymap;
957 
958 static void
Wayland_keymap_iter(struct xkb_keymap * keymap,xkb_keycode_t key,void * data)959 Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
960 {
961     const xkb_keysym_t *syms;
962     Wayland_Keymap *sdlKeymap = (Wayland_Keymap *)data;
963 
964     if ((key - 8) < SDL_arraysize(xfree86_scancode_table2)) {
965         SDL_Scancode scancode = xfree86_scancode_table2[key - 8];
966         if (scancode == SDL_SCANCODE_UNKNOWN) {
967             return;
968         }
969 
970         if (WAYLAND_xkb_keymap_key_get_syms_by_level(keymap, key, sdlKeymap->layout, 0, &syms) > 0) {
971             uint32_t keycode = SDL_KeySymToUcs4(syms[0]);
972             if (keycode) {
973                 sdlKeymap->keymap[scancode] = keycode;
974             } else {
975                 switch (scancode) {
976                     case SDL_SCANCODE_RETURN:
977                         sdlKeymap->keymap[scancode] = SDLK_RETURN;
978                         break;
979                     case SDL_SCANCODE_ESCAPE:
980                         sdlKeymap->keymap[scancode] = SDLK_ESCAPE;
981                         break;
982                     case SDL_SCANCODE_BACKSPACE:
983                         sdlKeymap->keymap[scancode] = SDLK_BACKSPACE;
984                         break;
985                     case SDL_SCANCODE_TAB:
986                         sdlKeymap->keymap[scancode] = SDLK_TAB;
987                         break;
988                     case SDL_SCANCODE_DELETE:
989                         sdlKeymap->keymap[scancode] = SDLK_DELETE;
990                         break;
991                     default:
992                         sdlKeymap->keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(scancode);
993                         break;
994                 }
995             }
996         }
997     }
998 }
999 
1000 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)1001 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
1002                           uint32_t serial, uint32_t mods_depressed,
1003                           uint32_t mods_latched, uint32_t mods_locked,
1004                           uint32_t group)
1005 {
1006     struct SDL_WaylandInput *input = data;
1007     Wayland_Keymap keymap;
1008 
1009     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
1010                           mods_locked, 0, 0, group);
1011 
1012     keymap.layout = group;
1013     SDL_GetDefaultKeymap(keymap.keymap);
1014     WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
1015                                     Wayland_keymap_iter,
1016                                     &keymap);
1017     SDL_SetKeymap(0, keymap.keymap, SDL_NUM_SCANCODES);
1018     SDL_SendKeymapChangedEvent();
1019 }
1020 
1021 static void
keyboard_handle_repeat_info(void * data,struct wl_keyboard * wl_keyboard,int32_t rate,int32_t delay)1022 keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
1023                             int32_t rate, int32_t delay)
1024 {
1025     struct SDL_WaylandInput *input = data;
1026     input->keyboard_repeat.repeat_rate = SDL_clamp(rate, 0, 1000);
1027     input->keyboard_repeat.repeat_delay = delay;
1028     input->keyboard_repeat.is_initialized = SDL_TRUE;
1029 }
1030 
1031 static const struct wl_keyboard_listener keyboard_listener = {
1032     keyboard_handle_keymap,
1033     keyboard_handle_enter,
1034     keyboard_handle_leave,
1035     keyboard_handle_key,
1036     keyboard_handle_modifiers,
1037     keyboard_handle_repeat_info,    // Version 4
1038 };
1039 
1040 static void
seat_handle_capabilities(void * data,struct wl_seat * seat,enum wl_seat_capability caps)1041 seat_handle_capabilities(void *data, struct wl_seat *seat,
1042                          enum wl_seat_capability caps)
1043 {
1044     struct SDL_WaylandInput *input = data;
1045 
1046     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
1047         input->pointer = wl_seat_get_pointer(seat);
1048         SDL_memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
1049         input->display->pointer = input->pointer;
1050         wl_pointer_set_user_data(input->pointer, input);
1051         wl_pointer_add_listener(input->pointer, &pointer_listener,
1052                                 input);
1053     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
1054         wl_pointer_destroy(input->pointer);
1055         input->pointer = NULL;
1056         input->display->pointer = NULL;
1057     }
1058 
1059     if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
1060         input->touch = wl_seat_get_touch(seat);
1061         SDL_AddTouch((SDL_TouchID)(intptr_t)input->touch, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
1062         wl_touch_set_user_data(input->touch, input);
1063         wl_touch_add_listener(input->touch, &touch_listener,
1064                                  input);
1065     } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
1066         SDL_DelTouch((SDL_TouchID)(intptr_t)input->touch);
1067         wl_touch_destroy(input->touch);
1068         input->touch = NULL;
1069     }
1070 
1071     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
1072         input->keyboard = wl_seat_get_keyboard(seat);
1073         wl_keyboard_set_user_data(input->keyboard, input);
1074         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
1075                                  input);
1076     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
1077         wl_keyboard_destroy(input->keyboard);
1078         input->keyboard = NULL;
1079     }
1080 }
1081 
1082 static void
seat_handle_name(void * data,struct wl_seat * wl_seat,const char * name)1083 seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
1084 {
1085     /* unimplemented */
1086 }
1087 
1088 static const struct wl_seat_listener seat_listener = {
1089     seat_handle_capabilities,
1090     seat_handle_name,           // Version 2
1091 };
1092 
1093 static void
data_source_handle_target(void * data,struct wl_data_source * wl_data_source,const char * mime_type)1094 data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
1095                           const char *mime_type)
1096 {
1097 }
1098 
1099 static void
data_source_handle_send(void * data,struct wl_data_source * wl_data_source,const char * mime_type,int32_t fd)1100 data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
1101                         const char *mime_type, int32_t fd)
1102 {
1103     Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
1104 }
1105 
1106 static void
data_source_handle_cancelled(void * data,struct wl_data_source * wl_data_source)1107 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
1108 {
1109     Wayland_data_source_destroy(data);
1110 }
1111 
1112 static void
data_source_handle_dnd_drop_performed(void * data,struct wl_data_source * wl_data_source)1113 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
1114 {
1115 }
1116 
1117 static void
data_source_handle_dnd_finished(void * data,struct wl_data_source * wl_data_source)1118 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
1119 {
1120 }
1121 
1122 static void
data_source_handle_action(void * data,struct wl_data_source * wl_data_source,uint32_t dnd_action)1123 data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
1124                           uint32_t dnd_action)
1125 {
1126 }
1127 
1128 static const struct wl_data_source_listener data_source_listener = {
1129     data_source_handle_target,
1130     data_source_handle_send,
1131     data_source_handle_cancelled,
1132     data_source_handle_dnd_drop_performed, // Version 3
1133     data_source_handle_dnd_finished,       // Version 3
1134     data_source_handle_action,             // Version 3
1135 };
1136 
1137 SDL_WaylandDataSource*
Wayland_data_source_create(_THIS)1138 Wayland_data_source_create(_THIS)
1139 {
1140     SDL_WaylandDataSource *data_source = NULL;
1141     SDL_VideoData *driver_data = NULL;
1142     struct wl_data_source *id = NULL;
1143 
1144     if (_this == NULL || _this->driverdata == NULL) {
1145         SDL_SetError("Video driver uninitialized");
1146     } else {
1147         driver_data = _this->driverdata;
1148 
1149         if (driver_data->data_device_manager != NULL) {
1150             id = wl_data_device_manager_create_data_source(
1151                      driver_data->data_device_manager);
1152         }
1153 
1154         if (id == NULL) {
1155             SDL_SetError("Wayland unable to create data source");
1156         } else {
1157             data_source = SDL_calloc(1, sizeof *data_source);
1158             if (data_source == NULL) {
1159                 SDL_OutOfMemory();
1160                 wl_data_source_destroy(id);
1161             } else {
1162                 WAYLAND_wl_list_init(&(data_source->mimes));
1163                 data_source->source = id;
1164                 wl_data_source_set_user_data(id, data_source);
1165                 wl_data_source_add_listener(id, &data_source_listener,
1166                                             data_source);
1167             }
1168         }
1169     }
1170     return data_source;
1171 }
1172 
1173 static void
data_offer_handle_offer(void * data,struct wl_data_offer * wl_data_offer,const char * mime_type)1174 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
1175                         const char *mime_type)
1176 {
1177     SDL_WaylandDataOffer *offer = data;
1178     Wayland_data_offer_add_mime(offer, mime_type);
1179 }
1180 
1181 static void
data_offer_handle_source_actions(void * data,struct wl_data_offer * wl_data_offer,uint32_t source_actions)1182 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
1183                                  uint32_t source_actions)
1184 {
1185 }
1186 
1187 static void
data_offer_handle_actions(void * data,struct wl_data_offer * wl_data_offer,uint32_t dnd_action)1188 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
1189                           uint32_t dnd_action)
1190 {
1191 }
1192 
1193 static const struct wl_data_offer_listener data_offer_listener = {
1194     data_offer_handle_offer,
1195     data_offer_handle_source_actions, // Version 3
1196     data_offer_handle_actions,        // Version 3
1197 };
1198 
1199 static void
data_device_handle_data_offer(void * data,struct wl_data_device * wl_data_device,struct wl_data_offer * id)1200 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
1201                               struct wl_data_offer *id)
1202 {
1203     SDL_WaylandDataOffer *data_offer = NULL;
1204 
1205     data_offer = SDL_calloc(1, sizeof *data_offer);
1206     if (data_offer == NULL) {
1207         SDL_OutOfMemory();
1208     } else {
1209         data_offer->offer = id;
1210         data_offer->data_device = data;
1211         WAYLAND_wl_list_init(&(data_offer->mimes));
1212         wl_data_offer_set_user_data(id, data_offer);
1213         wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
1214     }
1215 }
1216 
1217 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)1218 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
1219                          uint32_t serial, struct wl_surface *surface,
1220                          wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
1221 {
1222     SDL_WaylandDataDevice *data_device = data;
1223     SDL_bool has_mime = SDL_FALSE;
1224     uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
1225 
1226     data_device->drag_serial = serial;
1227 
1228     if (id != NULL) {
1229         data_device->drag_offer = wl_data_offer_get_user_data(id);
1230 
1231         /* TODO: SDL Support more mime types */
1232         has_mime = Wayland_data_offer_has_mime(
1233             data_device->drag_offer, FILE_MIME);
1234 
1235         /* If drag_mime is NULL this will decline the offer */
1236         wl_data_offer_accept(id, serial,
1237                              (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
1238 
1239         /* SDL only supports "copy" style drag and drop */
1240         if (has_mime == SDL_TRUE) {
1241             dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
1242         }
1243         if (wl_data_offer_get_version(data_device->drag_offer->offer) >= 3) {
1244             wl_data_offer_set_actions(data_device->drag_offer->offer,
1245                                       dnd_action, dnd_action);
1246         }
1247     }
1248 }
1249 
1250 static void
data_device_handle_leave(void * data,struct wl_data_device * wl_data_device)1251 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
1252 {
1253     SDL_WaylandDataDevice *data_device = data;
1254     SDL_WaylandDataOffer *offer = NULL;
1255 
1256     if (data_device->selection_offer != NULL) {
1257         data_device->selection_offer = NULL;
1258         Wayland_data_offer_destroy(offer);
1259     }
1260 }
1261 
1262 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)1263 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
1264                           uint32_t time, wl_fixed_t x, wl_fixed_t y)
1265 {
1266 }
1267 
1268 static void
data_device_handle_drop(void * data,struct wl_data_device * wl_data_device)1269 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
1270 {
1271     SDL_WaylandDataDevice *data_device = data;
1272     void *buffer = NULL;
1273     size_t length = 0;
1274 
1275     const char *current_uri = NULL;
1276     const char *last_char = NULL;
1277     char *current_char = NULL;
1278 
1279     if (data_device->drag_offer != NULL) {
1280         /* TODO: SDL Support more mime types */
1281         buffer = Wayland_data_offer_receive(data_device->drag_offer,
1282                                             &length, FILE_MIME, SDL_FALSE);
1283 
1284         /* uri-list */
1285         current_uri = (const char *)buffer;
1286         last_char = (const char *)buffer + length;
1287         for (current_char = buffer; current_char < last_char; ++current_char) {
1288             if (*current_char == '\n' || *current_char == 0) {
1289                 if (*current_uri != 0 && *current_uri != '#') {
1290                     *current_char = 0;
1291                     SDL_SendDropFile(NULL, current_uri);
1292                 }
1293                 current_uri = (const char *)current_char + 1;
1294             }
1295         }
1296 
1297         SDL_free(buffer);
1298     }
1299 }
1300 
1301 static void
data_device_handle_selection(void * data,struct wl_data_device * wl_data_device,struct wl_data_offer * id)1302 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
1303                              struct wl_data_offer *id)
1304 {
1305     SDL_WaylandDataDevice *data_device = data;
1306     SDL_WaylandDataOffer *offer = NULL;
1307 
1308     if (id != NULL) {
1309         offer = wl_data_offer_get_user_data(id);
1310     }
1311 
1312     if (data_device->selection_offer != offer) {
1313         Wayland_data_offer_destroy(data_device->selection_offer);
1314         data_device->selection_offer = offer;
1315     }
1316 
1317     SDL_SendClipboardUpdate();
1318 }
1319 
1320 static const struct wl_data_device_listener data_device_listener = {
1321     data_device_handle_data_offer,
1322     data_device_handle_enter,
1323     data_device_handle_leave,
1324     data_device_handle_motion,
1325     data_device_handle_drop,
1326     data_device_handle_selection
1327 };
1328 
1329 static void
text_input_enter(void * data,struct zwp_text_input_v3 * zwp_text_input_v3,struct wl_surface * surface)1330 text_input_enter(void *data,
1331                  struct zwp_text_input_v3 *zwp_text_input_v3,
1332                  struct wl_surface *surface)
1333 {
1334     /* No-op */
1335 }
1336 
1337 static void
text_input_leave(void * data,struct zwp_text_input_v3 * zwp_text_input_v3,struct wl_surface * surface)1338 text_input_leave(void *data,
1339                  struct zwp_text_input_v3 *zwp_text_input_v3,
1340                  struct wl_surface *surface)
1341 {
1342     /* No-op */
1343 }
1344 
1345 static void
text_input_preedit_string(void * data,struct zwp_text_input_v3 * zwp_text_input_v3,const char * text,int32_t cursor_begin,int32_t cursor_end)1346 text_input_preedit_string(void *data,
1347                           struct zwp_text_input_v3 *zwp_text_input_v3,
1348                           const char *text,
1349                           int32_t cursor_begin,
1350                           int32_t cursor_end)
1351 {
1352     char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
1353     if (text) {
1354         size_t text_bytes = SDL_strlen(text), i = 0;
1355         size_t cursor = 0;
1356 
1357         do {
1358             const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
1359             const size_t chars = SDL_utf8strlen(buf);
1360 
1361             SDL_SendEditingText(buf, cursor, chars);
1362 
1363             i += sz;
1364             cursor += chars;
1365         } while (i < text_bytes);
1366     } else {
1367         buf[0] = '\0';
1368         SDL_SendEditingText(buf, 0, 0);
1369     }
1370 }
1371 
1372 static void
text_input_commit_string(void * data,struct zwp_text_input_v3 * zwp_text_input_v3,const char * text)1373 text_input_commit_string(void *data,
1374                          struct zwp_text_input_v3 *zwp_text_input_v3,
1375                          const char *text)
1376 {
1377     if (text && *text) {
1378         char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
1379         size_t text_bytes = SDL_strlen(text), i = 0;
1380 
1381         while (i < text_bytes) {
1382             size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
1383             SDL_SendKeyboardText(buf);
1384 
1385             i += sz;
1386         }
1387     }
1388 }
1389 
1390 static void
text_input_delete_surrounding_text(void * data,struct zwp_text_input_v3 * zwp_text_input_v3,uint32_t before_length,uint32_t after_length)1391 text_input_delete_surrounding_text(void *data,
1392                                    struct zwp_text_input_v3 *zwp_text_input_v3,
1393                                    uint32_t before_length,
1394                                    uint32_t after_length)
1395 {
1396     /* FIXME: Do we care about this event? */
1397 }
1398 
1399 static void
text_input_done(void * data,struct zwp_text_input_v3 * zwp_text_input_v3,uint32_t serial)1400 text_input_done(void *data,
1401                 struct zwp_text_input_v3 *zwp_text_input_v3,
1402                 uint32_t serial)
1403 {
1404     /* No-op */
1405 }
1406 
1407 static const struct zwp_text_input_v3_listener text_input_listener = {
1408     text_input_enter,
1409     text_input_leave,
1410     text_input_preedit_string,
1411     text_input_commit_string,
1412     text_input_delete_surrounding_text,
1413     text_input_done
1414 };
1415 
1416 static void
Wayland_create_data_device(SDL_VideoData * d)1417 Wayland_create_data_device(SDL_VideoData *d)
1418 {
1419     SDL_WaylandDataDevice *data_device = NULL;
1420 
1421     data_device = SDL_calloc(1, sizeof *data_device);
1422     if (data_device == NULL) {
1423         return;
1424     }
1425 
1426     data_device->data_device = wl_data_device_manager_get_data_device(
1427         d->data_device_manager, d->input->seat
1428     );
1429     data_device->video_data = d;
1430 
1431     if (data_device->data_device == NULL) {
1432         SDL_free(data_device);
1433     } else {
1434         wl_data_device_set_user_data(data_device->data_device, data_device);
1435         wl_data_device_add_listener(data_device->data_device,
1436                                     &data_device_listener, data_device);
1437         d->input->data_device = data_device;
1438     }
1439 }
1440 
1441 static void
Wayland_create_text_input(SDL_VideoData * d)1442 Wayland_create_text_input(SDL_VideoData *d)
1443 {
1444     SDL_WaylandTextInput *text_input = NULL;
1445 
1446     text_input = SDL_calloc(1, sizeof *text_input);
1447     if (text_input == NULL) {
1448         return;
1449     }
1450 
1451     text_input->text_input = zwp_text_input_manager_v3_get_text_input(
1452         d->text_input_manager, d->input->seat
1453     );
1454 
1455     if (text_input->text_input == NULL) {
1456         SDL_free(text_input);
1457     } else {
1458         zwp_text_input_v3_set_user_data(text_input->text_input, text_input);
1459         zwp_text_input_v3_add_listener(text_input->text_input,
1460                                        &text_input_listener, text_input);
1461         d->input->text_input = text_input;
1462     }
1463 }
1464 
1465 void
Wayland_add_data_device_manager(SDL_VideoData * d,uint32_t id,uint32_t version)1466 Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
1467 {
1468     d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, SDL_min(3, version));
1469 
1470     if (d->input != NULL) {
1471         Wayland_create_data_device(d);
1472     }
1473 }
1474 
1475 void
Wayland_add_text_input_manager(SDL_VideoData * d,uint32_t id,uint32_t version)1476 Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
1477 {
1478     d->text_input_manager = wl_registry_bind(d->registry, id, &zwp_text_input_manager_v3_interface, 1);
1479 
1480     if (d->input != NULL) {
1481         Wayland_create_text_input(d);
1482     }
1483 }
1484 
1485 void
Wayland_display_add_input(SDL_VideoData * d,uint32_t id,uint32_t version)1486 Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
1487 {
1488     struct SDL_WaylandInput *input;
1489 
1490     input = SDL_calloc(1, sizeof *input);
1491     if (input == NULL)
1492         return;
1493 
1494     input->display = d;
1495     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
1496     input->sx_w = wl_fixed_from_int(0);
1497     input->sy_w = wl_fixed_from_int(0);
1498     d->input = input;
1499 
1500     if (d->data_device_manager != NULL) {
1501         Wayland_create_data_device(d);
1502     }
1503     if (d->text_input_manager != NULL) {
1504         Wayland_create_text_input(d);
1505     }
1506 
1507     wl_seat_add_listener(input->seat, &seat_listener, input);
1508     wl_seat_set_user_data(input->seat, input);
1509 
1510     WAYLAND_wl_display_flush(d->display);
1511 }
1512 
Wayland_display_destroy_input(SDL_VideoData * d)1513 void Wayland_display_destroy_input(SDL_VideoData *d)
1514 {
1515     struct SDL_WaylandInput *input = d->input;
1516 
1517     if (!input)
1518         return;
1519 
1520     if (input->data_device != NULL) {
1521         Wayland_data_device_clear_selection(input->data_device);
1522         if (input->data_device->selection_offer != NULL) {
1523             Wayland_data_offer_destroy(input->data_device->selection_offer);
1524         }
1525         if (input->data_device->drag_offer != NULL) {
1526             Wayland_data_offer_destroy(input->data_device->drag_offer);
1527         }
1528         if (input->data_device->data_device != NULL) {
1529             wl_data_device_release(input->data_device->data_device);
1530         }
1531         SDL_free(input->data_device);
1532     }
1533 
1534     if (input->text_input != NULL) {
1535         zwp_text_input_v3_destroy(input->text_input->text_input);
1536         SDL_free(input->text_input);
1537     }
1538 
1539     if (input->keyboard)
1540         wl_keyboard_destroy(input->keyboard);
1541 
1542     if (input->pointer)
1543         wl_pointer_destroy(input->pointer);
1544 
1545     if (input->touch) {
1546         SDL_DelTouch(1);
1547         wl_touch_destroy(input->touch);
1548     }
1549 
1550     if (input->seat)
1551         wl_seat_destroy(input->seat);
1552 
1553     if (input->xkb.compose_state)
1554         WAYLAND_xkb_compose_state_unref(input->xkb.compose_state);
1555 
1556     if (input->xkb.compose_table)
1557         WAYLAND_xkb_compose_table_unref(input->xkb.compose_table);
1558 
1559     if (input->xkb.state)
1560         WAYLAND_xkb_state_unref(input->xkb.state);
1561 
1562     if (input->xkb.keymap)
1563         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
1564 
1565     SDL_free(input);
1566     d->input = NULL;
1567 }
1568 
1569 /* !!! FIXME: just merge these into display_handle_global(). */
Wayland_display_add_relative_pointer_manager(SDL_VideoData * d,uint32_t id)1570 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
1571 {
1572     d->relative_pointer_manager =
1573         wl_registry_bind(d->registry, id,
1574                          &zwp_relative_pointer_manager_v1_interface, 1);
1575 }
1576 
Wayland_display_destroy_relative_pointer_manager(SDL_VideoData * d)1577 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
1578 {
1579     if (d->relative_pointer_manager)
1580         zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
1581 }
1582 
Wayland_display_add_pointer_constraints(SDL_VideoData * d,uint32_t id)1583 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
1584 {
1585     d->pointer_constraints =
1586         wl_registry_bind(d->registry, id,
1587                          &zwp_pointer_constraints_v1_interface, 1);
1588 }
1589 
Wayland_display_destroy_pointer_constraints(SDL_VideoData * d)1590 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
1591 {
1592     if (d->pointer_constraints)
1593         zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
1594 }
1595 
1596 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)1597 relative_pointer_handle_relative_motion(void *data,
1598                                         struct zwp_relative_pointer_v1 *pointer,
1599                                         uint32_t time_hi,
1600                                         uint32_t time_lo,
1601                                         wl_fixed_t dx_w,
1602                                         wl_fixed_t dy_w,
1603                                         wl_fixed_t dx_unaccel_w,
1604                                         wl_fixed_t dy_unaccel_w)
1605 {
1606     struct SDL_WaylandInput *input = data;
1607     SDL_VideoData *d = input->display;
1608     SDL_WindowData *window = input->pointer_focus;
1609     double dx_unaccel;
1610     double dy_unaccel;
1611     double dx;
1612     double dy;
1613 
1614     dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
1615     dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
1616 
1617     /* Add left over fraction from last event. */
1618     dx_unaccel += input->dx_frac;
1619     dy_unaccel += input->dy_frac;
1620 
1621     input->dx_frac = modf(dx_unaccel, &dx);
1622     input->dy_frac = modf(dy_unaccel, &dy);
1623 
1624     if (input->pointer_focus && d->relative_mouse_mode) {
1625         SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
1626     }
1627 }
1628 
1629 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
1630     relative_pointer_handle_relative_motion,
1631 };
1632 
1633 static void
locked_pointer_locked(void * data,struct zwp_locked_pointer_v1 * locked_pointer)1634 locked_pointer_locked(void *data,
1635                       struct zwp_locked_pointer_v1 *locked_pointer)
1636 {
1637 }
1638 
1639 static void
locked_pointer_unlocked(void * data,struct zwp_locked_pointer_v1 * locked_pointer)1640 locked_pointer_unlocked(void *data,
1641                         struct zwp_locked_pointer_v1 *locked_pointer)
1642 {
1643 }
1644 
1645 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
1646     locked_pointer_locked,
1647     locked_pointer_unlocked,
1648 };
1649 
1650 static void
lock_pointer_to_window(SDL_Window * window,struct SDL_WaylandInput * input)1651 lock_pointer_to_window(SDL_Window *window,
1652                        struct SDL_WaylandInput *input)
1653 {
1654     SDL_WindowData *w = window->driverdata;
1655     SDL_VideoData *d = input->display;
1656     struct zwp_locked_pointer_v1 *locked_pointer;
1657 
1658     if (w->locked_pointer)
1659         return;
1660 
1661     locked_pointer =
1662         zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
1663                                                 w->surface,
1664                                                 input->pointer,
1665                                                 NULL,
1666                                                 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1667     zwp_locked_pointer_v1_add_listener(locked_pointer,
1668                                        &locked_pointer_listener,
1669                                        window);
1670 
1671     w->locked_pointer = locked_pointer;
1672 }
1673 
pointer_confine_destroy(SDL_Window * window)1674 static void pointer_confine_destroy(SDL_Window *window)
1675 {
1676     SDL_WindowData *w = window->driverdata;
1677     if (w->confined_pointer) {
1678         zwp_confined_pointer_v1_destroy(w->confined_pointer);
1679         w->confined_pointer = NULL;
1680     }
1681 }
1682 
Wayland_input_lock_pointer(struct SDL_WaylandInput * input)1683 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
1684 {
1685     SDL_VideoDevice *vd = SDL_GetVideoDevice();
1686     SDL_VideoData *d = input->display;
1687     SDL_Window *window;
1688     struct zwp_relative_pointer_v1 *relative_pointer;
1689 
1690     if (!d->relative_pointer_manager)
1691         return -1;
1692 
1693     if (!d->pointer_constraints)
1694         return -1;
1695 
1696     if (!input->pointer)
1697         return -1;
1698 
1699     /* If we have a pointer confine active, we must destroy it here because
1700      * creating a locked pointer otherwise would be a protocol error. */
1701     for (window = vd->windows; window; window = window->next)
1702         pointer_confine_destroy(window);
1703 
1704     if (!input->relative_pointer) {
1705         relative_pointer =
1706             zwp_relative_pointer_manager_v1_get_relative_pointer(
1707                 d->relative_pointer_manager,
1708                 input->pointer);
1709         zwp_relative_pointer_v1_add_listener(relative_pointer,
1710                                              &relative_pointer_listener,
1711                                              input);
1712         input->relative_pointer = relative_pointer;
1713     }
1714 
1715     for (window = vd->windows; window; window = window->next)
1716         lock_pointer_to_window(window, input);
1717 
1718     d->relative_mouse_mode = 1;
1719 
1720     return 0;
1721 }
1722 
Wayland_input_unlock_pointer(struct SDL_WaylandInput * input)1723 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
1724 {
1725     SDL_VideoDevice *vd = SDL_GetVideoDevice();
1726     SDL_VideoData *d = input->display;
1727     SDL_Window *window;
1728     SDL_WindowData *w;
1729 
1730     for (window = vd->windows; window; window = window->next) {
1731         w = window->driverdata;
1732         if (w->locked_pointer)
1733             zwp_locked_pointer_v1_destroy(w->locked_pointer);
1734         w->locked_pointer = NULL;
1735     }
1736 
1737     zwp_relative_pointer_v1_destroy(input->relative_pointer);
1738     input->relative_pointer = NULL;
1739 
1740     d->relative_mouse_mode = 0;
1741 
1742     for (window = vd->windows; window; window = window->next)
1743         Wayland_input_confine_pointer(input, window);
1744 
1745     return 0;
1746 }
1747 
1748 static void
confined_pointer_confined(void * data,struct zwp_confined_pointer_v1 * confined_pointer)1749 confined_pointer_confined(void *data,
1750                           struct zwp_confined_pointer_v1 *confined_pointer)
1751 {
1752 }
1753 
1754 static void
confined_pointer_unconfined(void * data,struct zwp_confined_pointer_v1 * confined_pointer)1755 confined_pointer_unconfined(void *data,
1756                             struct zwp_confined_pointer_v1 *confined_pointer)
1757 {
1758 }
1759 
1760 static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
1761     confined_pointer_confined,
1762     confined_pointer_unconfined,
1763 };
1764 
Wayland_input_confine_pointer(struct SDL_WaylandInput * input,SDL_Window * window)1765 int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *window)
1766 {
1767     SDL_WindowData *w = window->driverdata;
1768     SDL_VideoData *d = input->display;
1769     struct zwp_confined_pointer_v1 *confined_pointer;
1770     struct wl_region *confine_rect;
1771 
1772     if (!d->pointer_constraints)
1773         return -1;
1774 
1775     if (!input->pointer)
1776         return -1;
1777 
1778     /* A confine may already be active, in which case we should destroy it and
1779      * create a new one. */
1780     pointer_confine_destroy(window);
1781 
1782     /* We cannot create a confine if the pointer is already locked. Defer until
1783      * the pointer is unlocked. */
1784     if (d->relative_mouse_mode)
1785         return 0;
1786 
1787     if (SDL_RectEmpty(&window->mouse_rect)) {
1788         confine_rect = NULL;
1789     } else {
1790         confine_rect = wl_compositor_create_region(d->compositor);
1791         wl_region_add(confine_rect,
1792                       window->mouse_rect.x,
1793                       window->mouse_rect.y,
1794                       window->mouse_rect.w,
1795                       window->mouse_rect.h);
1796     }
1797 
1798     confined_pointer =
1799         zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
1800                                                    w->surface,
1801                                                    input->pointer,
1802                                                    confine_rect,
1803                                                    ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1804     zwp_confined_pointer_v1_add_listener(confined_pointer,
1805                                          &confined_pointer_listener,
1806                                          window);
1807 
1808     if (confine_rect != NULL) {
1809         wl_region_destroy(confine_rect);
1810     }
1811 
1812     w->confined_pointer = confined_pointer;
1813     return 0;
1814 }
1815 
Wayland_input_unconfine_pointer(struct SDL_WaylandInput * input,SDL_Window * window)1816 int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input, SDL_Window *window)
1817 {
1818     pointer_confine_destroy(window);
1819     return 0;
1820 }
1821 
Wayland_input_grab_keyboard(SDL_Window * window,struct SDL_WaylandInput * input)1822 int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input)
1823 {
1824     SDL_WindowData *w = window->driverdata;
1825     SDL_VideoData *d = input->display;
1826 
1827     if (!d->key_inhibitor_manager)
1828         return -1;
1829 
1830     if (w->key_inhibitor)
1831         return 0;
1832 
1833     w->key_inhibitor =
1834         zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(d->key_inhibitor_manager,
1835                                                                     w->surface,
1836                                                                     input->seat);
1837 
1838     return 0;
1839 }
1840 
Wayland_input_ungrab_keyboard(SDL_Window * window)1841 int Wayland_input_ungrab_keyboard(SDL_Window *window)
1842 {
1843     SDL_WindowData *w = window->driverdata;
1844 
1845     if (w->key_inhibitor) {
1846         zwp_keyboard_shortcuts_inhibitor_v1_destroy(w->key_inhibitor);
1847         w->key_inhibitor = NULL;
1848     }
1849 
1850     return 0;
1851 }
1852 
1853 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
1854 
1855 /* vi: set ts=4 sw=4 expandtab: */
1856