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