22 #include "../../SDL_internal.h"
24 #if SDL_VIDEO_DRIVER_WAYLAND
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"
41 #include "pointer-constraints-unstable-v1-client-protocol.h"
42 #include "relative-pointer-unstable-v1-client-protocol.h"
43 #include "xdg-shell-client-protocol.h"
44 #include "xdg-shell-unstable-v6-client-protocol.h"
46 #include <linux/input.h>
47 #include <sys/select.h>
51 #include <xkbcommon/xkbcommon.h>
53 struct SDL_WaylandInput {
57 struct wl_touch *touch;
58 struct wl_keyboard *keyboard;
60 struct zwp_relative_pointer_v1 *relative_pointer;
72 struct xkb_keymap *keymap;
73 struct xkb_state *
state;
77 struct SDL_WaylandTouchPoint {
83 struct SDL_WaylandTouchPoint* prev;
84 struct SDL_WaylandTouchPoint* next;
87 struct SDL_WaylandTouchPointList {
88 struct SDL_WaylandTouchPoint*
head;
89 struct SDL_WaylandTouchPoint*
tail;
92 static struct SDL_WaylandTouchPointList touch_points = {
NULL,
NULL};
97 struct SDL_WaylandTouchPoint* tp =
SDL_malloc(
sizeof(
struct SDL_WaylandTouchPoint));
104 if (touch_points.tail) {
105 touch_points.tail->next = tp;
106 tp->prev = touch_points.tail;
108 touch_points.head = tp;
112 touch_points.tail = tp;
119 struct SDL_WaylandTouchPoint* tp = touch_points.head;
134 struct SDL_WaylandTouchPoint* tp = touch_points.head;
142 tp->prev->next = tp->next;
144 touch_points.head = tp->next;
148 tp->next->prev = tp->prev;
150 touch_points.tail = tp->prev;
160 static struct wl_surface*
163 struct SDL_WaylandTouchPoint* tp = touch_points.head;
181 WAYLAND_wl_display_flush(
d->display);
184 WAYLAND_wl_display_dispatch(
d->display);
188 WAYLAND_wl_display_dispatch_pending(
d->display);
193 pointer_handle_enter(
void *
data,
struct wl_pointer *
pointer,
195 wl_fixed_t sx_w, wl_fixed_t sy_w)
220 pointer_handle_leave(
void *
data,
struct wl_pointer *
pointer,
225 if (
input->pointer_focus) {
232 pointer_handle_motion(
void *
data,
struct wl_pointer *
pointer,
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);
247 ProcessHitTest(
struct SDL_WaylandInput *
input,
uint32_t serial)
256 static const uint32_t directions_wl[] = {
257 WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP,
258 WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT,
259 WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM,
260 WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT
265 const uint32_t *directions_zxdg = directions_wl;
269 if (
input->display->shell.xdg) {
271 }
else if (
input->display->shell.zxdg) {
286 if (
input->display->shell.xdg) {
288 }
else if (
input->display->shell.zxdg) {
303 pointer_handle_button_common(
struct SDL_WaylandInput *
input,
uint32_t serial,
307 enum wl_pointer_button_state
state = state_w;
310 if (
input->pointer_focus) {
314 if (ProcessHitTest(
input, serial)) {
351 pointer_handle_axis_common(
struct SDL_WaylandInput *
input,
355 enum wl_pointer_axis
a =
axis;
358 if (
input->pointer_focus) {
360 case WL_POINTER_AXIS_VERTICAL_SCROLL:
362 y = 0 - (float)wl_fixed_to_double(
value);
364 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
365 x = 0 - (float)wl_fixed_to_double(
value);
377 pointer_handle_axis(
void *
data,
struct wl_pointer *
pointer,
385 static const struct wl_pointer_listener pointer_listener = {
386 pointer_handle_enter,
387 pointer_handle_leave,
388 pointer_handle_motion,
389 pointer_handle_button,
398 touch_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)
403 const double dblx = wl_fixed_to_double(fx);
404 const double dbly = wl_fixed_to_double(fy);
414 touch_handler_up(
void *
data,
struct wl_touch *touch,
unsigned int serial,
415 unsigned int timestamp,
int id)
419 touch_del(
id, &
x, &
y);
424 touch_handler_motion(
void *
data,
struct wl_touch *touch,
unsigned int timestamp,
425 int id, wl_fixed_t fx, wl_fixed_t fy)
428 const double dblx = wl_fixed_to_double(fx);
429 const double dbly = wl_fixed_to_double(fy);
433 touch_update(
id,
x,
y);
438 touch_handler_frame(
void *
data,
struct wl_touch *touch)
444 touch_handler_cancel(
void *
data,
struct wl_touch *touch)
449 static const struct wl_touch_listener touch_listener = {
452 touch_handler_motion,
454 touch_handler_cancel,
460 keyboard_handle_keymap(
void *
data,
struct wl_keyboard *keyboard,
471 if (
format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
476 map_str = mmap(
NULL,
size, PROT_READ, MAP_SHARED,
fd, 0);
477 if (map_str == MAP_FAILED) {
482 input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(
input->display->xkb_context,
484 XKB_KEYMAP_FORMAT_TEXT_V1,
486 munmap(map_str,
size);
489 if (!
input->xkb.keymap) {
490 fprintf(stderr,
"failed to compile keymap\n");
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);
504 keyboard_handle_enter(
void *
data,
struct wl_keyboard *keyboard,
506 struct wl_array *keys)
526 keyboard_handle_leave(
void *
data,
struct wl_keyboard *keyboard,
533 keyboard_handle_key(
void *
data,
struct wl_keyboard *keyboard,
539 enum wl_keyboard_key_state
state = state_w;
540 const xkb_keysym_t *syms;
558 if (WAYLAND_xkb_state_key_get_syms(
input->xkb.state,
key + 8, &syms) != 1)
562 size = WAYLAND_xkb_keysym_to_utf8(syms[0],
text,
sizeof text);
575 keyboard_handle_modifiers(
void *
data,
struct wl_keyboard *keyboard,
582 WAYLAND_xkb_state_update_mask(
input->xkb.state, mods_depressed, mods_latched,
583 mods_locked, 0, 0,
group);
586 static const struct wl_keyboard_listener keyboard_listener = {
587 keyboard_handle_keymap,
588 keyboard_handle_enter,
589 keyboard_handle_leave,
591 keyboard_handle_modifiers,
596 seat_handle_capabilities(
void *
data,
struct wl_seat *seat,
597 enum wl_seat_capability caps)
601 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !
input->pointer) {
602 input->pointer = wl_seat_get_pointer(seat);
604 wl_pointer_set_user_data(
input->pointer,
input);
605 wl_pointer_add_listener(
input->pointer, &pointer_listener,
607 }
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) &&
input->pointer) {
608 wl_pointer_destroy(
input->pointer);
613 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !
input->touch) {
615 input->touch = wl_seat_get_touch(seat);
617 wl_touch_add_listener(
input->touch, &touch_listener,
619 }
else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) &&
input->touch) {
621 wl_touch_destroy(
input->touch);
625 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !
input->keyboard) {
626 input->keyboard = wl_seat_get_keyboard(seat);
627 wl_keyboard_set_user_data(
input->keyboard,
input);
628 wl_keyboard_add_listener(
input->keyboard, &keyboard_listener,
630 }
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) &&
input->keyboard) {
631 wl_keyboard_destroy(
input->keyboard);
636 static const struct wl_seat_listener seat_listener = {
637 seat_handle_capabilities,
642 data_source_handle_target(
void *
data,
struct wl_data_source *wl_data_source,
643 const char *mime_type)
648 data_source_handle_send(
void *
data,
struct wl_data_source *wl_data_source,
655 data_source_handle_cancelled(
void *
data,
struct wl_data_source *wl_data_source)
661 data_source_handle_dnd_drop_performed(
void *
data,
struct wl_data_source *wl_data_source)
666 data_source_handle_dnd_finished(
void *
data,
struct wl_data_source *wl_data_source)
671 data_source_handle_action(
void *
data,
struct wl_data_source *wl_data_source,
676 static 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,
681 data_source_handle_dnd_finished,
682 data_source_handle_action,
690 struct wl_data_source *
id =
NULL;
698 id = wl_data_device_manager_create_data_source(
705 data_source =
SDL_calloc(1,
sizeof *data_source);
706 if (data_source ==
NULL) {
708 wl_data_source_destroy(
id);
710 WAYLAND_wl_list_init(&(data_source->
mimes));
712 wl_data_source_set_user_data(
id, data_source);
713 wl_data_source_add_listener(
id, &data_source_listener,
722 data_offer_handle_offer(
void *
data,
struct wl_data_offer *wl_data_offer,
723 const char *mime_type)
730 data_offer_handle_source_actions(
void *
data,
struct wl_data_offer *wl_data_offer,
736 data_offer_handle_actions(
void *
data,
struct wl_data_offer *wl_data_offer,
741 static const struct wl_data_offer_listener data_offer_listener = {
742 data_offer_handle_offer,
743 data_offer_handle_source_actions,
744 data_offer_handle_actions,
748 data_device_handle_data_offer(
void *
data,
struct wl_data_device *wl_data_device,
749 struct wl_data_offer *
id)
753 data_offer =
SDL_calloc(1,
sizeof *data_offer);
754 if (data_offer ==
NULL) {
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);
766 data_device_handle_enter(
void *
data,
struct wl_data_device *wl_data_device,
768 wl_fixed_t
x, wl_fixed_t
y,
struct wl_data_offer *
id)
772 uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
777 data_device->
drag_offer = wl_data_offer_get_user_data(
id);
784 wl_data_offer_accept(
id, serial,
789 dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
792 dnd_action, dnd_action);
797 data_device_handle_leave(
void *
data,
struct wl_data_device *wl_data_device)
809 data_device_handle_motion(
void *
data,
struct wl_data_device *wl_data_device,
815 data_device_handle_drop(
void *
data,
struct wl_data_device *wl_data_device)
821 const char *current_uri =
NULL;
822 const char *last_char =
NULL;
823 char *current_char =
NULL;
831 current_uri = (
const char *)
buffer;
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 !=
'#') {
839 current_uri = (
const char *)current_char + 1;
848 data_device_handle_selection(
void *
data,
struct wl_data_device *wl_data_device,
849 struct wl_data_offer *
id)
855 offer = wl_data_offer_get_user_data(
id);
866 static 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
878 struct SDL_WaylandInput *
input;
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);
891 if (
d->data_device_manager !=
NULL) {
892 data_device =
SDL_calloc(1,
sizeof *data_device);
893 if (data_device ==
NULL) {
897 data_device->
data_device = wl_data_device_manager_get_data_device(
898 d->data_device_manager,
input->seat
905 wl_data_device_set_user_data(data_device->
data_device, data_device);
906 wl_data_device_add_listener(data_device->
data_device,
907 &data_device_listener, data_device);
908 input->data_device = data_device;
912 wl_seat_add_listener(
input->seat, &seat_listener,
input);
915 WAYLAND_wl_display_flush(
d->display);
920 struct SDL_WaylandInput *
input =
d->input;
927 if (
input->data_device->selection_offer !=
NULL) {
930 if (
input->data_device->drag_offer !=
NULL) {
933 if (
input->data_device->data_device !=
NULL) {
934 wl_data_device_release(
input->data_device->data_device);
940 wl_keyboard_destroy(
input->keyboard);
943 wl_pointer_destroy(
input->pointer);
947 wl_touch_destroy(
input->touch);
951 wl_seat_destroy(
input->seat);
953 if (
input->xkb.state)
954 WAYLAND_xkb_state_unref(
input->xkb.state);
956 if (
input->xkb.keymap)
957 WAYLAND_xkb_keymap_unref(
input->xkb.keymap);
969 return input->data_device;
975 d->relative_pointer_manager =
976 wl_registry_bind(
d->registry,
id,
977 &zwp_relative_pointer_manager_v1_interface, 1);
982 if (
d->relative_pointer_manager)
983 zwp_relative_pointer_manager_v1_destroy(
d->relative_pointer_manager);
988 d->pointer_constraints =
989 wl_registry_bind(
d->registry,
id,
990 &zwp_pointer_constraints_v1_interface, 1);
995 if (
d->pointer_constraints)
996 zwp_pointer_constraints_v1_destroy(
d->pointer_constraints);
1000 relative_pointer_handle_relative_motion(
void *
data,
1001 struct zwp_relative_pointer_v1 *
pointer,
1006 wl_fixed_t dx_unaccel_w,
1007 wl_fixed_t dy_unaccel_w)
1017 dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
1018 dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
1021 dx_unaccel +=
input->dx_frac;
1022 dy_unaccel +=
input->dy_frac;
1024 input->dx_frac = modf(dx_unaccel, &dx);
1025 input->dy_frac = modf(dy_unaccel, &dy);
1027 if (
input->pointer_focus &&
d->relative_mouse_mode) {
1032 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
1033 relative_pointer_handle_relative_motion,
1037 locked_pointer_locked(
void *
data,
1038 struct zwp_locked_pointer_v1 *locked_pointer)
1043 locked_pointer_unlocked(
void *
data,
1044 struct zwp_locked_pointer_v1 *locked_pointer)
1048 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
1049 locked_pointer_locked,
1050 locked_pointer_unlocked,
1055 struct SDL_WaylandInput *
input)
1059 struct zwp_locked_pointer_v1 *locked_pointer;
1061 if (
w->locked_pointer)
1065 zwp_pointer_constraints_v1_lock_pointer(
d->pointer_constraints,
1069 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
1070 zwp_locked_pointer_v1_add_listener(locked_pointer,
1071 &locked_pointer_listener,
1074 w->locked_pointer = locked_pointer;
1082 struct zwp_relative_pointer_v1 *relative_pointer;
1084 if (!
d->relative_pointer_manager)
1087 if (!
d->pointer_constraints)
1090 if (!
input->pointer)
1093 if (!
input->relative_pointer) {
1095 zwp_relative_pointer_manager_v1_get_relative_pointer(
1096 d->relative_pointer_manager,
1098 zwp_relative_pointer_v1_add_listener(relative_pointer,
1099 &relative_pointer_listener,
1101 input->relative_pointer = relative_pointer;
1107 d->relative_mouse_mode = 1;
1121 if (
w->locked_pointer)
1122 zwp_locked_pointer_v1_destroy(
w->locked_pointer);
1123 w->locked_pointer =
NULL;
1126 zwp_relative_pointer_v1_destroy(
input->relative_pointer);
1129 d->relative_mouse_mode = 0;