SDL  2.0
SDL_waylandevents.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 
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 
192 static void
193 pointer_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 
211  window = (SDL_WindowData *)wl_surface_get_user_data(surface);
212 
213  if (window) {
214  input->pointer_focus = window;
215  SDL_SetMouseFocus(window->sdlwindow);
216  }
217 }
218 
219 static void
220 pointer_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 
231 static void
232 pointer_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 
246 static SDL_bool
247 ProcessHitTest(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 
302 static void
303 pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
304  uint32_t time, uint32_t button, uint32_t state_w)
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 
341 static void
342 pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
343  uint32_t time, uint32_t button, uint32_t state_w)
344 {
345  struct SDL_WaylandInput *input = data;
346 
347  pointer_handle_button_common(input, serial, time, button, state_w);
348 }
349 
350 static void
351 pointer_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 
376 static void
377 pointer_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 
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,
390  pointer_handle_axis,
391  NULL, /* frame */
392  NULL, /* axis_source */
393  NULL, /* axis_stop */
394  NULL, /* axis_discrete */
395 };
396 
397 static void
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)
401 {
402  float x, y;
404 
405  window = (SDL_WindowData *)wl_surface_get_user_data(surface);
406 
407  x = wl_fixed_to_double(fx) / window->sdlwindow->w;
408  y = wl_fixed_to_double(fy) / window->sdlwindow->h;
409 
410  touch_add(id, x, y, surface);
411  SDL_SendTouch(1, (SDL_FingerID)id, SDL_TRUE, x, y, 1.0f);
412 }
413 
414 static void
415 touch_handler_up(void *data, struct wl_touch *touch, unsigned int serial,
416  unsigned int timestamp, int id)
417 {
418  float x = 0, y = 0;
419 
420  touch_del(id, &x, &y);
421  SDL_SendTouch(1, (SDL_FingerID)id, SDL_FALSE, x, y, 0.0f);
422 }
423 
424 static void
425 touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
426  int id, wl_fixed_t fx, wl_fixed_t fy)
427 {
428  float x, y;
430 
431  window = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
432 
433  x = wl_fixed_to_double(fx) / window->sdlwindow->w;
434  y = wl_fixed_to_double(fy) / window->sdlwindow->h;
435 
436  touch_update(id, x, y);
437  SDL_SendTouchMotion(1, (SDL_FingerID)id, x, y, 1.0f);
438 }
439 
440 static void
441 touch_handler_frame(void *data, struct wl_touch *touch)
442 {
443 
444 }
445 
446 static void
447 touch_handler_cancel(void *data, struct wl_touch *touch)
448 {
449 
450 }
451 
452 static const struct wl_touch_listener touch_listener = {
453  touch_handler_down,
454  touch_handler_up,
455  touch_handler_motion,
456  touch_handler_frame,
457  touch_handler_cancel,
458  NULL, /* shape */
459  NULL, /* orientation */
460 };
461 
462 static void
463 keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
465 {
466  struct SDL_WaylandInput *input = data;
467  char *map_str;
468 
469  if (!data) {
470  close(fd);
471  return;
472  }
473 
474  if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
475  close(fd);
476  return;
477  }
478 
479  map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
480  if (map_str == MAP_FAILED) {
481  close(fd);
482  return;
483  }
484 
485  input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
486  map_str,
487  XKB_KEYMAP_FORMAT_TEXT_V1,
488  0);
489  munmap(map_str, size);
490  close(fd);
491 
492  if (!input->xkb.keymap) {
493  fprintf(stderr, "failed to compile keymap\n");
494  return;
495  }
496 
497  input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
498  if (!input->xkb.state) {
499  fprintf(stderr, "failed to create XKB state\n");
500  WAYLAND_xkb_keymap_unref(input->xkb.keymap);
501  input->xkb.keymap = NULL;
502  return;
503  }
504 }
505 
506 static void
507 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
508  uint32_t serial, struct wl_surface *surface,
509  struct wl_array *keys)
510 {
511  struct SDL_WaylandInput *input = data;
513 
514  if (!surface) {
515  /* enter event for a window we've just destroyed */
516  return;
517  }
518 
519  window = wl_surface_get_user_data(surface);
520 
521  if (window) {
522  input->keyboard_focus = window;
523  window->keyboard_device = input;
525  }
526 }
527 
528 static void
529 keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
530  uint32_t serial, struct wl_surface *surface)
531 {
533 }
534 
535 static void
536 keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
537  uint32_t serial, uint32_t time, uint32_t key,
538  uint32_t state_w)
539 {
540  struct SDL_WaylandInput *input = data;
541  SDL_WindowData *window = input->keyboard_focus;
542  enum wl_keyboard_key_state state = state_w;
543  const xkb_keysym_t *syms;
544  uint32_t scancode;
545  char text[8];
546  int size;
547 
549  scancode = xfree86_scancode_table2[key];
550 
551  // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
552  if (scancode != SDL_SCANCODE_UNKNOWN)
554  SDL_PRESSED : SDL_RELEASED, scancode);
555  }
556 
557  if (!window || window->keyboard_device != input || !input->xkb.state)
558  return;
559 
560  // TODO can this happen?
561  if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
562  return;
563 
564  if (state) {
565  size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
566 
567  if (size > 0) {
568  text[size] = 0;
569 
570  Wayland_data_device_set_serial(input->data_device, serial);
571 
572  SDL_SendKeyboardText(text);
573  }
574  }
575 }
576 
577 static void
578 keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
579  uint32_t serial, uint32_t mods_depressed,
580  uint32_t mods_latched, uint32_t mods_locked,
581  uint32_t group)
582 {
583  struct SDL_WaylandInput *input = data;
584 
585  WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
586  mods_locked, 0, 0, group);
587 }
588 
589 static const struct wl_keyboard_listener keyboard_listener = {
590  keyboard_handle_keymap,
591  keyboard_handle_enter,
592  keyboard_handle_leave,
593  keyboard_handle_key,
594  keyboard_handle_modifiers,
595  NULL, /* repeat_info */
596 };
597 
598 static void
599 seat_handle_capabilities(void *data, struct wl_seat *seat,
600  enum wl_seat_capability caps)
601 {
602  struct SDL_WaylandInput *input = data;
603 
604  if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
605  input->pointer = wl_seat_get_pointer(seat);
606  input->display->pointer = input->pointer;
607  wl_pointer_set_user_data(input->pointer, input);
608  wl_pointer_add_listener(input->pointer, &pointer_listener,
609  input);
610  } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
611  wl_pointer_destroy(input->pointer);
612  input->pointer = NULL;
613  input->display->pointer = NULL;
614  }
615 
616  if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
617  SDL_AddTouch(1, "wayland_touch");
618  input->touch = wl_seat_get_touch(seat);
619  wl_touch_set_user_data(input->touch, input);
620  wl_touch_add_listener(input->touch, &touch_listener,
621  input);
622  } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
623  SDL_DelTouch(1);
624  wl_touch_destroy(input->touch);
625  input->touch = NULL;
626  }
627 
628  if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
629  input->keyboard = wl_seat_get_keyboard(seat);
630  wl_keyboard_set_user_data(input->keyboard, input);
631  wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
632  input);
633  } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
634  wl_keyboard_destroy(input->keyboard);
635  input->keyboard = NULL;
636  }
637 }
638 
639 static const struct wl_seat_listener seat_listener = {
640  seat_handle_capabilities,
641  NULL, /* name */
642 };
643 
644 static void
645 data_source_handle_target(void *data, struct wl_data_source *wl_data_source,
646  const char *mime_type)
647 {
648 }
649 
650 static void
651 data_source_handle_send(void *data, struct wl_data_source *wl_data_source,
652  const char *mime_type, int32_t fd)
653 {
654  Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
655 }
656 
657 static void
658 data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
659 {
661 }
662 
663 static void
664 data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
665 {
666 }
667 
668 static void
669 data_source_handle_dnd_finished(void *data, struct wl_data_source *wl_data_source)
670 {
671 }
672 
673 static void
674 data_source_handle_action(void *data, struct wl_data_source *wl_data_source,
675  uint32_t dnd_action)
676 {
677 }
678 
679 static const struct wl_data_source_listener data_source_listener = {
680  data_source_handle_target,
681  data_source_handle_send,
682  data_source_handle_cancelled,
683  data_source_handle_dnd_drop_performed, // Version 3
684  data_source_handle_dnd_finished, // Version 3
685  data_source_handle_action, // Version 3
686 };
687 
690 {
691  SDL_WaylandDataSource *data_source = NULL;
692  SDL_VideoData *driver_data = NULL;
693  struct wl_data_source *id = NULL;
694 
695  if (_this == NULL || _this->driverdata == NULL) {
696  SDL_SetError("Video driver uninitialized");
697  } else {
698  driver_data = _this->driverdata;
699 
700  if (driver_data->data_device_manager != NULL) {
702  driver_data->data_device_manager);
703  }
704 
705  if (id == NULL) {
706  SDL_SetError("Wayland unable to create data source");
707  } else {
708  data_source = SDL_calloc(1, sizeof *data_source);
709  if (data_source == NULL) {
710  SDL_OutOfMemory();
712  } else {
713  WAYLAND_wl_list_init(&(data_source->mimes));
714  data_source->source = id;
715  wl_data_source_set_user_data(id, data_source);
716  wl_data_source_add_listener(id, &data_source_listener,
717  data_source);
718  }
719  }
720  }
721  return data_source;
722 }
723 
724 static void
725 data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_offer,
726  const char *mime_type)
727 {
728  SDL_WaylandDataOffer *offer = data;
729  Wayland_data_offer_add_mime(offer, mime_type);
730 }
731 
732 static void
733 data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer,
734  uint32_t source_actions)
735 {
736 }
737 
738 static void
739 data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer,
740  uint32_t dnd_action)
741 {
742 }
743 
744 static const struct wl_data_offer_listener data_offer_listener = {
745  data_offer_handle_offer,
746  data_offer_handle_source_actions, // Version 3
747  data_offer_handle_actions, // Version 3
748 };
749 
750 static void
751 data_device_handle_data_offer(void *data, struct wl_data_device *wl_data_device,
752  struct wl_data_offer *id)
753 {
754  SDL_WaylandDataOffer *data_offer = NULL;
755 
756  data_offer = SDL_calloc(1, sizeof *data_offer);
757  if (data_offer == NULL) {
758  SDL_OutOfMemory();
759  } else {
760  data_offer->offer = id;
761  data_offer->data_device = data;
762  WAYLAND_wl_list_init(&(data_offer->mimes));
763  wl_data_offer_set_user_data(id, data_offer);
764  wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
765  }
766 }
767 
768 static void
769 data_device_handle_enter(void *data, struct wl_data_device *wl_data_device,
770  uint32_t serial, struct wl_surface *surface,
771  wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
772 {
773  SDL_WaylandDataDevice *data_device = data;
774  SDL_bool has_mime = SDL_FALSE;
776 
777  data_device->drag_serial = serial;
778 
779  if (id != NULL) {
780  data_device->drag_offer = wl_data_offer_get_user_data(id);
781 
782  /* TODO: SDL Support more mime types */
783  has_mime = Wayland_data_offer_has_mime(
784  data_device->drag_offer, FILE_MIME);
785 
786  /* If drag_mime is NULL this will decline the offer */
787  wl_data_offer_accept(id, serial,
788  (has_mime == SDL_TRUE) ? FILE_MIME : NULL);
789 
790  /* SDL only supports "copy" style drag and drop */
791  if (has_mime == SDL_TRUE) {
793  }
795  dnd_action, dnd_action);
796  }
797 }
798 
799 static void
800 data_device_handle_leave(void *data, struct wl_data_device *wl_data_device)
801 {
802  SDL_WaylandDataDevice *data_device = data;
804 
805  if (data_device->selection_offer != NULL) {
806  data_device->selection_offer = NULL;
808  }
809 }
810 
811 static void
812 data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
813  uint32_t time, wl_fixed_t x, wl_fixed_t y)
814 {
815 }
816 
817 static void
818 data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
819 {
820  SDL_WaylandDataDevice *data_device = data;
821  void *buffer = NULL;
822  size_t length = 0;
823 
824  const char *current_uri = NULL;
825  const char *last_char = NULL;
826  char *current_char = NULL;
827 
828  if (data_device->drag_offer != NULL) {
829  /* TODO: SDL Support more mime types */
830  buffer = Wayland_data_offer_receive(data_device->drag_offer,
831  &length, FILE_MIME, SDL_FALSE);
832 
833  /* uri-list */
834  current_uri = (const char *)buffer;
835  last_char = (const char *)buffer + length;
836  for (current_char = buffer; current_char < last_char; ++current_char) {
837  if (*current_char == '\n' || *current_char == 0) {
838  if (*current_uri != 0 && *current_uri != '#') {
839  *current_char = 0;
840  SDL_SendDropFile(NULL, current_uri);
841  }
842  current_uri = (const char *)current_char + 1;
843  }
844  }
845 
846  SDL_free(buffer);
847  }
848 }
849 
850 static void
851 data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
852  struct wl_data_offer *id)
853 {
854  SDL_WaylandDataDevice *data_device = data;
855  SDL_WaylandDataOffer *offer = NULL;
856 
857  if (id != NULL) {
858  offer = wl_data_offer_get_user_data(id);
859  }
860 
861  if (data_device->selection_offer != offer) {
863  data_device->selection_offer = offer;
864  }
865 
867 }
868 
869 static const struct wl_data_device_listener data_device_listener = {
870  data_device_handle_data_offer,
871  data_device_handle_enter,
872  data_device_handle_leave,
873  data_device_handle_motion,
874  data_device_handle_drop,
875  data_device_handle_selection
876 };
877 
878 void
880 {
881  struct SDL_WaylandInput *input;
882  SDL_WaylandDataDevice *data_device = NULL;
883 
884  input = SDL_calloc(1, sizeof *input);
885  if (input == NULL)
886  return;
887 
888  input->display = d;
889  input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
890  input->sx_w = wl_fixed_from_int(0);
891  input->sy_w = wl_fixed_from_int(0);
892  d->input = input;
893 
894  if (d->data_device_manager != NULL) {
895  data_device = SDL_calloc(1, sizeof *data_device);
896  if (data_device == NULL) {
897  return;
898  }
899 
901  d->data_device_manager, input->seat
902  );
903  data_device->video_data = d;
904 
905  if (data_device->data_device == NULL) {
906  SDL_free(data_device);
907  } else {
908  wl_data_device_set_user_data(data_device->data_device, data_device);
910  &data_device_listener, data_device);
911  input->data_device = data_device;
912  }
913  }
914 
915  wl_seat_add_listener(input->seat, &seat_listener, input);
916  wl_seat_set_user_data(input->seat, input);
917 
918  WAYLAND_wl_display_flush(d->display);
919 }
920 
922 {
923  struct SDL_WaylandInput *input = d->input;
924 
925  if (!input)
926  return;
927 
928  if (input->data_device != NULL) {
929  Wayland_data_device_clear_selection(input->data_device);
930  if (input->data_device->selection_offer != NULL) {
931  Wayland_data_offer_destroy(input->data_device->selection_offer);
932  }
933  if (input->data_device->drag_offer != NULL) {
934  Wayland_data_offer_destroy(input->data_device->drag_offer);
935  }
936  if (input->data_device->data_device != NULL) {
937  wl_data_device_release(input->data_device->data_device);
938  }
939  SDL_free(input->data_device);
940  }
941 
942  if (input->keyboard)
943  wl_keyboard_destroy(input->keyboard);
944 
945  if (input->pointer)
946  wl_pointer_destroy(input->pointer);
947 
948  if (input->touch) {
949  SDL_DelTouch(1);
950  wl_touch_destroy(input->touch);
951  }
952 
953  if (input->seat)
954  wl_seat_destroy(input->seat);
955 
956  if (input->xkb.state)
957  WAYLAND_xkb_state_unref(input->xkb.state);
958 
959  if (input->xkb.keymap)
960  WAYLAND_xkb_keymap_unref(input->xkb.keymap);
961 
962  SDL_free(input);
963  d->input = NULL;
964 }
965 
966 SDL_WaylandDataDevice* Wayland_get_data_device(struct SDL_WaylandInput *input)
967 {
968  if (input == NULL) {
969  return NULL;
970  }
971 
972  return input->data_device;
973 }
974 
975 /* !!! FIXME: just merge these into display_handle_global(). */
977 {
979  wl_registry_bind(d->registry, id,
981 }
982 
984 {
987 }
988 
990 {
992  wl_registry_bind(d->registry, id,
994 }
995 
997 {
998  if (d->pointer_constraints)
1000 }
1001 
1002 static void
1003 relative_pointer_handle_relative_motion(void *data,
1004  struct zwp_relative_pointer_v1 *pointer,
1005  uint32_t time_hi,
1006  uint32_t time_lo,
1007  wl_fixed_t dx_w,
1008  wl_fixed_t dy_w,
1009  wl_fixed_t dx_unaccel_w,
1010  wl_fixed_t dy_unaccel_w)
1011 {
1012  struct SDL_WaylandInput *input = data;
1013  SDL_VideoData *d = input->display;
1014  SDL_WindowData *window = input->pointer_focus;
1015  double dx_unaccel;
1016  double dy_unaccel;
1017  double dx;
1018  double dy;
1019 
1020  dx_unaccel = wl_fixed_to_double(dx_unaccel_w);
1021  dy_unaccel = wl_fixed_to_double(dy_unaccel_w);
1022 
1023  /* Add left over fraction from last event. */
1024  dx_unaccel += input->dx_frac;
1025  dy_unaccel += input->dy_frac;
1026 
1027  input->dx_frac = modf(dx_unaccel, &dx);
1028  input->dy_frac = modf(dy_unaccel, &dy);
1029 
1030  if (input->pointer_focus && d->relative_mouse_mode) {
1031  SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy);
1032  }
1033 }
1034 
1035 static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
1036  relative_pointer_handle_relative_motion,
1037 };
1038 
1039 static void
1040 locked_pointer_locked(void *data,
1041  struct zwp_locked_pointer_v1 *locked_pointer)
1042 {
1043 }
1044 
1045 static void
1046 locked_pointer_unlocked(void *data,
1047  struct zwp_locked_pointer_v1 *locked_pointer)
1048 {
1049 }
1050 
1051 static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
1052  locked_pointer_locked,
1053  locked_pointer_unlocked,
1054 };
1055 
1056 static void
1057 lock_pointer_to_window(SDL_Window *window,
1058  struct SDL_WaylandInput *input)
1059 {
1060  SDL_WindowData *w = window->driverdata;
1061  SDL_VideoData *d = input->display;
1062  struct zwp_locked_pointer_v1 *locked_pointer;
1063 
1064  if (w->locked_pointer)
1065  return;
1066 
1067  locked_pointer =
1069  w->surface,
1070  input->pointer,
1071  NULL,
1073  zwp_locked_pointer_v1_add_listener(locked_pointer,
1074  &locked_pointer_listener,
1075  window);
1076 
1077  w->locked_pointer = locked_pointer;
1078 }
1079 
1080 int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
1081 {
1083  SDL_VideoData *d = input->display;
1084  SDL_Window *window;
1085  struct zwp_relative_pointer_v1 *relative_pointer;
1086 
1087  if (!d->relative_pointer_manager)
1088  return -1;
1089 
1090  if (!d->pointer_constraints)
1091  return -1;
1092 
1093  if (!input->relative_pointer) {
1094  relative_pointer =
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 
1112 int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input)
1113 {
1115  SDL_VideoData *d = input->display;
1116  SDL_Window *window;
1117  SDL_WindowData *w;
1118 
1119  for (window = vd->windows; window; window = window->next) {
1120  w = window->driverdata;
1121  if (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: */
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
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.
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:222
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
union SDL_zxdg_shell_surface::@36 roleobj
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:177
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:284
void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id)
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
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:263
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:337
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
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 SDL_AddTouch(SDL_TouchID touchID, const char *name)
Definition: SDL_touch.c:136
int Wayland_data_offer_add_mime(SDL_WaylandDataOffer *offer, const char *mime_type)
GLsizeiptr size
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)
union SDL_WindowData::@38 shell_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:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:161
GLuint buffer
SDL_EventEntry * tail
Definition: SDL_events.c:83
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:538
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:586
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:82
GLuint GLsizei GLsizei * length
#define SDL_BUTTON_X2
Definition: SDL_mouse.h:286
struct zwp_pointer_constraints_v1 * pointer_constraints
union SDL_xdg_shell_surface::@37 roleobj
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:532
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)
static void wl_touch_destroy(struct wl_touch *wl_touch)