• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 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 #include "SDL_log.h"
29 
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 
43 #include <linux/input.h>
44 #include <sys/select.h>
45 #include <sys/mman.h>
46 #include <poll.h>
47 #include <unistd.h>
48 #include <xkbcommon/xkbcommon.h>
49 
50 struct SDL_WaylandInput {
51     SDL_VideoData *display;
52     struct wl_seat *seat;
53     struct wl_pointer *pointer;
54     struct wl_keyboard *keyboard;
55     struct zwp_relative_pointer_v1 *relative_pointer;
56     SDL_WindowData *pointer_focus;
57     SDL_WindowData *keyboard_focus;
58 
59     /* Last motion location */
60     wl_fixed_t sx_w;
61     wl_fixed_t sy_w;
62 
63     double dx_frac;
64     double dy_frac;
65 
66     struct {
67         struct xkb_keymap *keymap;
68         struct xkb_state *state;
69     } xkb;
70 };
71 
72 void
Wayland_PumpEvents(_THIS)73 Wayland_PumpEvents(_THIS)
74 {
75     SDL_VideoData *d = _this->driverdata;
76     struct pollfd pfd[1];
77 
78     pfd[0].fd = WAYLAND_wl_display_get_fd(d->display);
79     pfd[0].events = POLLIN;
80     poll(pfd, 1, 0);
81 
82     if (pfd[0].revents & POLLIN)
83         WAYLAND_wl_display_dispatch(d->display);
84     else
85         WAYLAND_wl_display_dispatch_pending(d->display);
86 }
87 
88 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)89 pointer_handle_enter(void *data, struct wl_pointer *pointer,
90                      uint32_t serial, struct wl_surface *surface,
91                      wl_fixed_t sx_w, wl_fixed_t sy_w)
92 {
93     struct SDL_WaylandInput *input = data;
94     SDL_WindowData *window;
95 
96     if (!surface) {
97         /* enter event for a window we've just destroyed */
98         return;
99     }
100 
101     /* This handler will be called twice in Wayland 1.4
102      * Once for the window surface which has valid user data
103      * and again for the mouse cursor surface which does not have valid user data
104      * We ignore the later
105      */
106 
107     window = (SDL_WindowData *)wl_surface_get_user_data(surface);
108 
109     if (window) {
110         input->pointer_focus = window;
111         SDL_SetMouseFocus(window->sdlwindow);
112     }
113 }
114 
115 static void
pointer_handle_leave(void * data,struct wl_pointer * pointer,uint32_t serial,struct wl_surface * surface)116 pointer_handle_leave(void *data, struct wl_pointer *pointer,
117                      uint32_t serial, struct wl_surface *surface)
118 {
119     struct SDL_WaylandInput *input = data;
120 
121     if (input->pointer_focus) {
122         SDL_SetMouseFocus(NULL);
123         input->pointer_focus = NULL;
124     }
125 }
126 
127 static void
pointer_handle_motion(void * data,struct wl_pointer * pointer,uint32_t time,wl_fixed_t sx_w,wl_fixed_t sy_w)128 pointer_handle_motion(void *data, struct wl_pointer *pointer,
129                       uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
130 {
131     struct SDL_WaylandInput *input = data;
132     SDL_WindowData *window = input->pointer_focus;
133     input->sx_w = sx_w;
134     input->sy_w = sy_w;
135     if (input->pointer_focus) {
136         const int sx = wl_fixed_to_int(sx_w);
137         const int sy = wl_fixed_to_int(sy_w);
138         SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
139     }
140 }
141 
142 static SDL_bool
ProcessHitTest(struct SDL_WaylandInput * input,uint32_t serial)143 ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
144 {
145     SDL_WindowData *window_data = input->pointer_focus;
146     SDL_Window *window = window_data->sdlwindow;
147 
148     if (window->hit_test) {
149         const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
150         const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
151         static const uint32_t directions[] = {
152             WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
153             WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
154             WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
155             WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
156         };
157         switch (rc) {
158             case SDL_HITTEST_DRAGGABLE:
159                 wl_shell_surface_move(window_data->shell_surface, input->seat, serial);
160                 return SDL_TRUE;
161 
162             case SDL_HITTEST_RESIZE_TOPLEFT:
163             case SDL_HITTEST_RESIZE_TOP:
164             case SDL_HITTEST_RESIZE_TOPRIGHT:
165             case SDL_HITTEST_RESIZE_RIGHT:
166             case SDL_HITTEST_RESIZE_BOTTOMRIGHT:
167             case SDL_HITTEST_RESIZE_BOTTOM:
168             case SDL_HITTEST_RESIZE_BOTTOMLEFT:
169             case SDL_HITTEST_RESIZE_LEFT:
170                 wl_shell_surface_resize(window_data->shell_surface, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
171                 return SDL_TRUE;
172 
173             default: return SDL_FALSE;
174         }
175     }
176 
177     return SDL_FALSE;
178 }
179 
180 static void
pointer_handle_button_common(struct SDL_WaylandInput * input,uint32_t serial,uint32_t time,uint32_t button,uint32_t state_w)181 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
182                              uint32_t time, uint32_t button, uint32_t state_w)
183 {
184     SDL_WindowData *window = input->pointer_focus;
185     enum wl_pointer_button_state state = state_w;
186     uint32_t sdl_button;
187 
188     if  (input->pointer_focus) {
189         switch (button) {
190             case BTN_LEFT:
191                 sdl_button = SDL_BUTTON_LEFT;
192                 if (ProcessHitTest(input, serial)) {
193                     return;  /* don't pass this event on to app. */
194                 }
195                 break;
196             case BTN_MIDDLE:
197                 sdl_button = SDL_BUTTON_MIDDLE;
198                 break;
199             case BTN_RIGHT:
200                 sdl_button = SDL_BUTTON_RIGHT;
201                 break;
202             case BTN_SIDE:
203                 sdl_button = SDL_BUTTON_X1;
204                 break;
205             case BTN_EXTRA:
206                 sdl_button = SDL_BUTTON_X2;
207                 break;
208             default:
209                 return;
210         }
211 
212         SDL_SendMouseButton(window->sdlwindow, 0,
213                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
214     }
215 }
216 
217 static void
pointer_handle_button(void * data,struct wl_pointer * pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state_w)218 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
219                       uint32_t time, uint32_t button, uint32_t state_w)
220 {
221     struct SDL_WaylandInput *input = data;
222 
223     pointer_handle_button_common(input, serial, time, button, state_w);
224 }
225 
226 static void
pointer_handle_axis_common(struct SDL_WaylandInput * input,uint32_t time,uint32_t axis,wl_fixed_t value)227 pointer_handle_axis_common(struct SDL_WaylandInput *input,
228                            uint32_t time, uint32_t axis, wl_fixed_t value)
229 {
230     SDL_WindowData *window = input->pointer_focus;
231     enum wl_pointer_axis a = axis;
232     int x, y;
233 
234     if (input->pointer_focus) {
235         switch (a) {
236             case WL_POINTER_AXIS_VERTICAL_SCROLL:
237                 x = 0;
238                 y = wl_fixed_to_int(value);
239                 break;
240             case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
241                 x = wl_fixed_to_int(value);
242                 y = 0;
243                 break;
244             default:
245                 return;
246         }
247 
248         SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
249     }
250 }
251 
252 static void
pointer_handle_axis(void * data,struct wl_pointer * pointer,uint32_t time,uint32_t axis,wl_fixed_t value)253 pointer_handle_axis(void *data, struct wl_pointer *pointer,
254                     uint32_t time, uint32_t axis, wl_fixed_t value)
255 {
256     struct SDL_WaylandInput *input = data;
257 
258     pointer_handle_axis_common(input, time, axis, value);
259 }
260 
261 static const struct wl_pointer_listener pointer_listener = {
262     pointer_handle_enter,
263     pointer_handle_leave,
264     pointer_handle_motion,
265     pointer_handle_button,
266     pointer_handle_axis,
267 };
268 
269 static void
keyboard_handle_keymap(void * data,struct wl_keyboard * keyboard,uint32_t format,int fd,uint32_t size)270 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
271                        uint32_t format, int fd, uint32_t size)
272 {
273     struct SDL_WaylandInput *input = data;
274     char *map_str;
275 
276     if (!data) {
277         close(fd);
278         return;
279     }
280 
281     if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
282         close(fd);
283         return;
284     }
285 
286     map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
287     if (map_str == MAP_FAILED) {
288         close(fd);
289         return;
290     }
291 
292     input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
293                                                 map_str,
294                                                 XKB_KEYMAP_FORMAT_TEXT_V1,
295                                                 0);
296     munmap(map_str, size);
297     close(fd);
298 
299     if (!input->xkb.keymap) {
300         fprintf(stderr, "failed to compile keymap\n");
301         return;
302     }
303 
304     input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
305     if (!input->xkb.state) {
306         fprintf(stderr, "failed to create XKB state\n");
307         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
308         input->xkb.keymap = NULL;
309         return;
310     }
311 }
312 
313 static void
keyboard_handle_enter(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)314 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
315                       uint32_t serial, struct wl_surface *surface,
316                       struct wl_array *keys)
317 {
318     struct SDL_WaylandInput *input = data;
319     SDL_WindowData *window;
320 
321     if (!surface) {
322         /* enter event for a window we've just destroyed */
323         return;
324     }
325 
326     window = wl_surface_get_user_data(surface);
327 
328     if (window) {
329         input->keyboard_focus = window;
330         window->keyboard_device = input;
331         SDL_SetKeyboardFocus(window->sdlwindow);
332     }
333 }
334 
335 static void
keyboard_handle_leave(void * data,struct wl_keyboard * keyboard,uint32_t serial,struct wl_surface * surface)336 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
337                       uint32_t serial, struct wl_surface *surface)
338 {
339     SDL_SetKeyboardFocus(NULL);
340 }
341 
342 static void
keyboard_handle_key(void * data,struct wl_keyboard * keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state_w)343 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
344                     uint32_t serial, uint32_t time, uint32_t key,
345                     uint32_t state_w)
346 {
347     struct SDL_WaylandInput *input = data;
348     SDL_WindowData *window = input->keyboard_focus;
349     enum wl_keyboard_key_state state = state_w;
350     const xkb_keysym_t *syms;
351     uint32_t scancode;
352     char text[8];
353     int size;
354 
355     if (key < SDL_arraysize(xfree86_scancode_table2)) {
356         scancode = xfree86_scancode_table2[key];
357 
358         // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
359         if (scancode != SDL_SCANCODE_UNKNOWN)
360             SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
361                                 SDL_PRESSED : SDL_RELEASED, scancode);
362     }
363 
364     if (!window || window->keyboard_device != input || !input->xkb.state)
365         return;
366 
367     // TODO can this happen?
368     if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
369         return;
370 
371     if (state) {
372         size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
373 
374         if (size > 0) {
375             text[size] = 0;
376             SDL_SendKeyboardText(text);
377         }
378     }
379 }
380 
381 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)382 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
383                           uint32_t serial, uint32_t mods_depressed,
384                           uint32_t mods_latched, uint32_t mods_locked,
385                           uint32_t group)
386 {
387     struct SDL_WaylandInput *input = data;
388 
389     WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
390                           mods_locked, 0, 0, group);
391 }
392 
393 static const struct wl_keyboard_listener keyboard_listener = {
394     keyboard_handle_keymap,
395     keyboard_handle_enter,
396     keyboard_handle_leave,
397     keyboard_handle_key,
398     keyboard_handle_modifiers,
399 };
400 
401 static void
seat_handle_capabilities(void * data,struct wl_seat * seat,enum wl_seat_capability caps)402 seat_handle_capabilities(void *data, struct wl_seat *seat,
403                          enum wl_seat_capability caps)
404 {
405     struct SDL_WaylandInput *input = data;
406 
407     if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
408         input->pointer = wl_seat_get_pointer(seat);
409         input->display->pointer = input->pointer;
410         wl_pointer_set_user_data(input->pointer, input);
411         wl_pointer_add_listener(input->pointer, &pointer_listener,
412                                 input);
413     } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
414         wl_pointer_destroy(input->pointer);
415         input->pointer = NULL;
416     }
417 
418     if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
419         input->keyboard = wl_seat_get_keyboard(seat);
420         wl_keyboard_set_user_data(input->keyboard, input);
421         wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
422                                  input);
423     } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
424         wl_keyboard_destroy(input->keyboard);
425         input->keyboard = NULL;
426     }
427 }
428 
429 static const struct wl_seat_listener seat_listener = {
430     seat_handle_capabilities,
431 };
432 
433 void
Wayland_display_add_input(SDL_VideoData * d,uint32_t id)434 Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
435 {
436     struct SDL_WaylandInput *input;
437 
438     input = SDL_calloc(1, sizeof *input);
439     if (input == NULL)
440         return;
441 
442     input->display = d;
443     input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
444     input->sx_w = wl_fixed_from_int(0);
445     input->sy_w = wl_fixed_from_int(0);
446     d->input = input;
447 
448     wl_seat_add_listener(input->seat, &seat_listener, input);
449     wl_seat_set_user_data(input->seat, input);
450 
451     WAYLAND_wl_display_flush(d->display);
452 }
453 
Wayland_display_destroy_input(SDL_VideoData * d)454 void Wayland_display_destroy_input(SDL_VideoData *d)
455 {
456     struct SDL_WaylandInput *input = d->input;
457 
458     if (!input)
459         return;
460 
461     if (input->keyboard)
462         wl_keyboard_destroy(input->keyboard);
463 
464     if (input->pointer)
465         wl_pointer_destroy(input->pointer);
466 
467     if (input->seat)
468         wl_seat_destroy(input->seat);
469 
470     if (input->xkb.state)
471         WAYLAND_xkb_state_unref(input->xkb.state);
472 
473     if (input->xkb.keymap)
474         WAYLAND_xkb_keymap_unref(input->xkb.keymap);
475 
476     SDL_free(input);
477     d->input = NULL;
478 }
479 
Wayland_display_add_relative_pointer_manager(SDL_VideoData * d,uint32_t id)480 void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
481 {
482     d->relative_pointer_manager =
483         wl_registry_bind(d->registry, id,
484                          &zwp_relative_pointer_manager_v1_interface, 1);
485 }
486 
Wayland_display_destroy_relative_pointer_manager(SDL_VideoData * d)487 void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
488 {
489     if (d->relative_pointer_manager)
490         zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
491 }
492 
Wayland_display_add_pointer_constraints(SDL_VideoData * d,uint32_t id)493 void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
494 {
495     d->pointer_constraints =
496         wl_registry_bind(d->registry, id,
497                          &zwp_pointer_constraints_v1_interface, 1);
498 }
499 
Wayland_display_destroy_pointer_constraints(SDL_VideoData * d)500 void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
501 {
502     if (d->pointer_constraints)
503         zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
504 }
505 
506 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)507 relative_pointer_handle_relative_motion(void *data,
508                                         struct zwp_relative_pointer_v1 *pointer,
509                                         uint32_t time_hi,
510                                         uint32_t time_lo,
511                                         wl_fixed_t dx_w,
512                                         wl_fixed_t dy_w,
513                                         wl_fixed_t dx_unaccel_w,
514                                         wl_fixed_t dy_unaccel_w)
515 {
516     struct SDL_WaylandInput *input = data;
517     SDL_VideoData *d = input->display;
518     SDL_WindowData *window = input->pointer_focus;
519     double dx_unaccel;
520     double dy_unaccel;
521     double dx;
522     double dy;
523 
524     dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
525     dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
526 
527     /* Add left over fraction from last event. */
528     dx_unaccel += input->dx_frac;
529     dy_unaccel += input->dy_frac;
530 
531     input->dx_frac = modf(dx_unaccel, &dx);
532     input->dy_frac = modf(dy_unaccel, &dy);
533 
534     if (input->pointer_focus && d->relative_mouse_mode) {
535         SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
536     }
537 }
538 
539 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
540     relative_pointer_handle_relative_motion,
541 };
542 
543 static void
locked_pointer_locked(void * data,struct zwp_locked_pointer_v1 * locked_pointer)544 locked_pointer_locked(void *data,
545                       struct zwp_locked_pointer_v1 *locked_pointer)
546 {
547 }
548 
549 static void
locked_pointer_unlocked(void * data,struct zwp_locked_pointer_v1 * locked_pointer)550 locked_pointer_unlocked(void *data,
551                         struct zwp_locked_pointer_v1 *locked_pointer)
552 {
553 }
554 
555 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
556     locked_pointer_locked,
557     locked_pointer_unlocked,
558 };
559 
560 static void
lock_pointer_to_window(SDL_Window * window,struct SDL_WaylandInput * input)561 lock_pointer_to_window(SDL_Window *window,
562                        struct SDL_WaylandInput *input)
563 {
564     SDL_WindowData *w = window->driverdata;
565     SDL_VideoData *d = input->display;
566     struct zwp_locked_pointer_v1 *locked_pointer;
567 
568     if (w->locked_pointer)
569         return;
570 
571     locked_pointer =
572         zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
573                                                 w->surface,
574                                                 input->pointer,
575                                                 NULL,
576                                                 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
577     zwp_locked_pointer_v1_add_listener(locked_pointer,
578                                        &locked_pointer_listener,
579                                        window);
580 
581     w->locked_pointer = locked_pointer;
582 }
583 
Wayland_input_lock_pointer(struct SDL_WaylandInput * input)584 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
585 {
586     SDL_VideoDevice *vd = SDL_GetVideoDevice();
587     SDL_VideoData *d = input->display;
588     SDL_Window *window;
589     struct zwp_relative_pointer_v1 *relative_pointer;
590 
591     if (!d->relative_pointer_manager)
592         return -1;
593 
594     if (!d->pointer_constraints)
595         return -1;
596 
597     if (!input->relative_pointer) {
598         relative_pointer =
599             zwp_relative_pointer_manager_v1_get_relative_pointer(
600                 d->relative_pointer_manager,
601                 input->pointer);
602         zwp_relative_pointer_v1_add_listener(relative_pointer,
603                                              &relative_pointer_listener,
604                                              input);
605         input->relative_pointer = relative_pointer;
606     }
607 
608     for (window = vd->windows; window; window = window->next)
609         lock_pointer_to_window(window, input);
610 
611     d->relative_mouse_mode = 1;
612 
613     return 0;
614 }
615 
Wayland_input_unlock_pointer(struct SDL_WaylandInput * input)616 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
617 {
618     SDL_VideoDevice *vd = SDL_GetVideoDevice();
619     SDL_VideoData *d = input->display;
620     SDL_Window *window;
621     SDL_WindowData *w;
622 
623     for (window = vd->windows; window; window = window->next) {
624         w = window->driverdata;
625         if (w->locked_pointer)
626             zwp_locked_pointer_v1_destroy(w->locked_pointer);
627         w->locked_pointer = NULL;
628     }
629 
630     zwp_relative_pointer_v1_destroy(input->relative_pointer);
631     input->relative_pointer = NULL;
632 
633     d->relative_mouse_mode = 0;
634 
635     return 0;
636 }
637 
638 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
639 
640 /* vi: set ts=4 sw=4 expandtab: */
641