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