SDL 2.0
SDL_waylandevents.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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 "../../core/unix/SDL_poll.h"
31#include "../../events/SDL_sysevents.h"
32#include "../../events/SDL_events_c.h"
33#include "../../events/scancodes_xfree86.h"
34
35#include "SDL_waylandvideo.h"
36#include "SDL_waylandevents_c.h"
37#include "SDL_waylandwindow.h"
38
39#include "SDL_waylanddyn.h"
40
45
46#include <linux/input.h>
47#include <sys/select.h>
48#include <sys/mman.h>
49#include <poll.h>
50#include <unistd.h>
51#include <xkbcommon/xkbcommon.h>
52
53struct SDL_WaylandInput {
54 SDL_VideoData *display;
55 struct wl_seat *seat;
56 struct wl_pointer *pointer;
57 struct wl_touch *touch;
58 struct wl_keyboard *keyboard;
59 SDL_WaylandDataDevice *data_device;
60 struct zwp_relative_pointer_v1 *relative_pointer;
61 SDL_WindowData *pointer_focus;
62 SDL_WindowData *keyboard_focus;
63
64 /* Last motion location */
65 wl_fixed_t sx_w;
66 wl_fixed_t sy_w;
67
68 double dx_frac;
69 double dy_frac;
70
71 struct {
72 struct xkb_keymap *keymap;
73 struct xkb_state *state;
74 } xkb;
75};
76
77struct SDL_WaylandTouchPoint {
79 float x;
80 float y;
81 struct wl_surface* surface;
82
83 struct SDL_WaylandTouchPoint* prev;
84 struct SDL_WaylandTouchPoint* next;
85};
86
87struct SDL_WaylandTouchPointList {
88 struct SDL_WaylandTouchPoint* head;
89 struct SDL_WaylandTouchPoint* tail;
90};
91
92static struct SDL_WaylandTouchPointList touch_points = {NULL, NULL};
93
94static void
95touch_add(SDL_TouchID id, float x, float y, struct wl_surface *surface)
96{
97 struct SDL_WaylandTouchPoint* tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
98
99 tp->id = id;
100 tp->x = x;
101 tp->y = y;
102 tp->surface = surface;
103
104 if (touch_points.tail) {
105 touch_points.tail->next = tp;
106 tp->prev = touch_points.tail;
107 } else {
108 touch_points.head = tp;
109 tp->prev = NULL;
110 }
111
112 touch_points.tail = tp;
113 tp->next = NULL;
114}
115
116static void
117touch_update(SDL_TouchID id, float x, float y)
118{
119 struct SDL_WaylandTouchPoint* tp = touch_points.head;
120
121 while (tp) {
122 if (tp->id == id) {
123 tp->x = x;
124 tp->y = y;
125 }
126
127 tp = tp->next;
128 }
129}
130
131static void
132touch_del(SDL_TouchID id, float* x, float* y)
133{
134 struct SDL_WaylandTouchPoint* tp = touch_points.head;
135
136 while (tp) {
137 if (tp->id == id) {
138 *x = tp->x;
139 *y = tp->y;
140
141 if (tp->prev) {
142 tp->prev->next = tp->next;
143 } else {
144 touch_points.head = tp->next;
145 }
146
147 if (tp->next) {
148 tp->next->prev = tp->prev;
149 } else {
150 touch_points.tail = tp->prev;
151 }
152
153 SDL_free(tp);
154 }
155
156 tp = tp->next;
157 }
158}
159
160static struct wl_surface*
161touch_surface(SDL_TouchID id)
162{
163 struct SDL_WaylandTouchPoint* tp = touch_points.head;
164
165 while (tp) {
166 if (tp->id == id) {
167 return tp->surface;
168 }
169
170 tp = tp->next;
171 }
172
173 return NULL;
174}
175
176void
178{
180
181 WAYLAND_wl_display_flush(d->display);
182
183 if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
184 WAYLAND_wl_display_dispatch(d->display);
185 }
186 else
187 {
188 WAYLAND_wl_display_dispatch_pending(d->display);
189 }
190}
191
192static void
193pointer_handle_enter(void *data, struct wl_pointer *pointer,
194 uint32_t serial, struct wl_surface *surface,
195 wl_fixed_t sx_w, wl_fixed_t sy_w)
196{
197 struct SDL_WaylandInput *input = data;
199
200 if (!surface) {
201 /* enter event for a window we've just destroyed */
202 return;
203 }
204
205 /* This handler will be called twice in Wayland 1.4
206 * Once for the window surface which has valid user data
207 * and again for the mouse cursor surface which does not have valid user data
208 * We ignore the later
209 */
210
212
213 if (window) {
214 input->pointer_focus = window;
215 SDL_SetMouseFocus(window->sdlwindow);
216 }
217}
218
219static void
220pointer_handle_leave(void *data, struct wl_pointer *pointer,
221 uint32_t serial, struct wl_surface *surface)
222{
223 struct SDL_WaylandInput *input = data;
224
225 if (input->pointer_focus) {
227 input->pointer_focus = NULL;
228 }
229}
230
231static void
232pointer_handle_motion(void *data, struct wl_pointer *pointer,
233 uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
234{
235 struct SDL_WaylandInput *input = data;
236 SDL_WindowData *window = input->pointer_focus;
237 input->sx_w = sx_w;
238 input->sy_w = sy_w;
239 if (input->pointer_focus) {
240 const int sx = wl_fixed_to_int(sx_w);
241 const int sy = wl_fixed_to_int(sy_w);
242 SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
243 }
244}
245
246static SDL_bool
247ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
248{
249 SDL_WindowData *window_data = input->pointer_focus;
250 SDL_Window *window = window_data->sdlwindow;
251
252 if (window->hit_test) {
253 const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) };
254 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
255
256 static const uint32_t directions_wl[] = {
261 };
262
263 /* the names are different (ZXDG_TOPLEVEL_V6_RESIZE_EDGE_* vs
264 WL_SHELL_SURFACE_RESIZE_*), but the values are the same. */
265 const uint32_t *directions_zxdg = directions_wl;
266
267 switch (rc) {
269 if (input->display->shell.xdg) {
270 xdg_toplevel_move(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial);
271 } else if (input->display->shell.zxdg) {
272 zxdg_toplevel_v6_move(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial);
273 } else {
274 wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial);
275 }
276 return SDL_TRUE;
277
286 if (input->display->shell.xdg) {
287 xdg_toplevel_resize(window_data->shell_surface.xdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
288 } else if (input->display->shell.zxdg) {
289 zxdg_toplevel_v6_resize(window_data->shell_surface.zxdg.roleobj.toplevel, input->seat, serial, directions_zxdg[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
290 } else {
291 wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions_wl[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
292 }
293 return SDL_TRUE;
294
295 default: return SDL_FALSE;
296 }
297 }
298
299 return SDL_FALSE;
300}
301
302static void
303pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
305{
306 SDL_WindowData *window = input->pointer_focus;
307 enum wl_pointer_button_state state = state_w;
308 uint32_t sdl_button;
309
310 if (input->pointer_focus) {
311 switch (button) {
312 case BTN_LEFT:
313 sdl_button = SDL_BUTTON_LEFT;
314 if (ProcessHitTest(input, serial)) {
315 return; /* don't pass this event on to app. */
316 }
317 break;
318 case BTN_MIDDLE:
319 sdl_button = SDL_BUTTON_MIDDLE;
320 break;
321 case BTN_RIGHT:
322 sdl_button = SDL_BUTTON_RIGHT;
323 break;
324 case BTN_SIDE:
325 sdl_button = SDL_BUTTON_X1;
326 break;
327 case BTN_EXTRA:
328 sdl_button = SDL_BUTTON_X2;
329 break;
330 default:
331 return;
332 }
333
334 Wayland_data_device_set_serial(input->data_device, serial);
335
336 SDL_SendMouseButton(window->sdlwindow, 0,
337 state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
338 }
339}
340
341static void
342pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
344{
345 struct SDL_WaylandInput *input = data;
346
347 pointer_handle_button_common(input, serial, time, button, state_w);
348}
349
350static void
351pointer_handle_axis_common(struct SDL_WaylandInput *input,
352 uint32_t time, uint32_t axis, wl_fixed_t value)
353{
354 SDL_WindowData *window = input->pointer_focus;
355 enum wl_pointer_axis a = axis;
356 float x, y;
357
358 if (input->pointer_focus) {
359 switch (a) {
361 x = 0;
362 y = 0 - (float)wl_fixed_to_double(value);
363 break;
365 x = 0 - (float)wl_fixed_to_double(value);
366 y = 0;
367 break;
368 default:
369 return;
370 }
371
373 }
374}
375
376static void
377pointer_handle_axis(void *data, struct wl_pointer *pointer,
378 uint32_t time, uint32_t axis, wl_fixed_t value)
379{
380 struct SDL_WaylandInput *input = data;
381
382 pointer_handle_axis_common(input, time, axis, value);
383}
384
385static const struct wl_pointer_listener pointer_listener = {
386 pointer_handle_enter,
387 pointer_handle_leave,
388 pointer_handle_motion,
389 pointer_handle_button,
390 pointer_handle_axis,
391 NULL, /* frame */
392 NULL, /* axis_source */
393 NULL, /* axis_stop */
394 NULL, /* axis_discrete */
395};
396
397static void
398touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
399 unsigned int timestamp, struct wl_surface *surface,
400 int id, wl_fixed_t fx, wl_fixed_t fy)
401{
403 const double dblx = wl_fixed_to_double(fx);
404 const double dbly = wl_fixed_to_double(fy);
405 const float x = dblx / window_data->sdlwindow->w;
406 const float y = dbly / window_data->sdlwindow->h;
407
408 touch_add(id, x, y, surface);
409
410 SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f);
411}
412
413static void
414touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
415 unsigned int timestamp, int id)
416{
417 float x = 0, y = 0;
418
419 touch_del(id, &x, &y);
420 SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f);
421}
422
423static void
424touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
425 int id, wl_fixed_t fx, wl_fixed_t fy)
426{
427 SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
428 const double dblx = wl_fixed_to_double(fx);
429 const double dbly = wl_fixed_to_double(fy);
430 const float x = dblx / window_data->sdlwindow->w;
431 const float y = dbly / window_data->sdlwindow->h;
432
433 touch_update(id, x, y);
434 SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f);
435}
436
437static void
438touch_handler_frame(void *data, struct wl_touch *touch)
439{
440
441}
442
443static void
444touch_handler_cancel(void *data, struct wl_touch *touch)
445{
446
447}
448
449static const struct wl_touch_listener touch_listener = {
450 touch_handler_down,
451 touch_handler_up,
452 touch_handler_motion,
453 touch_handler_frame,
454 touch_handler_cancel,
455 NULL, /* shape */
456 NULL, /* orientation */
457};
458
459static void
460keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
462{
463 struct SDL_WaylandInput *input = data;
464 char *map_str;
465
466 if (!data) {
467 close(fd);
468 return;
469 }
470
472 close(fd);
473 return;
474 }
475
476 map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
477 if (map_str == MAP_FAILED) {
478 close(fd);
479 return;
480 }
481
482 input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
483 map_str,
484 XKB_KEYMAP_FORMAT_TEXT_V1,
485 0);
486 munmap(map_str, size);
487 close(fd);
488
489 if (!input->xkb.keymap) {
490 fprintf(stderr, "failed to compile keymap\n");
491 return;
492 }
493
494 input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
495 if (!input->xkb.state) {
496 fprintf(stderr, "failed to create XKB state\n");
497 WAYLAND_xkb_keymap_unref(input->xkb.keymap);
498 input->xkb.keymap = NULL;
499 return;
500 }
501}
502
503static void
504keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
505 uint32_t serial, struct wl_surface *surface,
506 struct wl_array *keys)
507{
508 struct SDL_WaylandInput *input = data;
510
511 if (!surface) {
512 /* enter event for a window we've just destroyed */
513 return;
514 }
515
517
518 if (window) {
519 input->keyboard_focus = window;
520 window->keyboard_device = input;
521 SDL_SetKeyboardFocus(window->sdlwindow);
522 }
523}
524
525static void
526keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
527 uint32_t serial, struct wl_surface *surface)
528{
530}
531
532static void
533keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
535 uint32_t state_w)
536{
537 struct SDL_WaylandInput *input = data;
538 SDL_WindowData *window = input->keyboard_focus;
539 enum wl_keyboard_key_state state = state_w;
540 const xkb_keysym_t *syms;
541 uint32_t scancode;
542 char text[8];
543 int size;
544
546 scancode = xfree86_scancode_table2[key];
547
548 // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
549 if (scancode != SDL_SCANCODE_UNKNOWN)
551 SDL_PRESSED : SDL_RELEASED, scancode);
552 }
553
554 if (!window || window->keyboard_device != input || !input->xkb.state)
555 return;
556
557 // TODO can this happen?
558 if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
559 return;
560
561 if (state) {
562 size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
563
564 if (size > 0) {
565 text[size] = 0;
566
567 Wayland_data_device_set_serial(input->data_device, serial);
568
570 }
571 }
572}
573
574static void
575keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
576 uint32_t serial, uint32_t mods_depressed,
577 uint32_t mods_latched, uint32_t mods_locked,
579{
580 struct SDL_WaylandInput *input = data;
581
582 WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
583 mods_locked, 0, 0, group);
584}
585
586static const struct wl_keyboard_listener keyboard_listener = {
587 keyboard_handle_keymap,
588 keyboard_handle_enter,
589 keyboard_handle_leave,
590 keyboard_handle_key,
591 keyboard_handle_modifiers,
592 NULL, /* repeat_info */
593};
594
595static void
596seat_handle_capabilities(void *data, struct wl_seat *seat,
597 enum wl_seat_capability caps)
598{
599 struct SDL_WaylandInput *input = data;
600
601 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
602 input->pointer = wl_seat_get_pointer(seat);
603 input->display->pointer = input->pointer;
605 wl_pointer_add_listener(input->pointer, &pointer_listener,
606 input);
607 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
608 wl_pointer_destroy(input->pointer);
609 input->pointer = NULL;
610 input->display->pointer = NULL;
611 }
612
613 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
614 SDL_AddTouch(1, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
615 input->touch = wl_seat_get_touch(seat);
617 wl_touch_add_listener(input->touch, &touch_listener,
618 input);
619 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
620 SDL_DelTouch(1);
621 wl_touch_destroy(input->touch);
622 input->touch = NULL;
623 }
624
625 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
626 input->keyboard = wl_seat_get_keyboard(seat);
628 wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
629 input);
630 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
631 wl_keyboard_destroy(input->keyboard);
632 input->keyboard = NULL;
633 }
634}
635
636static const struct wl_seat_listener seat_listener = {
637 seat_handle_capabilities,
638 NULL, /* name */
639};
640
641static void
642data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
643 const char *mime_type)
644{
645}
646
647static void
648data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
649 const char *mime_type, int32_t fd)
650{
652}
653
654static void
655data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
656{
658}
659
660static void
661data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
662{
663}
664
665static void
666data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
667{
668}
669
670static void
671data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
672 uint32_t dnd_action)
673{
674}
675
676static const struct wl_data_source_listener data_source_listener = {
677 data_source_handle_target,
678 data_source_handle_send,
679 data_source_handle_cancelled,
680 data_source_handle_dnd_drop_performed, // Version 3
681 data_source_handle_dnd_finished, // Version 3
682 data_source_handle_action, // Version 3
683};
684
687{
688 SDL_WaylandDataSource *data_source = NULL;
689 SDL_VideoData *driver_data = NULL;
690 struct wl_data_source *id = NULL;
691
692 if (_this == NULL || _this->driverdata == NULL) {
693 SDL_SetError("Video driver uninitialized");
694 } else {
695 driver_data = _this->driverdata;
696
697 if (driver_data->data_device_manager != NULL) {
699 driver_data->data_device_manager);
700 }
701
702 if (id == NULL) {
703 SDL_SetError("Wayland unable to create data source");
704 } else {
705 data_source = SDL_calloc(1, sizeof *data_source);
706 if (data_source == NULL) {
709 } else {
710 WAYLAND_wl_list_init(&(data_source->mimes));
711 data_source->source = id;
712 wl_data_source_set_user_data(id, data_source);
713 wl_data_source_add_listener(id, &data_source_listener,
714 data_source);
715 }
716 }
717 }
718 return data_source;
719}
720
721static void
722data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
723 const char *mime_type)
724{
725 SDL_WaylandDataOffer *offer = data;
726 Wayland_data_offer_add_mime(offer, mime_type);
727}
728
729static void
730data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
731 uint32_t source_actions)
732{
733}
734
735static void
736data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
737 uint32_t dnd_action)
738{
739}
740
741static const struct wl_data_offer_listener data_offer_listener = {
742 data_offer_handle_offer,
743 data_offer_handle_source_actions, // Version 3
744 data_offer_handle_actions, // Version 3
745};
746
747static void
748data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
749 struct wl_data_offer *id)
750{
751 SDL_WaylandDataOffer *data_offer = NULL;
752
753 data_offer = SDL_calloc(1, sizeof *data_offer);
754 if (data_offer == NULL) {
756 } else {
757 data_offer->offer = id;
758 data_offer->data_device = data;
759 WAYLAND_wl_list_init(&(data_offer->mimes));
760 wl_data_offer_set_user_data(id, data_offer);
761 wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
762 }
763}
764
765static void
766data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
767 uint32_t serial, struct wl_surface *surface,
768 wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
769{
770 SDL_WaylandDataDevice *data_device = data;
771 SDL_bool has_mime = SDL_FALSE;
773
774 data_device->drag_serial = serial;
775
776 if (id != NULL) {
777 data_device->drag_offer = wl_data_offer_get_user_data(id);
778
779 /* TODO: SDL Support more mime types */
781 data_device->drag_offer, FILE_MIME);
782
783 /* If drag_mime is NULL this will decline the offer */
784 wl_data_offer_accept(id, serial,
785 (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
786
787 /* SDL only supports "copy" style drag and drop */
788 if (has_mime == SDL_TRUE) {
790 }
792 dnd_action, dnd_action);
793 }
794}
795
796static void
797data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
798{
799 SDL_WaylandDataDevice *data_device = data;
801
802 if (data_device->selection_offer != NULL) {
803 data_device->selection_offer = NULL;
805 }
806}
807
808static void
809data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
810 uint32_t time, wl_fixed_t x, wl_fixed_t y)
811{
812}
813
814static void
815data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
816{
817 SDL_WaylandDataDevice *data_device = data;
818 void *buffer = NULL;
819 size_t length = 0;
820
821 const char *current_uri = NULL;
822 const char *last_char = NULL;
823 char *current_char = NULL;
824
825 if (data_device->drag_offer != NULL) {
826 /* TODO: SDL Support more mime types */
829
830 /* uri-list */
831 current_uri = (const char *)buffer;
832 last_char = (const char *)buffer + length;
833 for (current_char = buffer; current_char < last_char; ++current_char) {
834 if (*current_char == '\n' || *current_char == 0) {
835 if (*current_uri != 0 && *current_uri != '#') {
836 *current_char = 0;
837 SDL_SendDropFile(NULL, current_uri);
838 }
839 current_uri = (const char *)current_char + 1;
840 }
841 }
842
844 }
845}
846
847static void
848data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
849 struct wl_data_offer *id)
850{
851 SDL_WaylandDataDevice *data_device = data;
853
854 if (id != NULL) {
856 }
857
858 if (data_device->selection_offer != offer) {
860 data_device->selection_offer = offer;
861 }
862
864}
865
866static const struct wl_data_device_listener data_device_listener = {
867 data_device_handle_data_offer,
868 data_device_handle_enter,
869 data_device_handle_leave,
870 data_device_handle_motion,
871 data_device_handle_drop,
872 data_device_handle_selection
873};
874
875void
877{
878 struct SDL_WaylandInput *input;
879 SDL_WaylandDataDevice *data_device = NULL;
880
881 input = SDL_calloc(1, sizeof *input);
882 if (input == NULL)
883 return;
884
885 input->display = d;
886 input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
887 input->sx_w = wl_fixed_from_int(0);
888 input->sy_w = wl_fixed_from_int(0);
889 d->input = input;
890
891 if (d->data_device_manager != NULL) {
892 data_device = SDL_calloc(1, sizeof *data_device);
893 if (data_device == NULL) {
894 return;
895 }
896
898 d->data_device_manager, input->seat
899 );
900 data_device->video_data = d;
901
902 if (data_device->data_device == NULL) {
903 SDL_free(data_device);
904 } else {
905 wl_data_device_set_user_data(data_device->data_device, data_device);
907 &data_device_listener, data_device);
908 input->data_device = data_device;
909 }
910 }
911
912 wl_seat_add_listener(input->seat, &seat_listener, input);
914
915 WAYLAND_wl_display_flush(d->display);
916}
917
919{
920 struct SDL_WaylandInput *input = d->input;
921
922 if (!input)
923 return;
924
925 if (input->data_device != NULL) {
927 if (input->data_device->selection_offer != NULL) {
928 Wayland_data_offer_destroy(input->data_device->selection_offer);
929 }
930 if (input->data_device->drag_offer != NULL) {
931 Wayland_data_offer_destroy(input->data_device->drag_offer);
932 }
933 if (input->data_device->data_device != NULL) {
934 wl_data_device_release(input->data_device->data_device);
935 }
936 SDL_free(input->data_device);
937 }
938
939 if (input->keyboard)
940 wl_keyboard_destroy(input->keyboard);
941
942 if (input->pointer)
943 wl_pointer_destroy(input->pointer);
944
945 if (input->touch) {
946 SDL_DelTouch(1);
947 wl_touch_destroy(input->touch);
948 }
949
950 if (input->seat)
951 wl_seat_destroy(input->seat);
952
953 if (input->xkb.state)
954 WAYLAND_xkb_state_unref(input->xkb.state);
955
956 if (input->xkb.keymap)
957 WAYLAND_xkb_keymap_unref(input->xkb.keymap);
958
960 d->input = NULL;
961}
962
963SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
964{
965 if (input == NULL) {
966 return NULL;
967 }
968
969 return input->data_device;
970}
971
972/* !!! FIXME: just merge these into display_handle_global(). */
974{
975 d->relative_pointer_manager =
976 wl_registry_bind(d->registry, id,
978}
979
981{
982 if (d->relative_pointer_manager)
983 zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager);
984}
985
987{
988 d->pointer_constraints =
989 wl_registry_bind(d->registry, id,
991}
992
994{
995 if (d->pointer_constraints)
996 zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
997}
998
999static void
1000relative_pointer_handle_relative_motion(void *data,
1001 struct zwp_relative_pointer_v1 *pointer,
1002 uint32_t time_hi,
1003 uint32_t time_lo,
1004 wl_fixed_t dx_w,
1005 wl_fixed_t dy_w,
1006 wl_fixed_t dx_unaccel_w,
1007 wl_fixed_t dy_unaccel_w)
1008{
1009 struct SDL_WaylandInput *input = data;
1010 SDL_VideoData *d = input->display;
1011 SDL_WindowData *window = input->pointer_focus;
1012 double dx_unaccel;
1013 double dy_unaccel;
1014 double dx;
1015 double dy;
1016
1017 dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
1018 dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
1019
1020 /* Add left over fraction from last event. */
1021 dx_unaccel += input->dx_frac;
1022 dy_unaccel += input->dy_frac;
1023
1024 input->dx_frac = modf(dx_unaccel, &dx);
1025 input->dy_frac = modf(dy_unaccel, &dy);
1026
1027 if (input->pointer_focus && d->relative_mouse_mode) {
1028 SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
1029 }
1030}
1031
1032static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
1033 relative_pointer_handle_relative_motion,
1034};
1035
1036static void
1037locked_pointer_locked(void *data,
1038 struct zwp_locked_pointer_v1 *locked_pointer)
1039{
1040}
1041
1042static void
1043locked_pointer_unlocked(void *data,
1044 struct zwp_locked_pointer_v1 *locked_pointer)
1045{
1046}
1047
1048static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
1049 locked_pointer_locked,
1050 locked_pointer_unlocked,
1051};
1052
1053static void
1054lock_pointer_to_window(SDL_Window *window,
1055 struct SDL_WaylandInput *input)
1056{
1057 SDL_WindowData *w = window->driverdata;
1058 SDL_VideoData *d = input->display;
1059 struct zwp_locked_pointer_v1 *locked_pointer;
1060
1061 if (w->locked_pointer)
1062 return;
1063
1064 locked_pointer =
1065 zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
1066 w->surface,
1067 input->pointer,
1068 NULL,
1071 &locked_pointer_listener,
1072 window);
1073
1074 w->locked_pointer = locked_pointer;
1075}
1076
1077int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
1078{
1080 SDL_VideoData *d = input->display;
1082 struct zwp_relative_pointer_v1 *relative_pointer;
1083
1084 if (!d->relative_pointer_manager)
1085 return -1;
1086
1087 if (!d->pointer_constraints)
1088 return -1;
1089
1090 if (!input->pointer)
1091 return -1;
1092
1093 if (!input->relative_pointer) {
1094 relative_pointer =
1096 d->relative_pointer_manager,
1097 input->pointer);
1098 zwp_relative_pointer_v1_add_listener(relative_pointer,
1099 &relative_pointer_listener,
1100 input);
1101 input->relative_pointer = relative_pointer;
1102 }
1103
1104 for (window = vd->windows; window; window = window->next)
1105 lock_pointer_to_window(window, input);
1106
1107 d->relative_mouse_mode = 1;
1108
1109 return 0;
1110}
1111
1112int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
1113{
1115 SDL_VideoData *d = input->display;
1118
1119 for (window = vd->windows; window; window = window->next) {
1120 w = window->driverdata;
1121 if (w->locked_pointer)
1122 zwp_locked_pointer_v1_destroy(w->locked_pointer);
1123 w->locked_pointer = NULL;
1124 }
1125
1126 zwp_relative_pointer_v1_destroy(input->relative_pointer);
1127 input->relative_pointer = NULL;
1128
1129 d->relative_mouse_mode = 0;
1130
1131 return 0;
1132}
1133
1134#endif /* SDL_VIDEO_DRIVER_WAYLAND */
1135
1136/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
int SDL_SendClipboardUpdate(void)
unsigned int uint32_t
signed int int32_t
int SDL_SendDropFile(SDL_Window *window, const char *file)
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_calloc
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_EventEntry * head
Definition: SDL_events.c:80
SDL_EventEntry * tail
Definition: SDL_events.c:81
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:605
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:211
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:611
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:301
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
#define SDL_BUTTON_X2
Definition: SDL_mouse.h:286
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:283
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
@ SDL_MOUSEWHEEL_NORMAL
Definition: SDL_mouse.h:68
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLsizei const void * pointer
GLuint id
GLboolean GLboolean GLboolean GLboolean a
GLuint buffer
GLboolean GLuint group
GLsizeiptr size
GLuint GLsizei GLsizei * length
GLsizei const GLfloat * value
GLenum GLenum GLenum input
GLubyte GLubyte GLubyte GLubyte w
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:38
@ SDL_SCANCODE_UNKNOWN
Definition: SDL_scancode.h:45
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:583
void SDL_DelTouch(SDL_TouchID id)
Definition: SDL_touch.c:449
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:364
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
SDL_HitTestResult
Possible return values from the SDL_HitTest callback.
Definition: SDL_video.h:1021
@ SDL_HITTEST_DRAGGABLE
Definition: SDL_video.h:1023
@ SDL_HITTEST_RESIZE_LEFT
Definition: SDL_video.h:1031
@ SDL_HITTEST_RESIZE_TOP
Definition: SDL_video.h:1025
@ SDL_HITTEST_RESIZE_TOPRIGHT
Definition: SDL_video.h:1026
@ SDL_HITTEST_RESIZE_BOTTOM
Definition: SDL_video.h:1029
@ SDL_HITTEST_RESIZE_BOTTOMRIGHT
Definition: SDL_video.h:1028
@ SDL_HITTEST_RESIZE_BOTTOMLEFT
Definition: SDL_video.h:1030
@ SDL_HITTEST_RESIZE_RIGHT
Definition: SDL_video.h:1027
@ SDL_HITTEST_RESIZE_TOPLEFT
Definition: SDL_video.h:1024
void Wayland_data_offer_destroy(SDL_WaylandDataOffer *offer)
ssize_t Wayland_data_source_send(SDL_WaylandDataSource *source, const char *mime_type, int fd)
int Wayland_data_device_clear_selection(SDL_WaylandDataDevice *device)
SDL_WaylandDataSource * Wayland_data_source_create(_THIS)
int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer, const char *mime_type)
void Wayland_data_source_destroy(SDL_WaylandDataSource *source)
SDL_bool Wayland_data_offer_has_mime(SDL_WaylandDataOffer *offer, const char *mime_type)
void * Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, size_t *length, const char *mime_type, SDL_bool null_terminate)
#define FILE_MIME
int Wayland_data_device_set_serial(SDL_WaylandDataDevice *device, uint32_t serial)
int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
void Wayland_display_destroy_input(SDL_VideoData *d)
void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d)
void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d)
void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id)
void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
void Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
SDL_WaylandDataDevice * Wayland_get_data_device(struct SDL_WaylandInput *input)
void Wayland_PumpEvents(_THIS)
struct xkb_state * state
#define NULL
Definition: begin_code.h:167
EGLSurface surface
Definition: eglext.h:248
EGLSurface EGLnsecsANDROID time
Definition: eglext.h:518
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
GLuint64 key
Definition: gl2ext.h:2192
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
static struct wl_data_device * wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat)
static struct wl_data_source * wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager)
@ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY
@ WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE
static void wl_data_device_release(struct wl_data_device *wl_data_device)
static int wl_data_device_add_listener(struct wl_data_device *wl_data_device, const struct wl_data_device_listener *listener, void *data)
static void wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data)
static void wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data)
static int wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer, const struct wl_data_offer_listener *listener, void *data)
static void * wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer)
static void wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type)
static void wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action)
static int wl_data_source_add_listener(struct wl_data_source *wl_data_source, const struct wl_data_source_listener *listener, void *data)
static void wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data)
static void wl_data_source_destroy(struct wl_data_source *wl_data_source)
static void wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data)
static void wl_keyboard_destroy(struct wl_keyboard *wl_keyboard)
static int wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard, const struct wl_keyboard_listener *listener, void *data)
@ WL_KEYBOARD_KEY_STATE_PRESSED
@ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1
static int wl_pointer_add_listener(struct wl_pointer *wl_pointer, const struct wl_pointer_listener *listener, void *data)
static void wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data)
static void wl_pointer_destroy(struct wl_pointer *wl_pointer)
@ WL_POINTER_AXIS_VERTICAL_SCROLL
@ WL_POINTER_AXIS_HORIZONTAL_SCROLL
static void * wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
static int wl_seat_add_listener(struct wl_seat *wl_seat, const struct wl_seat_listener *listener, void *data)
static struct wl_touch * wl_seat_get_touch(struct wl_seat *wl_seat)
static void wl_seat_destroy(struct wl_seat *wl_seat)
static struct wl_pointer * wl_seat_get_pointer(struct wl_seat *wl_seat)
static void wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data)
static struct wl_keyboard * wl_seat_get_keyboard(struct wl_seat *wl_seat)
@ WL_SEAT_CAPABILITY_KEYBOARD
@ WL_SEAT_CAPABILITY_POINTER
@ WL_SEAT_CAPABILITY_TOUCH
static void wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial)
@ WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT
@ WL_SHELL_SURFACE_RESIZE_BOTTOM
@ WL_SHELL_SURFACE_RESIZE_LEFT
@ WL_SHELL_SURFACE_RESIZE_TOP
@ WL_SHELL_SURFACE_RESIZE_RIGHT
@ WL_SHELL_SURFACE_RESIZE_TOP_RIGHT
@ WL_SHELL_SURFACE_RESIZE_TOP_LEFT
@ WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT
static void * wl_surface_get_user_data(struct wl_surface *wl_surface)
static void wl_touch_destroy(struct wl_touch *wl_touch)
static int wl_touch_add_listener(struct wl_touch *wl_touch, const struct wl_touch_listener *listener, void *data)
static void wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data)
static void xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
static void xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
static int zwp_locked_pointer_v1_add_listener(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1, const struct zwp_locked_pointer_v1_listener *listener, void *data)
static void zwp_locked_pointer_v1_destroy(struct zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
static struct zwp_locked_pointer_v1 * zwp_pointer_constraints_v1_lock_pointer(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1, struct wl_surface *surface, struct wl_pointer *pointer, struct wl_region *region, uint32_t lifetime)
static void zwp_pointer_constraints_v1_destroy(struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1)
static struct zwp_relative_pointer_v1 * zwp_relative_pointer_manager_v1_get_relative_pointer(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1, struct wl_pointer *pointer)
static void zwp_relative_pointer_manager_v1_destroy(struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1)
static void zwp_relative_pointer_v1_destroy(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1)
static int zwp_relative_pointer_v1_add_listener(struct zwp_relative_pointer_v1 *zwp_relative_pointer_v1, const struct zwp_relative_pointer_v1_listener *listener, void *data)
static void zxdg_toplevel_v6_resize(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial, uint32_t edges)
static void zxdg_toplevel_v6_move(struct zxdg_toplevel_v6 *zxdg_toplevel_v6, struct wl_seat *seat, uint32_t serial)
const struct wl_interface zwp_pointer_constraints_v1_interface
const struct wl_interface zwp_relative_pointer_manager_v1_interface
static const SDL_Scancode xfree86_scancode_table2[]
The structure that defines a point (integer)
Definition: SDL_rect.h:49
struct wl_data_device_manager * data_device_manager
SDL_Window * windows
Definition: SDL_sysvideo.h:317
SDL_WaylandDataOffer * drag_offer
SDL_WaylandDataOffer * selection_offer
struct wl_data_device * data_device
struct wl_data_offer * offer
struct wl_data_source * source
union SDL_WindowData::@267 shell_surface
SDL_Window * sdlwindow
SDL_xdg_shell_surface xdg
struct wl_shell_surface * wl
SDL_zxdg_shell_surface zxdg
The type used to identify a window.
Definition: SDL_sysvideo.h:74
SDL_Window * next
Definition: SDL_sysvideo.h:114
struct xdg_toplevel * toplevel
union SDL_xdg_shell_surface::@266 roleobj
struct zxdg_toplevel_v6 * toplevel
union SDL_zxdg_shell_surface::@265 roleobj
void(* offer)(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type)
SDL_Texture * button
SDL_Texture * axis
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
const struct wl_interface wl_seat_interface