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