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