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