1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "gdkdevice-wayland-private.h"
21
22#include "gdkclipboard-wayland.h"
23#include "gdkclipboardprivate.h"
24#include "gdkcursorprivate.h"
25#include "gdkdeviceprivate.h"
26#include "gdkdevicepadprivate.h"
27#include "gdkdevicetoolprivate.h"
28#include "gdkdropprivate.h"
29#include "gdkeventsprivate.h"
30#include "gdkkeysprivate.h"
31#include "gdkkeysyms.h"
32#include "gdkprimary-wayland.h"
33#include "gdkprivate-wayland.h"
34#include "gdkseat-wayland.h"
35#include "gdkseatprivate.h"
36#include "gdksurfaceprivate.h"
37#include "gdktypes.h"
38#include "gdkwayland.h"
39#include "gdk-private.h"
40
41#include "pointer-gestures-unstable-v1-client-protocol.h"
42#include "tablet-unstable-v2-client-protocol.h"
43
44#include <xkbcommon/xkbcommon.h>
45
46#include <errno.h>
47#include <fcntl.h>
48#include <string.h>
49#include <unistd.h>
50#include <sys/time.h>
51#include <sys/mman.h>
52#if defined(HAVE_DEV_EVDEV_INPUT_H)
53#include <dev/evdev/input.h>
54#elif defined(HAVE_LINUX_INPUT_H)
55#include <linux/input.h>
56#endif
57
58/**
59 * GdkWaylandDevice:
60 *
61 * The Wayland implementation of `GdkDevice`.
62 *
63 * Beyond the regular [class@Gdk.Device] API, the Wayland implementation
64 * provides access to Wayland objects such as the `wl_seat` with
65 * [method@GdkWayland.WaylandDevice.get_wl_seat], the `wl_keyboard` with
66 * [method@GdkWayland.WaylandDevice.get_wl_keyboard] and the `wl_pointer` with
67 * [method@GdkWayland.WaylandDevice.get_wl_pointer].
68 */
69
70/**
71 * GdkWaylandSeat:
72 *
73 * The Wayland implementation of `GdkSeat`.
74 *
75 * Beyond the regular [class@Gdk.Seat] API, the Wayland implementation
76 * provides access to the Wayland `wl_seat` object with
77 * [method@GdkWayland.WaylandSeat.get_wl_seat].
78 */
79
80#define BUTTON_BASE (BTN_LEFT - 1) /* Used to translate to 1-indexed buttons */
81
82#ifndef BTN_STYLUS3
83#define BTN_STYLUS3 0x149 /* Linux 4.15 */
84#endif
85
86#define ALL_BUTTONS_MASK (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | \
87 GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | \
88 GDK_BUTTON5_MASK)
89
90#define GDK_SEAT_NOTE(seat,type,action) GDK_DISPLAY_NOTE(gdk_seat_get_display (GDK_SEAT (seat)),type,action)
91
92typedef struct _GdkWaylandDevicePad GdkWaylandDevicePad;
93typedef struct _GdkWaylandDevicePadClass GdkWaylandDevicePadClass;
94
95typedef struct _GdkWaylandTouchData GdkWaylandTouchData;
96typedef struct _GdkWaylandPointerFrameData GdkWaylandPointerFrameData;
97typedef struct _GdkWaylandPointerData GdkWaylandPointerData;
98typedef struct _GdkWaylandTabletData GdkWaylandTabletData;
99typedef struct _GdkWaylandTabletToolData GdkWaylandTabletToolData;
100typedef struct _GdkWaylandTabletPadGroupData GdkWaylandTabletPadGroupData;
101typedef struct _GdkWaylandTabletPadData GdkWaylandTabletPadData;
102
103struct _GdkWaylandTouchData
104{
105 uint32_t id;
106 double x;
107 double y;
108 GdkSurface *surface;
109 uint32_t touch_down_serial;
110 guint initial_touch : 1;
111};
112
113struct _GdkWaylandPointerFrameData
114{
115 GdkEvent *event;
116
117 /* Specific to the scroll event */
118 double delta_x, delta_y;
119 int32_t discrete_x, discrete_y;
120 gint8 is_scroll_stop;
121 enum wl_pointer_axis_source source;
122};
123
124struct _GdkWaylandPointerData {
125 GdkSurface *focus;
126
127 double surface_x, surface_y;
128
129 GdkModifierType button_modifiers;
130
131 uint32_t time;
132 uint32_t enter_serial;
133 uint32_t press_serial;
134
135 GdkSurface *grab_surface;
136 uint32_t grab_time;
137
138 struct wl_surface *pointer_surface;
139 guint cursor_is_default: 1;
140 GdkCursor *cursor;
141 guint cursor_timeout_id;
142 guint cursor_image_index;
143 guint cursor_image_delay;
144 guint touchpad_event_sequence;
145
146 guint current_output_scale;
147 GSList *pointer_surface_outputs;
148
149 /* Accumulated event data for a pointer frame */
150 GdkWaylandPointerFrameData frame;
151};
152
153struct _GdkWaylandTabletToolData
154{
155 GdkSeat *seat;
156 struct zwp_tablet_tool_v2 *wp_tablet_tool;
157 GdkAxisFlags axes;
158 GdkDeviceToolType type;
159 guint64 hardware_serial;
160 guint64 hardware_id_wacom;
161
162 GdkDeviceTool *tool;
163 GdkWaylandTabletData *current_tablet;
164};
165
166struct _GdkWaylandTabletPadGroupData
167{
168 GdkWaylandTabletPadData *pad;
169 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group;
170 GList *rings;
171 GList *strips;
172 GList *buttons;
173
174 guint mode_switch_serial;
175 guint n_modes;
176 guint current_mode;
177
178 struct {
179 guint source;
180 gboolean is_stop;
181 double value;
182 } axis_tmp_info;
183};
184
185struct _GdkWaylandTabletPadData
186{
187 GdkSeat *seat;
188 struct zwp_tablet_pad_v2 *wp_tablet_pad;
189 GdkDevice *device;
190
191 GdkWaylandTabletData *current_tablet;
192
193 guint enter_serial;
194 uint32_t n_buttons;
195 char *path;
196
197 GList *rings;
198 GList *strips;
199 GList *mode_groups;
200};
201
202struct _GdkWaylandTabletData
203{
204 struct zwp_tablet_v2 *wp_tablet;
205 char *name;
206 char *path;
207 uint32_t vid;
208 uint32_t pid;
209
210 GdkDevice *logical_device;
211 GdkDevice *stylus_device;
212 GdkSeat *seat;
213 GdkWaylandPointerData pointer_info;
214
215 GList *pads;
216
217 GdkWaylandTabletToolData *current_tool;
218
219 int axis_indices[GDK_AXIS_LAST];
220 double axes[GDK_AXIS_LAST];
221};
222
223struct _GdkWaylandSeat
224{
225 GdkSeat parent_instance;
226
227 guint32 id;
228 struct wl_seat *wl_seat;
229 struct wl_pointer *wl_pointer;
230 struct wl_keyboard *wl_keyboard;
231 struct wl_touch *wl_touch;
232 struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe;
233 struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch;
234 struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold;
235 struct zwp_tablet_seat_v2 *wp_tablet_seat;
236
237 GdkDisplay *display;
238
239 GdkDevice *logical_pointer;
240 GdkDevice *logical_keyboard;
241 GdkDevice *pointer;
242 GdkDevice *wheel_scrolling;
243 GdkDevice *finger_scrolling;
244 GdkDevice *continuous_scrolling;
245 GdkDevice *keyboard;
246 GdkDevice *logical_touch;
247 GdkDevice *touch;
248 GdkCursor *cursor;
249 GdkKeymap *keymap;
250
251 GHashTable *touches;
252 GList *tablets;
253 GList *tablet_tools;
254 GList *tablet_pads;
255
256 GdkWaylandPointerData pointer_info;
257 GdkWaylandPointerData touch_info;
258
259 GdkModifierType key_modifiers;
260 GdkSurface *keyboard_focus;
261 GdkSurface *grab_surface;
262 uint32_t grab_time;
263 gboolean have_server_repeat;
264 uint32_t server_repeat_rate;
265 uint32_t server_repeat_delay;
266
267 struct wl_data_offer *pending_offer;
268 GdkContentFormatsBuilder *pending_builder;
269 GdkDragAction pending_source_actions;
270 GdkDragAction pending_action;
271
272 struct wl_callback *repeat_callback;
273 guint32 repeat_timer;
274 guint32 repeat_key;
275 guint32 repeat_count;
276 gint64 repeat_deadline;
277 uint32_t keyboard_time;
278 uint32_t keyboard_key_serial;
279
280 GdkClipboard *clipboard;
281 GdkClipboard *primary_clipboard;
282 struct wl_data_device *data_device;
283 GdkDrag *drag;
284 GdkDrop *drop;
285
286 /* Some tracking on gesture events */
287 guint gesture_n_fingers;
288 double gesture_scale;
289
290 GdkCursor *grab_cursor;
291};
292
293G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT)
294
295struct _GdkWaylandDevice
296{
297 GdkDevice parent_instance;
298 GdkWaylandTouchData *emulating_touch; /* Only used on wd->logical_touch */
299 GdkWaylandPointerData *pointer;
300};
301
302struct _GdkWaylandDeviceClass
303{
304 GdkDeviceClass parent_class;
305};
306
307G_DEFINE_TYPE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE)
308
309struct _GdkWaylandDevicePad
310{
311 GdkWaylandDevice parent_instance;
312};
313
314struct _GdkWaylandDevicePadClass
315{
316 GdkWaylandDeviceClass parent_class;
317};
318
319static void gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface);
320static void init_pointer_data (GdkWaylandPointerData *pointer_data,
321 GdkDisplay *display_wayland,
322 GdkDevice *logical_device);
323static void pointer_surface_update_scale (GdkDevice *device);
324
325#define GDK_TYPE_WAYLAND_DEVICE_PAD (gdk_wayland_device_pad_get_type ())
326GType gdk_wayland_device_pad_get_type (void);
327
328G_DEFINE_TYPE_WITH_CODE (GdkWaylandDevicePad, gdk_wayland_device_pad,
329 GDK_TYPE_WAYLAND_DEVICE,
330 G_IMPLEMENT_INTERFACE (GDK_TYPE_DEVICE_PAD,
331 gdk_wayland_device_pad_iface_init))
332
333#define GDK_SLOT_TO_EVENT_SEQUENCE(s) ((GdkEventSequence *) GUINT_TO_POINTER((s) + 1))
334#define GDK_EVENT_SEQUENCE_TO_SLOT(s) (GPOINTER_TO_UINT(s) - 1)
335
336static void deliver_key_event (GdkWaylandSeat *seat,
337 uint32_t time_,
338 uint32_t key,
339 uint32_t state,
340 gboolean from_key_repeat);
341
342static void
343gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer)
344{
345 if (pointer->cursor_timeout_id > 0)
346 {
347 g_source_remove (tag: pointer->cursor_timeout_id);
348 pointer->cursor_timeout_id = 0;
349 pointer->cursor_image_delay = 0;
350 }
351
352 pointer->cursor_image_index = 0;
353}
354
355static GdkWaylandTabletData *
356gdk_wayland_seat_find_tablet (GdkWaylandSeat *seat,
357 GdkDevice *device)
358{
359 GList *l;
360
361 for (l = seat->tablets; l; l = l->next)
362 {
363 GdkWaylandTabletData *tablet = l->data;
364
365 if (tablet->logical_device == device ||
366 tablet->stylus_device == device)
367 return tablet;
368 }
369
370 return NULL;
371}
372
373static GdkWaylandTabletPadData *
374gdk_wayland_seat_find_pad (GdkWaylandSeat *seat,
375 GdkDevice *device)
376{
377 GList *l;
378
379 for (l = seat->tablet_pads; l; l = l->next)
380 {
381 GdkWaylandTabletPadData *pad = l->data;
382
383 if (pad->device == device)
384 return pad;
385 }
386
387 return NULL;
388}
389
390
391static gboolean
392gdk_wayland_device_update_surface_cursor (GdkDevice *device)
393{
394 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
395 GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
396 struct wl_buffer *buffer;
397 int x, y, w, h, scale;
398 guint next_image_index, next_image_delay;
399 gboolean retval = G_SOURCE_REMOVE;
400 GdkWaylandTabletData *tablet;
401
402 tablet = gdk_wayland_seat_find_tablet (seat, device);
403
404 if (pointer->cursor)
405 {
406 buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display),
407 cursor: pointer->cursor,
408 desired_scale: pointer->current_output_scale,
409 image_index: pointer->cursor_image_index,
410 hotspot_x: &x, hotspot_y: &y, w: &w, h: &h, scale: &scale);
411 }
412 else
413 {
414 pointer->cursor_timeout_id = 0;
415 return G_SOURCE_REMOVE;
416 }
417
418 if (tablet)
419 {
420 if (!tablet->current_tool)
421 {
422 pointer->cursor_timeout_id = 0;
423 return G_SOURCE_REMOVE;
424 }
425
426 zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool,
427 pointer->enter_serial,
428 pointer->pointer_surface,
429 x, y);
430 }
431 else if (seat->wl_pointer)
432 {
433 wl_pointer_set_cursor (wl_pointer: seat->wl_pointer,
434 serial: pointer->enter_serial,
435 surface: pointer->pointer_surface,
436 hotspot_x: x, hotspot_y: y);
437 }
438 else
439 {
440 pointer->cursor_timeout_id = 0;
441 return G_SOURCE_REMOVE;
442 }
443
444 if (buffer)
445 {
446 wl_surface_attach (wl_surface: pointer->pointer_surface, buffer, x: 0, y: 0);
447 wl_surface_set_buffer_scale (wl_surface: pointer->pointer_surface, scale);
448 wl_surface_damage (wl_surface: pointer->pointer_surface, x: 0, y: 0, width: w, height: h);
449 wl_surface_commit (wl_surface: pointer->pointer_surface);
450 }
451 else
452 {
453 wl_surface_attach (wl_surface: pointer->pointer_surface, NULL, x: 0, y: 0);
454 wl_surface_commit (wl_surface: pointer->pointer_surface);
455 }
456
457 next_image_index =
458 _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display),
459 cursor: pointer->cursor,
460 scale: pointer->current_output_scale,
461 current_image_index: pointer->cursor_image_index,
462 next_image_delay: &next_image_delay);
463
464 if (next_image_index != pointer->cursor_image_index)
465 {
466 if (next_image_delay != pointer->cursor_image_delay ||
467 pointer->cursor_timeout_id == 0)
468 {
469 guint id;
470 GSource *source;
471
472 gdk_wayland_pointer_stop_cursor_animation (pointer);
473
474 /* Queue timeout for next frame */
475 id = g_timeout_add (interval: next_image_delay,
476 function: (GSourceFunc) gdk_wayland_device_update_surface_cursor,
477 data: device);
478 source = g_main_context_find_source_by_id (NULL, source_id: id);
479 g_source_set_static_name (source, "[gtk] gdk_wayland_device_update_surface_cursor");
480 pointer->cursor_timeout_id = id;
481 }
482 else
483 retval = G_SOURCE_CONTINUE;
484
485 pointer->cursor_image_index = next_image_index;
486 pointer->cursor_image_delay = next_image_delay;
487 }
488 else
489 gdk_wayland_pointer_stop_cursor_animation (pointer);
490
491 return retval;
492}
493
494static void
495gdk_wayland_device_set_surface_cursor (GdkDevice *device,
496 GdkSurface *surface,
497 GdkCursor *cursor)
498{
499 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
500 GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
501
502 if (device == seat->logical_touch)
503 return;
504
505 if (seat->grab_cursor)
506 cursor = seat->grab_cursor;
507
508 if (pointer->cursor != NULL &&
509 cursor != NULL &&
510 gdk_cursor_equal (a: cursor, b: pointer->cursor))
511 return;
512
513 if (cursor == NULL)
514 {
515 if (!pointer->cursor_is_default)
516 {
517 g_clear_object (&pointer->cursor);
518 pointer->cursor = gdk_cursor_new_from_name (name: "default", NULL);
519 pointer->cursor_is_default = TRUE;
520
521 gdk_wayland_pointer_stop_cursor_animation (pointer);
522 gdk_wayland_device_update_surface_cursor (device);
523 }
524 else
525 {
526 /* Nothing to do, we'already using the default cursor */
527 }
528 }
529 else
530 {
531 g_set_object (&pointer->cursor, cursor);
532 pointer->cursor_is_default = FALSE;
533
534 gdk_wayland_pointer_stop_cursor_animation (pointer);
535 gdk_wayland_device_update_surface_cursor (device);
536 }
537}
538
539static GdkModifierType
540device_get_modifiers (GdkDevice *device)
541{
542 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
543 GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
544 GdkModifierType mask;
545
546 mask = seat->key_modifiers;
547
548 if (pointer)
549 mask |= pointer->button_modifiers;
550
551 return mask;
552}
553
554void
555gdk_wayland_device_query_state (GdkDevice *device,
556 GdkSurface *surface,
557 double *win_x,
558 double *win_y,
559 GdkModifierType *mask)
560{
561 GdkWaylandPointerData *pointer;
562 double x, y;
563
564 if (mask)
565 *mask = device_get_modifiers (device);
566
567 pointer = GDK_WAYLAND_DEVICE (device)->pointer;
568
569 if (pointer->focus == surface)
570 {
571 x = pointer->surface_x;
572 y = pointer->surface_y;
573 }
574 else
575 {
576 x = y = -1;
577 }
578
579 if (win_x)
580 *win_x = x;
581 if (win_y)
582 *win_y = y;
583}
584
585static void
586emulate_crossing (GdkSurface *surface,
587 GdkSurface *child_surface,
588 GdkDevice *device,
589 GdkEventType type,
590 GdkCrossingMode mode,
591 guint32 time_)
592{
593 GdkEvent *event;
594 GdkModifierType state;
595 double x, y;
596
597 gdk_surface_get_device_position (surface, device, x: &x, y: &y, mask: &state);
598 event = gdk_crossing_event_new (type,
599 surface,
600 device,
601 time: time_,
602 state,
603 x, y,
604 mode,
605 notify: GDK_NOTIFY_NONLINEAR);
606
607 _gdk_wayland_display_deliver_event (display: gdk_surface_get_display (surface), event);
608}
609
610static void
611emulate_touch_crossing (GdkSurface *surface,
612 GdkSurface *child_surface,
613 GdkDevice *device,
614 GdkDevice *source,
615 GdkWaylandTouchData *touch,
616 GdkEventType type,
617 GdkCrossingMode mode,
618 guint32 time_)
619{
620 GdkEvent *event;
621
622 event = gdk_crossing_event_new (type,
623 surface,
624 device,
625 time: time_,
626 state: 0,
627 x: touch->x, y: touch->y,
628 mode,
629 notify: GDK_NOTIFY_NONLINEAR);
630
631 _gdk_wayland_display_deliver_event (display: gdk_surface_get_display (surface), event);
632}
633
634static void
635emulate_focus (GdkSurface *surface,
636 GdkDevice *device,
637 gboolean focus_in,
638 guint32 time_)
639{
640 GdkEvent *event = gdk_focus_event_new (surface, device, focus_in);
641
642 _gdk_wayland_display_deliver_event (display: gdk_surface_get_display (surface), event);
643}
644
645static void
646device_emit_grab_crossing (GdkDevice *device,
647 GdkSurface *from,
648 GdkSurface *to,
649 GdkCrossingMode mode,
650 guint32 time_)
651{
652 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
653 {
654 if (from)
655 emulate_focus (surface: from, device, FALSE, time_);
656 if (to)
657 emulate_focus (surface: to, device, TRUE, time_);
658 }
659 else
660 {
661 if (from)
662 emulate_crossing (surface: from, child_surface: to, device, type: GDK_LEAVE_NOTIFY, mode, time_);
663 if (to)
664 emulate_crossing (surface: to, child_surface: from, device, type: GDK_ENTER_NOTIFY, mode, time_);
665 }
666}
667
668GdkSurface *
669gdk_wayland_device_get_focus (GdkDevice *device)
670{
671 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
672 GdkWaylandPointerData *pointer;
673
674 if (device == wayland_seat->logical_keyboard)
675 return wayland_seat->keyboard_focus;
676 else
677 {
678 pointer = GDK_WAYLAND_DEVICE (device)->pointer;
679
680 if (pointer)
681 return pointer->focus;
682 }
683
684 return NULL;
685}
686
687static void
688device_maybe_emit_grab_crossing (GdkDevice *device,
689 GdkSurface *window,
690 guint32 time)
691{
692 GdkSurface *surface = gdk_wayland_device_get_focus (device);
693 GdkSurface *focus = window;
694
695 if (focus != surface)
696 device_emit_grab_crossing (device, from: focus, to: window, mode: GDK_CROSSING_GRAB, time_: time);
697}
698
699static GdkSurface*
700device_maybe_emit_ungrab_crossing (GdkDevice *device,
701 guint32 time_)
702{
703 GdkDeviceGrabInfo *grab;
704 GdkSurface *focus = NULL;
705 GdkSurface *surface = NULL;
706 GdkSurface *prev_focus = NULL;
707
708 focus = gdk_wayland_device_get_focus (device);
709 grab = _gdk_display_get_last_device_grab (display: gdk_device_get_display (device), device);
710
711 if (grab)
712 {
713 prev_focus = grab->surface;
714 surface = grab->surface;
715 }
716
717 if (focus != surface)
718 device_emit_grab_crossing (device, from: prev_focus, to: focus, mode: GDK_CROSSING_UNGRAB, time_);
719
720 return prev_focus;
721}
722
723static GdkGrabStatus
724gdk_wayland_device_grab (GdkDevice *device,
725 GdkSurface *surface,
726 gboolean owner_events,
727 GdkEventMask event_mask,
728 GdkSurface *confine_to,
729 GdkCursor *cursor,
730 guint32 time_)
731{
732 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
733 GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
734
735 if (GDK_IS_DRAG_SURFACE (ptr: surface) &&
736 gdk_surface_get_mapped (surface))
737 {
738 g_warning ("Surface %p is already mapped at the time of grabbing. "
739 "gdk_seat_grab() should be used to simultaneously grab input "
740 "and show this popup. You may find oddities ahead.",
741 surface);
742 }
743
744 device_maybe_emit_grab_crossing (device, window: surface, time: time_);
745
746 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
747 {
748 /* Device is a keyboard */
749 gdk_wayland_surface_inhibit_shortcuts (surface,
750 gdk_seat: gdk_device_get_seat (device));
751 return GDK_GRAB_SUCCESS;
752 }
753 else
754 {
755 /* Device is a pointer */
756 if (pointer->grab_surface != NULL &&
757 time_ != 0 && pointer->grab_time > time_)
758 {
759 return GDK_GRAB_ALREADY_GRABBED;
760 }
761
762 if (time_ == 0)
763 time_ = pointer->time;
764
765 pointer->grab_surface = surface;
766 pointer->grab_time = time_;
767 _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (wayland_seat));
768
769 g_clear_object (&wayland_seat->cursor);
770
771 if (cursor)
772 wayland_seat->cursor = g_object_ref (cursor);
773
774 gdk_wayland_device_update_surface_cursor (device);
775 }
776
777 return GDK_GRAB_SUCCESS;
778}
779
780static void
781gdk_wayland_device_ungrab (GdkDevice *device,
782 guint32 time_)
783{
784 GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
785 GdkSurface *prev_focus;
786
787 prev_focus = device_maybe_emit_ungrab_crossing (device, time_);
788
789 if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
790 {
791 /* Device is a keyboard */
792 if (prev_focus)
793 gdk_wayland_surface_restore_shortcuts (surface: prev_focus,
794 gdk_seat: gdk_device_get_seat (device));
795 }
796 else
797 {
798 /* Device is a pointer */
799 gdk_wayland_device_update_surface_cursor (device);
800
801 if (pointer->grab_surface)
802 _gdk_wayland_surface_set_grab_seat (surface: pointer->grab_surface,
803 NULL);
804 }
805}
806
807static GdkSurface *
808gdk_wayland_device_surface_at_position (GdkDevice *device,
809 double *win_x,
810 double *win_y,
811 GdkModifierType *mask)
812{
813 GdkWaylandPointerData *pointer;
814
815 pointer = GDK_WAYLAND_DEVICE(device)->pointer;
816
817 if (!pointer)
818 return NULL;
819
820 if (win_x)
821 *win_x = pointer->surface_x;
822 if (win_y)
823 *win_y = pointer->surface_y;
824 if (mask)
825 *mask = device_get_modifiers (device);
826
827 return pointer->focus;
828}
829
830static void
831gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass)
832{
833 GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
834
835 device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor;
836 device_class->grab = gdk_wayland_device_grab;
837 device_class->ungrab = gdk_wayland_device_ungrab;
838 device_class->surface_at_position = gdk_wayland_device_surface_at_position;
839}
840
841static void
842gdk_wayland_device_init (GdkWaylandDevice *device_core)
843{
844 GdkDevice *device;
845
846 device = GDK_DEVICE (device_core);
847
848 _gdk_device_add_axis (device, use: GDK_AXIS_X, min_value: 0, max_value: 0, resolution: 1);
849 _gdk_device_add_axis (device, use: GDK_AXIS_Y, min_value: 0, max_value: 0, resolution: 1);
850}
851
852static int
853gdk_wayland_device_pad_get_n_groups (GdkDevicePad *pad)
854{
855 GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad));
856 GdkWaylandTabletPadData *data;
857
858 data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat),
859 GDK_DEVICE (pad));
860#ifdef G_DISABLE_ASSERT
861 if (data == NULL)
862 return 0;
863#else
864 g_assert (data != NULL);
865#endif
866
867 return g_list_length (list: data->mode_groups);
868}
869
870static int
871gdk_wayland_device_pad_get_group_n_modes (GdkDevicePad *pad,
872 int n_group)
873{
874 GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad));
875 GdkWaylandTabletPadGroupData *group;
876 GdkWaylandTabletPadData *data;
877
878 data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat),
879 GDK_DEVICE (pad));
880#ifdef G_DISABLE_ASSERT
881 if (data == NULL)
882 return 0;
883#else
884 g_assert (data != NULL);
885#endif
886
887 group = g_list_nth_data (list: data->mode_groups, n: n_group);
888 if (!group)
889 return -1;
890
891 return group->n_modes;
892}
893
894static int
895gdk_wayland_device_pad_get_n_features (GdkDevicePad *pad,
896 GdkDevicePadFeature feature)
897{
898 GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad));
899 GdkWaylandTabletPadData *data;
900
901 data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat),
902 GDK_DEVICE (pad));
903 g_assert (data != NULL);
904
905 switch (feature)
906 {
907 case GDK_DEVICE_PAD_FEATURE_BUTTON:
908 return data->n_buttons;
909 case GDK_DEVICE_PAD_FEATURE_RING:
910 return g_list_length (list: data->rings);
911 case GDK_DEVICE_PAD_FEATURE_STRIP:
912 return g_list_length (list: data->strips);
913 default:
914 return -1;
915 }
916}
917
918static int
919gdk_wayland_device_pad_get_feature_group (GdkDevicePad *pad,
920 GdkDevicePadFeature feature,
921 int idx)
922{
923 GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad));
924 GdkWaylandTabletPadGroupData *group;
925 GdkWaylandTabletPadData *data;
926 GList *l;
927 int i;
928
929 data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat),
930 GDK_DEVICE (pad));
931#ifdef G_DISABLE_ASSERT
932 if (data == NULL)
933 return -1;
934#else
935 g_assert (data != NULL);
936#endif
937
938 for (l = data->mode_groups, i = 0; l; l = l->next, i++)
939 {
940 group = l->data;
941
942 switch (feature)
943 {
944 case GDK_DEVICE_PAD_FEATURE_BUTTON:
945 if (g_list_find (list: group->buttons, GINT_TO_POINTER (idx)))
946 return i;
947 break;
948 case GDK_DEVICE_PAD_FEATURE_RING:
949 {
950 gpointer ring;
951
952 ring = g_list_nth_data (list: data->rings, n: idx);
953 if (ring && g_list_find (list: group->rings, data: ring))
954 return i;
955 break;
956 }
957 case GDK_DEVICE_PAD_FEATURE_STRIP:
958 {
959 gpointer strip;
960 strip = g_list_nth_data (list: data->strips, n: idx);
961 if (strip && g_list_find (list: group->strips, data: strip))
962 return i;
963 break;
964 }
965 default:
966 break;
967 }
968 }
969
970 return -1;
971}
972
973static void
974gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface)
975{
976 iface->get_n_groups = gdk_wayland_device_pad_get_n_groups;
977 iface->get_group_n_modes = gdk_wayland_device_pad_get_group_n_modes;
978 iface->get_n_features = gdk_wayland_device_pad_get_n_features;
979 iface->get_feature_group = gdk_wayland_device_pad_get_feature_group;
980}
981
982static void
983gdk_wayland_device_pad_class_init (GdkWaylandDevicePadClass *klass)
984{
985}
986
987static void
988gdk_wayland_device_pad_init (GdkWaylandDevicePad *pad)
989{
990}
991
992/**
993 * gdk_wayland_device_get_wl_seat: (skip)
994 * @device: (type GdkWaylandDevice): a `GdkDevice`
995 *
996 * Returns the Wayland `wl_seat` of a `GdkDevice`.
997 *
998 * Returns: (transfer none): a Wayland `wl_seat`
999 */
1000struct wl_seat *
1001gdk_wayland_device_get_wl_seat (GdkDevice *device)
1002{
1003 GdkWaylandSeat *seat;
1004
1005 g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL);
1006
1007 seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
1008 return seat->wl_seat;
1009}
1010
1011/**
1012 * gdk_wayland_device_get_wl_pointer: (skip)
1013 * @device: (type GdkWaylandDevice): a `GdkDevice`
1014 *
1015 * Returns the Wayland `wl_pointer` of a `GdkDevice`.
1016 *
1017 * Returns: (transfer none): a Wayland `wl_pointer`
1018 */
1019struct wl_pointer *
1020gdk_wayland_device_get_wl_pointer (GdkDevice *device)
1021{
1022 GdkWaylandSeat *seat;
1023
1024 g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL);
1025
1026 seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
1027 return seat->wl_pointer;
1028}
1029
1030/**
1031 * gdk_wayland_device_get_wl_keyboard: (skip)
1032 * @device: (type GdkWaylandDevice): a `GdkDevice`
1033 *
1034 * Returns the Wayland `wl_keyboard` of a `GdkDevice`.
1035 *
1036 * Returns: (transfer none): a Wayland `wl_keyboard`
1037 */
1038struct wl_keyboard *
1039gdk_wayland_device_get_wl_keyboard (GdkDevice *device)
1040{
1041 GdkWaylandSeat *seat;
1042
1043 g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL);
1044
1045 seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
1046 return seat->wl_keyboard;
1047}
1048
1049/**
1050 * gdk_wayland_device_get_xkb_keymap:
1051 * @device: (type GdkWaylandDevice): a `GdkDevice`
1052 *
1053 * Returns the `xkb_keymap` of a `GdkDevice`.
1054 *
1055 * Returns: (transfer none): a `struct xkb_keymap`
1056 *
1057 * Since: 4.4
1058 */
1059struct xkb_keymap *
1060gdk_wayland_device_get_xkb_keymap (GdkDevice *device)
1061{
1062 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
1063 return _gdk_wayland_keymap_get_xkb_keymap (keymap: seat->keymap);
1064}
1065
1066GdkKeymap *
1067_gdk_wayland_device_get_keymap (GdkDevice *device)
1068{
1069 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
1070 return seat->keymap;
1071}
1072
1073static void
1074gdk_wayland_seat_discard_pending_offer (GdkWaylandSeat *seat)
1075{
1076 if (seat->pending_builder)
1077 {
1078 GdkContentFormats *ignore = gdk_content_formats_builder_free_to_formats (builder: seat->pending_builder);
1079 gdk_content_formats_unref (formats: ignore);
1080 seat->pending_builder = NULL;
1081 }
1082 g_clear_pointer (&seat->pending_offer, wl_data_offer_destroy);
1083 seat->pending_source_actions = 0;
1084 seat->pending_action = 0;
1085}
1086
1087static inline GdkDragAction
1088gdk_wayland_actions_to_gdk_actions (uint32_t dnd_actions)
1089{
1090 GdkDragAction actions = 0;
1091
1092 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
1093 actions |= GDK_ACTION_COPY;
1094 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
1095 actions |= GDK_ACTION_MOVE;
1096 if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
1097 actions |= GDK_ACTION_ASK;
1098
1099 return actions;
1100}
1101
1102static void
1103data_offer_offer (void *data,
1104 struct wl_data_offer *offer,
1105 const char *type)
1106{
1107 GdkWaylandSeat *seat = data;
1108
1109 if (seat->pending_offer != offer)
1110 {
1111 GDK_SEAT_NOTE (seat, EVENTS,
1112 g_message ("%p: offer for unknown offer %p of %s",
1113 seat, offer, type));
1114 return;
1115 }
1116
1117 /* skip magic mime types */
1118 if (g_str_equal (v1: type, GDK_WAYLAND_LOCAL_DND_MIME_TYPE))
1119 return;
1120
1121 gdk_content_formats_builder_add_mime_type (builder: seat->pending_builder, mime_type: type);
1122}
1123
1124static void
1125data_offer_source_actions (void *data,
1126 struct wl_data_offer *offer,
1127 uint32_t source_actions)
1128{
1129 GdkWaylandSeat *seat = data;
1130
1131 if (offer == seat->pending_offer)
1132 {
1133 seat->pending_source_actions = gdk_wayland_actions_to_gdk_actions (dnd_actions: source_actions);
1134 return;
1135 }
1136
1137 if (seat->drop == NULL)
1138 return;
1139
1140 gdk_wayland_drop_set_source_actions (drop: seat->drop, source_actions);
1141
1142 gdk_drop_emit_motion_event (self: seat->drop,
1143 FALSE,
1144 x: seat->pointer_info.surface_x,
1145 y: seat->pointer_info.surface_y,
1146 GDK_CURRENT_TIME);
1147}
1148
1149static void
1150data_offer_action (void *data,
1151 struct wl_data_offer *offer,
1152 uint32_t action)
1153{
1154 GdkWaylandSeat *seat = data;
1155
1156 if (offer == seat->pending_offer)
1157 {
1158 seat->pending_action = gdk_wayland_actions_to_gdk_actions (dnd_actions: action);
1159 return;
1160 }
1161
1162 if (seat->drop == NULL)
1163 return;
1164
1165 gdk_wayland_drop_set_action (drop: seat->drop, action);
1166
1167 gdk_drop_emit_motion_event (self: seat->drop,
1168 FALSE,
1169 x: seat->pointer_info.surface_x,
1170 y: seat->pointer_info.surface_y,
1171 GDK_CURRENT_TIME);
1172}
1173
1174static const struct wl_data_offer_listener data_offer_listener = {
1175 data_offer_offer,
1176 data_offer_source_actions,
1177 data_offer_action
1178};
1179
1180static void
1181data_device_data_offer (void *data,
1182 struct wl_data_device *data_device,
1183 struct wl_data_offer *offer)
1184{
1185 GdkWaylandSeat *seat = data;
1186
1187 GDK_SEAT_NOTE (seat, EVENTS,
1188 g_message ("data device data offer, data device %p, offer %p",
1189 data_device, offer));
1190
1191 gdk_wayland_seat_discard_pending_offer (seat);
1192
1193 seat->pending_offer = offer;
1194 wl_data_offer_add_listener (wl_data_offer: offer,
1195 listener: &data_offer_listener,
1196 data: seat);
1197
1198 seat->pending_builder = gdk_content_formats_builder_new ();
1199 seat->pending_source_actions = 0;
1200 seat->pending_action = 0;
1201}
1202
1203static void
1204data_device_enter (void *data,
1205 struct wl_data_device *data_device,
1206 uint32_t serial,
1207 struct wl_surface *surface,
1208 wl_fixed_t x,
1209 wl_fixed_t y,
1210 struct wl_data_offer *offer)
1211{
1212 GdkWaylandSeat *seat = data;
1213 GdkSurface *dest_surface;
1214 GdkContentFormats *formats;
1215 int origin_x, origin_y;
1216 GdkDevice *device;
1217
1218 dest_surface = wl_surface_get_user_data (wl_surface: surface);
1219
1220 if (!GDK_IS_SURFACE (dest_surface))
1221 return;
1222
1223 if (offer != seat->pending_offer)
1224 {
1225 GDK_SEAT_NOTE (seat, EVENTS,
1226 g_message ("%p: enter event for unknown offer %p, expected %p",
1227 seat, offer, seat->pending_offer));
1228 return;
1229 }
1230
1231 GDK_SEAT_NOTE (seat, EVENTS,
1232 g_message ("data device enter, data device %p serial %u, surface %p, x %f y %f, offer %p",
1233 data_device, serial, surface, wl_fixed_to_double (x), wl_fixed_to_double (y), offer));
1234
1235 /* Update pointer state, so device state queries work during DnD */
1236 seat->pointer_info.focus = g_object_ref (dest_surface);
1237 seat->pointer_info.surface_x = wl_fixed_to_double (f: x);
1238 seat->pointer_info.surface_y = wl_fixed_to_double (f: y);
1239
1240 if (seat->logical_pointer)
1241 device = seat->logical_pointer;
1242 else if (seat->logical_touch)
1243 device = seat->logical_touch;
1244 else
1245 {
1246 g_warning ("No device for DND enter, ignoring.");
1247 return;
1248 }
1249
1250 formats = gdk_content_formats_builder_free_to_formats (builder: seat->pending_builder);
1251 seat->pending_builder = NULL;
1252 seat->pending_offer = NULL;
1253
1254 seat->drop = gdk_wayland_drop_new (device, drag: seat->drag, formats, surface: dest_surface, offer, serial);
1255 gdk_wayland_drop_set_source_actions (drop: seat->drop, source_actions: seat->pending_source_actions);
1256 gdk_wayland_drop_set_action (drop: seat->drop, action: seat->pending_action);
1257
1258 gdk_content_formats_unref (formats);
1259
1260 gdk_wayland_seat_discard_pending_offer (seat);
1261
1262 gdk_surface_get_origin (surface: gdk_drop_get_surface (self: seat->drop), x: &origin_x, y: &origin_y);
1263
1264 gdk_drop_emit_enter_event (self: seat->drop,
1265 FALSE,
1266 x: origin_x + seat->pointer_info.surface_x,
1267 y: origin_y + seat->pointer_info.surface_y,
1268 GDK_CURRENT_TIME);
1269}
1270
1271static void
1272data_device_leave (void *data,
1273 struct wl_data_device *data_device)
1274{
1275 GdkWaylandSeat *seat = data;
1276
1277 GDK_SEAT_NOTE (seat, EVENTS,
1278 g_message ("data device leave, data device %p", data_device));
1279
1280 if (seat->drop == NULL)
1281 return;
1282
1283 g_object_unref (object: seat->pointer_info.focus);
1284 seat->pointer_info.focus = NULL;
1285
1286 gdk_drop_emit_leave_event (self: seat->drop,
1287 FALSE,
1288 GDK_CURRENT_TIME);
1289
1290 g_clear_object (&seat->drop);
1291}
1292
1293static void
1294data_device_motion (void *data,
1295 struct wl_data_device *data_device,
1296 uint32_t time,
1297 wl_fixed_t x,
1298 wl_fixed_t y)
1299{
1300 GdkWaylandSeat *seat = data;
1301 int origin_x, origin_y;
1302
1303 GDK_SEAT_NOTE (seat, EVENTS,
1304 g_message ("data device motion, data_device = %p, time = %d, x = %f, y = %f",
1305 data_device, time, wl_fixed_to_double (x), wl_fixed_to_double (y)));
1306
1307 if (seat->drop == NULL)
1308 return;
1309
1310 /* Update pointer state, so device state queries work during DnD */
1311 seat->pointer_info.surface_x = wl_fixed_to_double (f: x);
1312 seat->pointer_info.surface_y = wl_fixed_to_double (f: y);
1313
1314 gdk_surface_get_origin (surface: gdk_drop_get_surface (self: seat->drop), x: &origin_x, y: &origin_y);
1315
1316 gdk_drop_emit_motion_event (self: seat->drop,
1317 FALSE,
1318 x: origin_x + seat->pointer_info.surface_x,
1319 y: origin_y + seat->pointer_info.surface_y,
1320 time);
1321}
1322
1323static void
1324data_device_drop (void *data,
1325 struct wl_data_device *data_device)
1326{
1327 GdkWaylandSeat *seat = data;
1328 int origin_x, origin_y;
1329
1330 GDK_SEAT_NOTE (seat, EVENTS,
1331 g_message ("data device drop, data device %p", data_device));
1332
1333 gdk_surface_get_origin (surface: gdk_drop_get_surface (self: seat->drop), x: &origin_x, y: &origin_y);
1334
1335 gdk_drop_emit_drop_event (self: seat->drop,
1336 FALSE,
1337 x: origin_x + seat->pointer_info.surface_x,
1338 y: origin_y + seat->pointer_info.surface_y,
1339 GDK_CURRENT_TIME);
1340}
1341
1342static void
1343data_device_selection (void *data,
1344 struct wl_data_device *wl_data_device,
1345 struct wl_data_offer *offer)
1346{
1347 GdkWaylandSeat *seat = data;
1348 GdkContentFormats *formats;
1349
1350 if (offer)
1351 {
1352 if (offer == seat->pending_offer)
1353 {
1354 formats = gdk_content_formats_builder_free_to_formats (builder: seat->pending_builder);
1355 seat->pending_builder = NULL;
1356 seat->pending_offer = NULL;
1357 }
1358 else
1359 {
1360 formats = gdk_content_formats_new (NULL, n_mime_types: 0);
1361 offer = NULL;
1362 }
1363
1364 gdk_wayland_seat_discard_pending_offer (seat);
1365 }
1366 else
1367 {
1368 formats = gdk_content_formats_new (NULL, n_mime_types: 0);
1369 }
1370
1371 gdk_wayland_clipboard_claim_remote (GDK_WAYLAND_CLIPBOARD (seat->clipboard),
1372 offer,
1373 formats);
1374}
1375
1376static const struct wl_data_device_listener data_device_listener = {
1377 data_device_data_offer,
1378 data_device_enter,
1379 data_device_leave,
1380 data_device_motion,
1381 data_device_drop,
1382 data_device_selection
1383};
1384
1385static GdkDevice * get_scroll_device (GdkWaylandSeat *seat,
1386 enum wl_pointer_axis_source source);
1387
1388static void
1389flush_discrete_scroll_event (GdkWaylandSeat *seat,
1390 GdkScrollDirection direction)
1391{
1392 GdkEvent *event;
1393 GdkDevice *source;
1394
1395 source = get_scroll_device (seat, source: seat->pointer_info.frame.source);
1396 event = gdk_scroll_event_new_discrete (surface: seat->pointer_info.focus,
1397 device: source,
1398 NULL,
1399 time: seat->pointer_info.time,
1400 state: device_get_modifiers (device: seat->logical_pointer),
1401 direction,
1402 TRUE);
1403
1404 _gdk_wayland_display_deliver_event (display: seat->display, event);
1405}
1406
1407static void
1408flush_smooth_scroll_event (GdkWaylandSeat *seat,
1409 double delta_x,
1410 double delta_y,
1411 gboolean is_stop)
1412{
1413 GdkEvent *event;
1414 GdkDevice *source;
1415
1416 source = get_scroll_device (seat, source: seat->pointer_info.frame.source);
1417 event = gdk_scroll_event_new (surface: seat->pointer_info.focus,
1418 device: source,
1419 NULL,
1420 time: seat->pointer_info.time,
1421 state: device_get_modifiers (device: seat->logical_pointer),
1422 delta_x, delta_y,
1423 is_stop);
1424
1425 _gdk_wayland_display_deliver_event (display: seat->display, event);
1426}
1427
1428static void
1429flush_scroll_event (GdkWaylandSeat *seat,
1430 GdkWaylandPointerFrameData *pointer_frame)
1431{
1432 gboolean is_stop = FALSE;
1433
1434 if (pointer_frame->discrete_x || pointer_frame->discrete_y)
1435 {
1436 GdkScrollDirection direction;
1437
1438 if (pointer_frame->discrete_x > 0)
1439 direction = GDK_SCROLL_LEFT;
1440 else if (pointer_frame->discrete_x < 0)
1441 direction = GDK_SCROLL_RIGHT;
1442 else if (pointer_frame->discrete_y > 0)
1443 direction = GDK_SCROLL_DOWN;
1444 else
1445 direction = GDK_SCROLL_UP;
1446
1447 flush_discrete_scroll_event (seat, direction);
1448 pointer_frame->discrete_x = 0;
1449 pointer_frame->discrete_y = 0;
1450 }
1451 else if (pointer_frame->is_scroll_stop ||
1452 pointer_frame->delta_x != 0 ||
1453 pointer_frame->delta_y != 0)
1454 {
1455 /* Axes can stop independently, if we stop on one axis but have a
1456 * delta on the other, we don't count it as a stop event.
1457 */
1458 if (pointer_frame->is_scroll_stop &&
1459 pointer_frame->delta_x == 0 &&
1460 pointer_frame->delta_y == 0)
1461 is_stop = TRUE;
1462
1463 flush_smooth_scroll_event (seat,
1464 delta_x: pointer_frame->delta_x,
1465 delta_y: pointer_frame->delta_y,
1466 is_stop);
1467 }
1468
1469 pointer_frame->discrete_x = 0;
1470 pointer_frame->discrete_y = 0;
1471 pointer_frame->delta_x = 0;
1472 pointer_frame->delta_y = 0;
1473 pointer_frame->is_scroll_stop = FALSE;
1474}
1475
1476static void
1477gdk_wayland_seat_flush_frame_event (GdkWaylandSeat *seat)
1478{
1479 if (seat->pointer_info.frame.event)
1480 {
1481 _gdk_wayland_display_deliver_event (display: gdk_seat_get_display (GDK_SEAT (seat)),
1482 event: seat->pointer_info.frame.event);
1483 seat->pointer_info.frame.event = NULL;
1484 }
1485 else
1486 {
1487 flush_scroll_event (seat, pointer_frame: &seat->pointer_info.frame);
1488 seat->pointer_info.frame.source = 0;
1489 }
1490}
1491
1492static void
1493gdk_wayland_seat_set_frame_event (GdkWaylandSeat *seat,
1494 GdkEvent *event)
1495{
1496 if (seat->pointer_info.frame.event &&
1497 gdk_event_get_event_type (event: seat->pointer_info.frame.event) != gdk_event_get_event_type (event))
1498 gdk_wayland_seat_flush_frame_event (seat);
1499
1500 seat->pointer_info.frame.event = event;
1501}
1502
1503static void
1504pointer_handle_enter (void *data,
1505 struct wl_pointer *pointer,
1506 uint32_t serial,
1507 struct wl_surface *surface,
1508 wl_fixed_t sx,
1509 wl_fixed_t sy)
1510{
1511 GdkWaylandSeat *seat = data;
1512 GdkEvent *event;
1513 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
1514
1515 if (!surface)
1516 return;
1517
1518 if (!GDK_IS_SURFACE (wl_surface_get_user_data (surface)))
1519 return;
1520
1521 _gdk_wayland_display_update_serial (display_wayland, serial);
1522
1523 seat->pointer_info.focus = wl_surface_get_user_data (wl_surface: surface);
1524 g_object_ref (seat->pointer_info.focus);
1525
1526 seat->pointer_info.button_modifiers = 0;
1527
1528 seat->pointer_info.surface_x = wl_fixed_to_double (f: sx);
1529 seat->pointer_info.surface_y = wl_fixed_to_double (f: sy);
1530 seat->pointer_info.enter_serial = serial;
1531
1532 event = gdk_crossing_event_new (type: GDK_ENTER_NOTIFY,
1533 surface: seat->pointer_info.focus,
1534 device: seat->logical_pointer,
1535 time: 0,
1536 state: 0,
1537 x: seat->pointer_info.surface_x,
1538 y: seat->pointer_info.surface_y,
1539 mode: GDK_CROSSING_NORMAL,
1540 notify: GDK_NOTIFY_NONLINEAR);
1541 gdk_wayland_seat_set_frame_event (seat, event);
1542
1543 gdk_wayland_device_update_surface_cursor (device: seat->logical_pointer);
1544
1545 GDK_SEAT_NOTE (seat, EVENTS,
1546 g_message ("enter, seat %p surface %p",
1547 seat, seat->pointer_info.focus));
1548
1549 if (display_wayland->seat_version < WL_POINTER_HAS_FRAME)
1550 gdk_wayland_seat_flush_frame_event (seat);
1551}
1552
1553static void
1554pointer_handle_leave (void *data,
1555 struct wl_pointer *pointer,
1556 uint32_t serial,
1557 struct wl_surface *surface)
1558{
1559 GdkWaylandSeat *seat = data;
1560 GdkEvent *event;
1561 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
1562 GdkDeviceGrabInfo *grab;
1563
1564 if (!seat->pointer_info.focus)
1565 return;
1566
1567 _gdk_wayland_display_update_serial (display_wayland, serial);
1568 grab = _gdk_display_get_last_device_grab (display: seat->display,
1569 device: seat->logical_pointer);
1570
1571 if (seat->pointer_info.button_modifiers != 0 &&
1572 grab && grab->implicit)
1573 {
1574 gulong display_serial;
1575
1576 display_serial = _gdk_display_get_next_serial (display: seat->display);
1577 _gdk_display_end_device_grab (display: seat->display, device: seat->logical_pointer,
1578 serial: display_serial, NULL, TRUE);
1579 _gdk_display_device_grab_update (display: seat->display,
1580 device: seat->logical_pointer,
1581 current_serial: display_serial);
1582 }
1583
1584 event = gdk_crossing_event_new (type: GDK_LEAVE_NOTIFY,
1585 surface: seat->pointer_info.focus,
1586 device: seat->logical_pointer,
1587 time: 0,
1588 state: 0,
1589 x: seat->pointer_info.surface_x,
1590 y: seat->pointer_info.surface_y,
1591 mode: GDK_CROSSING_NORMAL,
1592 notify: GDK_NOTIFY_NONLINEAR);
1593 gdk_wayland_seat_set_frame_event (seat, event);
1594
1595 gdk_wayland_device_update_surface_cursor (device: seat->logical_pointer);
1596
1597 GDK_SEAT_NOTE (seat, EVENTS,
1598 g_message ("leave, seat %p surface %p",
1599 seat, seat->pointer_info.focus));
1600
1601 g_object_unref (object: seat->pointer_info.focus);
1602 seat->pointer_info.focus = NULL;
1603 if (seat->cursor)
1604 gdk_wayland_pointer_stop_cursor_animation (pointer: &seat->pointer_info);
1605
1606 if (display_wayland->seat_version < WL_POINTER_HAS_FRAME)
1607 gdk_wayland_seat_flush_frame_event (seat);
1608}
1609
1610static void
1611pointer_handle_motion (void *data,
1612 struct wl_pointer *pointer,
1613 uint32_t time,
1614 wl_fixed_t sx,
1615 wl_fixed_t sy)
1616{
1617 GdkWaylandSeat *seat = data;
1618 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
1619 GdkEvent *event;
1620
1621 if (!seat->pointer_info.focus)
1622 return;
1623
1624 seat->pointer_info.time = time;
1625 seat->pointer_info.surface_x = wl_fixed_to_double (f: sx);
1626 seat->pointer_info.surface_y = wl_fixed_to_double (f: sy);
1627
1628 event = gdk_motion_event_new (surface: seat->pointer_info.focus,
1629 device: seat->logical_pointer,
1630 NULL,
1631 time,
1632 state: device_get_modifiers (device: seat->logical_pointer),
1633 x: seat->pointer_info.surface_x,
1634 y: seat->pointer_info.surface_y,
1635 NULL);
1636 gdk_wayland_seat_set_frame_event (seat, event);
1637
1638 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
1639 {
1640 double x, y;
1641 gdk_event_get_position (event, x: &x, y: &y);
1642 g_message ("motion %f %f, seat %p state %d",
1643 x, y, seat, gdk_event_get_modifier_state (event));
1644 }
1645
1646 if (display->seat_version < WL_POINTER_HAS_FRAME)
1647 gdk_wayland_seat_flush_frame_event (seat);
1648}
1649
1650static void
1651pointer_handle_button (void *data,
1652 struct wl_pointer *pointer,
1653 uint32_t serial,
1654 uint32_t time,
1655 uint32_t button,
1656 uint32_t state)
1657{
1658 GdkWaylandSeat *seat = data;
1659 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
1660 GdkEvent *event;
1661 uint32_t modifier;
1662 int gdk_button;
1663
1664 if (!seat->pointer_info.focus)
1665 return;
1666
1667 _gdk_wayland_display_update_serial (display_wayland: display, serial);
1668
1669 switch (button)
1670 {
1671 case BTN_LEFT:
1672 gdk_button = GDK_BUTTON_PRIMARY;
1673 break;
1674 case BTN_MIDDLE:
1675 gdk_button = GDK_BUTTON_MIDDLE;
1676 break;
1677 case BTN_RIGHT:
1678 gdk_button = GDK_BUTTON_SECONDARY;
1679 break;
1680 default:
1681 /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */
1682 gdk_button = button - BUTTON_BASE + 4;
1683 break;
1684 }
1685
1686 seat->pointer_info.time = time;
1687 if (state)
1688 seat->pointer_info.press_serial = serial;
1689
1690 event = gdk_button_event_new (type: state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE,
1691 surface: seat->pointer_info.focus,
1692 device: seat->logical_pointer,
1693 NULL,
1694 time,
1695 state: device_get_modifiers (device: seat->logical_pointer),
1696 button: gdk_button,
1697 x: seat->pointer_info.surface_x,
1698 y: seat->pointer_info.surface_y,
1699 NULL);
1700
1701 gdk_wayland_seat_set_frame_event (seat, event);
1702
1703 modifier = (GDK_BUTTON1_MASK << (button - BUTTON_BASE - 1)) & ALL_BUTTONS_MASK;
1704
1705 if (state)
1706 seat->pointer_info.button_modifiers |= modifier;
1707 else
1708 seat->pointer_info.button_modifiers &= ~modifier;
1709
1710 GDK_SEAT_NOTE (seat, EVENTS,
1711 g_message ("button %d %s, seat %p state %d",
1712 gdk_button_event_get_button (event),
1713 state ? "press" : "release",
1714 seat,
1715 gdk_event_get_modifier_state (event)));
1716
1717 if (display->seat_version < WL_POINTER_HAS_FRAME)
1718 gdk_wayland_seat_flush_frame_event (seat);
1719}
1720
1721#ifdef G_ENABLE_DEBUG
1722
1723static const char *
1724get_axis_name (uint32_t axis)
1725{
1726 switch (axis)
1727 {
1728 case WL_POINTER_AXIS_VERTICAL_SCROLL:
1729 return "horizontal";
1730 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
1731 return "vertical";
1732 default:
1733 return "unknown";
1734 }
1735}
1736
1737#endif
1738
1739static void
1740pointer_handle_axis (void *data,
1741 struct wl_pointer *pointer,
1742 uint32_t time,
1743 uint32_t axis,
1744 wl_fixed_t value)
1745{
1746 GdkWaylandSeat *seat = data;
1747 GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame;
1748 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
1749
1750 if (!seat->pointer_info.focus)
1751 return;
1752
1753 /* get the delta and convert it into the expected range */
1754 switch (axis)
1755 {
1756 case WL_POINTER_AXIS_VERTICAL_SCROLL:
1757 pointer_frame->delta_y = wl_fixed_to_double (f: value) / 10.0;
1758 break;
1759 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
1760 pointer_frame->delta_x = wl_fixed_to_double (f: value) / 10.0;
1761 break;
1762 default:
1763 g_return_if_reached ();
1764 }
1765
1766 seat->pointer_info.time = time;
1767
1768 GDK_SEAT_NOTE (seat, EVENTS,
1769 g_message ("scroll, axis %s, value %f, seat %p",
1770 get_axis_name (axis), wl_fixed_to_double (value) / 10.0,
1771 seat));
1772
1773 if (display->seat_version < WL_POINTER_HAS_FRAME)
1774 gdk_wayland_seat_flush_frame_event (seat);
1775}
1776
1777static void
1778pointer_handle_frame (void *data,
1779 struct wl_pointer *pointer)
1780{
1781 GdkWaylandSeat *seat = data;
1782
1783 GDK_SEAT_NOTE (seat, EVENTS,
1784 g_message ("frame, seat %p", seat));
1785
1786 gdk_wayland_seat_flush_frame_event (seat);
1787}
1788
1789#ifdef G_ENABLE_DEBUG
1790
1791static const char *
1792get_axis_source_name (enum wl_pointer_axis_source source)
1793{
1794 switch (source)
1795 {
1796 case WL_POINTER_AXIS_SOURCE_WHEEL:
1797 return "wheel";
1798 case WL_POINTER_AXIS_SOURCE_FINGER:
1799 return "finger";
1800 case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
1801 return "continuous";
1802 case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
1803 return "wheel-tilt";
1804 default:
1805 return "unknown";
1806 }
1807}
1808
1809#endif
1810
1811static void
1812pointer_handle_axis_source (void *data,
1813 struct wl_pointer *pointer,
1814 enum wl_pointer_axis_source source)
1815{
1816 GdkWaylandSeat *seat = data;
1817 GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame;
1818
1819 if (!seat->pointer_info.focus)
1820 return;
1821
1822 pointer_frame->source = source;
1823
1824 GDK_SEAT_NOTE (seat, EVENTS,
1825 g_message ("axis source %s, seat %p", get_axis_source_name (source), seat));
1826}
1827
1828static void
1829pointer_handle_axis_stop (void *data,
1830 struct wl_pointer *pointer,
1831 uint32_t time,
1832 uint32_t axis)
1833{
1834 GdkWaylandSeat *seat = data;
1835 GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame;
1836
1837 if (!seat->pointer_info.focus)
1838 return;
1839
1840 seat->pointer_info.time = time;
1841
1842 switch (axis)
1843 {
1844 case WL_POINTER_AXIS_VERTICAL_SCROLL:
1845 pointer_frame->delta_y = 0;
1846 break;
1847 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
1848 pointer_frame->delta_x = 0;
1849 break;
1850 default:
1851 g_return_if_reached ();
1852 }
1853
1854 pointer_frame->is_scroll_stop = TRUE;
1855
1856 GDK_SEAT_NOTE (seat, EVENTS,
1857 g_message ("axis %s stop, seat %p", get_axis_name (axis), seat));
1858}
1859
1860static void
1861pointer_handle_axis_discrete (void *data,
1862 struct wl_pointer *pointer,
1863 uint32_t axis,
1864 int32_t value)
1865{
1866 GdkWaylandSeat *seat = data;
1867 GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame;
1868
1869 if (!seat->pointer_info.focus)
1870 return;
1871
1872 switch (axis)
1873 {
1874 case WL_POINTER_AXIS_VERTICAL_SCROLL:
1875 pointer_frame->discrete_y = value;
1876 break;
1877 case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
1878 pointer_frame->discrete_x = value;
1879 break;
1880 default:
1881 g_return_if_reached ();
1882 }
1883
1884 GDK_SEAT_NOTE (seat, EVENTS,
1885 g_message ("discrete scroll, axis %s, value %d, seat %p",
1886 get_axis_name (axis), value, seat));
1887}
1888
1889static int
1890get_active_layout (GdkKeymap *keymap)
1891{
1892 struct xkb_keymap *xkb_keymap;
1893 struct xkb_state *xkb_state;
1894
1895 xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap);
1896 xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap);
1897
1898 for (int i = 0; i < xkb_keymap_num_layouts (keymap: xkb_keymap); i++)
1899 {
1900 if (xkb_state_layout_index_is_active (state: xkb_state, idx: i, type: XKB_STATE_LAYOUT_EFFECTIVE))
1901 return i;
1902 }
1903
1904 return -1;
1905}
1906
1907#ifdef G_ENABLE_DEBUG
1908static const char *
1909get_active_layout_name (GdkKeymap *keymap)
1910{
1911 struct xkb_keymap *xkb_keymap;
1912
1913 xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap);
1914
1915 return xkb_keymap_layout_get_name (keymap: xkb_keymap, idx: get_active_layout (keymap));
1916}
1917#endif
1918
1919static void
1920keyboard_handle_keymap (void *data,
1921 struct wl_keyboard *keyboard,
1922 uint32_t format,
1923 int fd,
1924 uint32_t size)
1925{
1926 GdkWaylandSeat *seat = data;
1927 PangoDirection direction;
1928 gboolean bidi;
1929 gboolean caps_lock;
1930 gboolean num_lock;
1931 gboolean scroll_lock;
1932 GdkModifierType modifiers;
1933
1934 direction = gdk_keymap_get_direction (keymap: seat->keymap);
1935 bidi = gdk_keymap_have_bidi_layouts (keymap: seat->keymap);
1936 caps_lock = gdk_keymap_get_caps_lock_state (keymap: seat->keymap);
1937 num_lock = gdk_keymap_get_num_lock_state (keymap: seat->keymap);
1938 scroll_lock = gdk_keymap_get_scroll_lock_state (keymap: seat->keymap);
1939 modifiers = gdk_keymap_get_modifier_state (keymap: seat->keymap);
1940
1941 _gdk_wayland_keymap_update_from_fd (keymap: seat->keymap, format, fd, size);
1942
1943 GDK_DISPLAY_NOTE(seat->keymap->display, INPUT,
1944 {
1945 GString *s = g_string_new ("");
1946 struct xkb_keymap *xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (seat->keymap);
1947 struct xkb_state *xkb_state = _gdk_wayland_keymap_get_xkb_state (seat->keymap);
1948 for (int i = 0; i < xkb_keymap_num_layouts (xkb_keymap); i++)
1949 {
1950 if (s->len > 0)
1951 g_string_append (s, ", ");
1952 if (xkb_state_layout_index_is_active (xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE))
1953 g_string_append (s, "*");
1954 g_string_append (s, xkb_keymap_layout_get_name (xkb_keymap, i));
1955 }
1956 g_print ("layouts: %s\n", s->str);
1957 g_string_free (s, TRUE);
1958 });
1959
1960 g_signal_emit_by_name (instance: seat->keymap, detailed_signal: "keys-changed");
1961 g_signal_emit_by_name (instance: seat->keymap, detailed_signal: "state-changed");
1962 if (direction != gdk_keymap_get_direction (keymap: seat->keymap))
1963 g_signal_emit_by_name (instance: seat->keymap, detailed_signal: "direction-changed");
1964
1965 if (direction != gdk_keymap_get_direction (keymap: seat->keymap))
1966 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "direction");
1967 if (bidi != gdk_keymap_have_bidi_layouts (keymap: seat->keymap))
1968 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "has-bidi-layouts");
1969 if (caps_lock != gdk_keymap_get_caps_lock_state (keymap: seat->keymap))
1970 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "caps-lock-state");
1971 if (num_lock != gdk_keymap_get_num_lock_state (keymap: seat->keymap))
1972 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "num-lock-state");
1973 if (scroll_lock != gdk_keymap_get_scroll_lock_state (keymap: seat->keymap))
1974 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "scroll-lock-state");
1975 if (modifiers != gdk_keymap_get_modifier_state (keymap: seat->keymap))
1976 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "modifier-state");
1977}
1978
1979static void
1980keyboard_handle_enter (void *data,
1981 struct wl_keyboard *keyboard,
1982 uint32_t serial,
1983 struct wl_surface *surface,
1984 struct wl_array *keys)
1985{
1986 GdkWaylandSeat *seat = data;
1987 GdkEvent *event;
1988 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
1989
1990 if (!surface)
1991 return;
1992
1993 if (!GDK_IS_SURFACE (wl_surface_get_user_data (surface)))
1994 return;
1995
1996 _gdk_wayland_display_update_serial (display_wayland: display, serial);
1997
1998 seat->keyboard_focus = wl_surface_get_user_data (wl_surface: surface);
1999 g_object_ref (seat->keyboard_focus);
2000 seat->repeat_key = 0;
2001
2002 event = gdk_focus_event_new (surface: seat->keyboard_focus,
2003 device: seat->logical_keyboard,
2004 TRUE);
2005
2006 GDK_SEAT_NOTE (seat, EVENTS,
2007 g_message ("focus in, seat %p surface %p",
2008 seat, seat->keyboard_focus));
2009
2010 _gdk_wayland_display_deliver_event (display: seat->display, event);
2011}
2012
2013static void stop_key_repeat (GdkWaylandSeat *seat);
2014
2015static void
2016keyboard_handle_leave (void *data,
2017 struct wl_keyboard *keyboard,
2018 uint32_t serial,
2019 struct wl_surface *surface)
2020{
2021 GdkWaylandSeat *seat = data;
2022 GdkEvent *event;
2023 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2024
2025 if (!seat->keyboard_focus)
2026 return;
2027
2028 /* gdk_surface_is_destroyed() might already return TRUE for
2029 * seat->keyboard_focus here, which would happen if we destroyed the
2030 * surface before losing keyboard focus.
2031 */
2032 stop_key_repeat (seat);
2033
2034 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2035
2036 event = gdk_focus_event_new (surface: seat->keyboard_focus,
2037 device: seat->logical_keyboard,
2038 FALSE);
2039
2040 g_object_unref (object: seat->keyboard_focus);
2041 seat->keyboard_focus = NULL;
2042 seat->repeat_key = 0;
2043 seat->key_modifiers = 0;
2044
2045 GDK_SEAT_NOTE (seat, EVENTS,
2046 g_message ("focus out, seat %p surface %p",
2047 seat, gdk_event_get_surface (event)));
2048
2049 _gdk_wayland_display_deliver_event (display: seat->display, event);
2050}
2051
2052static gboolean keyboard_repeat (gpointer data);
2053
2054static gboolean
2055get_key_repeat (GdkWaylandSeat *seat,
2056 guint *delay,
2057 guint *interval)
2058{
2059 gboolean repeat;
2060
2061 if (seat->have_server_repeat)
2062 {
2063 if (seat->server_repeat_rate > 0)
2064 {
2065 repeat = TRUE;
2066 *delay = seat->server_repeat_delay;
2067 *interval = (1000 / seat->server_repeat_rate);
2068 }
2069 else
2070 {
2071 repeat = FALSE;
2072 }
2073 }
2074 else
2075 {
2076 repeat = TRUE;
2077 *delay = 400;
2078 *interval = 80;
2079 }
2080
2081 return repeat;
2082}
2083
2084static void
2085stop_key_repeat (GdkWaylandSeat *seat)
2086{
2087 if (seat->repeat_timer)
2088 {
2089 g_source_remove (tag: seat->repeat_timer);
2090 seat->repeat_timer = 0;
2091 }
2092
2093 g_clear_pointer (&seat->repeat_callback, wl_callback_destroy);
2094}
2095
2096static void
2097deliver_key_event (GdkWaylandSeat *seat,
2098 uint32_t time_,
2099 uint32_t key,
2100 uint32_t state,
2101 gboolean from_key_repeat)
2102{
2103 GdkEvent *event;
2104 struct xkb_state *xkb_state;
2105 struct xkb_keymap *xkb_keymap;
2106 GdkKeymap *keymap;
2107 guint delay, interval, timeout;
2108 gint64 begin_time, now;
2109 xkb_mod_mask_t consumed;
2110 GdkTranslatedKey translated;
2111 GdkTranslatedKey no_lock;
2112 xkb_mod_mask_t modifiers;
2113 xkb_mod_index_t caps_lock;
2114
2115 begin_time = g_get_monotonic_time ();
2116
2117 stop_key_repeat (seat);
2118
2119 keymap = seat->keymap;
2120 xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap);
2121 xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap);
2122
2123 translated.keyval = xkb_state_key_get_one_sym (state: xkb_state, key);
2124 modifiers = xkb_state_serialize_mods (state: xkb_state, components: XKB_STATE_MODS_EFFECTIVE);
2125 consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (state: xkb_state, key, mask: modifiers);
2126 translated.consumed = gdk_wayland_keymap_get_gdk_modifiers (keymap, mods: consumed);
2127 translated.layout = xkb_state_key_get_layout (state: xkb_state, key);
2128 translated.level = xkb_state_key_get_level (state: xkb_state, key, layout: translated.layout);
2129
2130 if (translated.keyval == XKB_KEY_NoSymbol)
2131 return;
2132
2133 seat->pointer_info.time = time_;
2134 seat->key_modifiers = gdk_keymap_get_modifier_state (keymap);
2135
2136
2137 modifiers = xkb_state_serialize_mods (state: xkb_state, components: XKB_STATE_MODS_EFFECTIVE);
2138 caps_lock = xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_CAPS);
2139 if (modifiers & (1 << caps_lock))
2140 {
2141 struct xkb_state *tmp_state = xkb_state_new (keymap: xkb_keymap);
2142 xkb_layout_index_t layout;
2143
2144 modifiers &= ~(1 << caps_lock);
2145 layout = xkb_state_serialize_layout (state: xkb_state, components: XKB_STATE_LAYOUT_EFFECTIVE);
2146 xkb_state_update_mask (state: tmp_state, depressed_mods: modifiers, latched_mods: 0, locked_mods: 0, depressed_layout: layout, latched_layout: 0, locked_layout: 0);
2147
2148 no_lock.keyval = xkb_state_key_get_one_sym (state: tmp_state, key);
2149 consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (state: tmp_state, key, mask: modifiers);
2150 no_lock.consumed = gdk_wayland_keymap_get_gdk_modifiers (keymap, mods: consumed);
2151 no_lock.layout = xkb_state_key_get_layout (state: tmp_state, key);
2152 no_lock.level = xkb_state_key_get_level (state: tmp_state, key, layout: no_lock.layout);
2153
2154 xkb_state_unref (state: tmp_state);
2155 }
2156 else
2157 {
2158 no_lock = translated;
2159 }
2160
2161 event = gdk_key_event_new (type: state ? GDK_KEY_PRESS : GDK_KEY_RELEASE,
2162 surface: seat->keyboard_focus,
2163 device: seat->logical_keyboard,
2164 time: time_,
2165 keycode: key,
2166 modifiers: device_get_modifiers (device: seat->logical_pointer),
2167 is_modifier: _gdk_wayland_keymap_key_is_modifier (keymap, keycode: key),
2168 translated: &translated,
2169 no_lock: &no_lock);
2170
2171 _gdk_wayland_display_deliver_event (display: seat->display, event);
2172
2173 GDK_SEAT_NOTE (seat, EVENTS,
2174 g_message ("keyboard %s event%s, surface %p, code %d, sym %d, "
2175 "mods 0x%x, consumed 0x%x, layout %d level %d",
2176 (state ? "press" : "release"),
2177 (from_key_repeat ? " (repeat)" : ""),
2178 gdk_event_get_surface (event),
2179 gdk_key_event_get_keycode (event),
2180 gdk_key_event_get_keyval (event),
2181 gdk_event_get_modifier_state (event),
2182 gdk_key_event_get_consumed_modifiers (event),
2183 gdk_key_event_get_layout (event),
2184 gdk_key_event_get_level (event)));
2185
2186 if (!xkb_keymap_key_repeats (keymap: xkb_keymap, key))
2187 return;
2188
2189 if (!get_key_repeat (seat, delay: &delay, interval: &interval))
2190 return;
2191
2192 if (!from_key_repeat)
2193 {
2194 if (state) /* Another key is pressed */
2195 {
2196 seat->repeat_key = key;
2197 }
2198 else if (seat->repeat_key == key) /* Repeated key is released */
2199 {
2200 seat->repeat_key = 0;
2201 }
2202 }
2203
2204 if (!seat->repeat_key)
2205 return;
2206
2207 seat->repeat_count++;
2208
2209 interval *= 1000L;
2210 delay *= 1000L;
2211
2212 now = g_get_monotonic_time ();
2213
2214 if (seat->repeat_count == 1)
2215 seat->repeat_deadline = begin_time + delay;
2216 else if (seat->repeat_deadline + interval > now)
2217 seat->repeat_deadline += interval;
2218 else
2219 /* frame delay caused us to miss repeat deadline */
2220 seat->repeat_deadline = now;
2221
2222 timeout = (seat->repeat_deadline - now) / 1000L;
2223
2224 seat->repeat_timer = g_timeout_add (interval: timeout, function: keyboard_repeat, data: seat);
2225 gdk_source_set_static_name_by_id (tag: seat->repeat_timer, name: "[gtk] keyboard_repeat");
2226}
2227
2228static void
2229sync_after_repeat_callback (void *data,
2230 struct wl_callback *callback,
2231 uint32_t time)
2232{
2233 GdkWaylandSeat *seat = data;
2234
2235 g_clear_pointer (&seat->repeat_callback, wl_callback_destroy);
2236 deliver_key_event (seat, time_: seat->keyboard_time, key: seat->repeat_key, state: 1, TRUE);
2237}
2238
2239static const struct wl_callback_listener sync_after_repeat_callback_listener = {
2240 sync_after_repeat_callback
2241};
2242
2243static gboolean
2244keyboard_repeat (gpointer data)
2245{
2246 GdkWaylandSeat *seat = data;
2247 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2248
2249 /* Ping the server and wait for the timeout. We won't process
2250 * key repeat until it responds, since a hung server could lead
2251 * to a delayed key release event. We don't want to generate
2252 * repeat events long after the user released the key, just because
2253 * the server is tardy in telling us the user released the key.
2254 */
2255 seat->repeat_callback = wl_display_sync (wl_display: display->wl_display);
2256
2257 wl_callback_add_listener (wl_callback: seat->repeat_callback,
2258 listener: &sync_after_repeat_callback_listener,
2259 data: seat);
2260
2261 seat->repeat_timer = 0;
2262 return G_SOURCE_REMOVE;
2263}
2264
2265static void
2266keyboard_handle_key (void *data,
2267 struct wl_keyboard *keyboard,
2268 uint32_t serial,
2269 uint32_t time,
2270 uint32_t key,
2271 uint32_t state_w)
2272{
2273 GdkWaylandSeat *seat = data;
2274 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2275
2276 if (!seat->keyboard_focus)
2277 return;
2278
2279 seat->keyboard_time = time;
2280 seat->keyboard_key_serial = serial;
2281 seat->repeat_count = 0;
2282 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2283 deliver_key_event (seat: data, time_: time, key: key + 8, state: state_w, FALSE);
2284
2285}
2286
2287static void
2288keyboard_handle_modifiers (void *data,
2289 struct wl_keyboard *keyboard,
2290 uint32_t serial,
2291 uint32_t mods_depressed,
2292 uint32_t mods_latched,
2293 uint32_t mods_locked,
2294 uint32_t group)
2295{
2296 GdkWaylandSeat *seat = data;
2297 GdkKeymap *keymap;
2298 struct xkb_state *xkb_state;
2299 PangoDirection direction;
2300 gboolean bidi;
2301 gboolean caps_lock;
2302 gboolean num_lock;
2303 gboolean scroll_lock;
2304 GdkModifierType modifiers;
2305 int layout;
2306
2307 keymap = seat->keymap;
2308 xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap);
2309
2310 direction = gdk_keymap_get_direction (keymap);
2311 bidi = gdk_keymap_have_bidi_layouts (keymap);
2312 caps_lock = gdk_keymap_get_caps_lock_state (keymap);
2313 num_lock = gdk_keymap_get_num_lock_state (keymap);
2314 scroll_lock = gdk_keymap_get_scroll_lock_state (keymap);
2315 modifiers = gdk_keymap_get_modifier_state (keymap);
2316 layout = get_active_layout (keymap);
2317
2318 /* Note: the docs for xkb_state_update mask state that all parameters
2319 * must be passed, or we may end up with an 'incoherent' state. But the
2320 * Wayland modifiers event only includes a single group field, so we
2321 * can't pass depressed/latched/locked groups.
2322 *
2323 * We assume that the compositor is sending us the 'effective' group
2324 * (the protocol is not clear on that point), and pass it as the depressed
2325 * group - we are basically pretending that the user holds down a key for
2326 * this group at all times.
2327 *
2328 * This means that our xkb_state would answer a few questions differently
2329 * from the compositors xkb_state - e.g. if you asked it about the latched
2330 * group. But nobody is asking it those questions, so it does not really
2331 * matter. We hope.
2332 */
2333 xkb_state_update_mask (state: xkb_state, depressed_mods: mods_depressed, latched_mods: mods_latched, locked_mods: mods_locked, depressed_layout: group, latched_layout: 0, locked_layout: 0);
2334
2335 seat->key_modifiers = gdk_keymap_get_modifier_state (keymap);
2336
2337 g_signal_emit_by_name (instance: keymap, detailed_signal: "state-changed");
2338 if (layout != get_active_layout (keymap))
2339 {
2340 GDK_DISPLAY_NOTE(keymap->display, INPUT, g_print ("active layout now: %s\n", get_active_layout_name (keymap)));
2341
2342 g_signal_emit_by_name (instance: keymap, detailed_signal: "keys-changed");
2343 }
2344 if (direction != gdk_keymap_get_direction (keymap))
2345 {
2346 g_signal_emit_by_name (instance: keymap, detailed_signal: "direction-changed");
2347 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "direction");
2348 }
2349 if (bidi != gdk_keymap_have_bidi_layouts (keymap))
2350 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "has-bidi-layouts");
2351 if (caps_lock != gdk_keymap_get_caps_lock_state (keymap))
2352 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "caps-lock-state");
2353 if (num_lock != gdk_keymap_get_num_lock_state (keymap))
2354 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "num-lock-state");
2355 if (scroll_lock != gdk_keymap_get_scroll_lock_state (keymap))
2356 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "scroll-lock-state");
2357 if (modifiers != gdk_keymap_get_modifier_state (keymap))
2358 g_object_notify (G_OBJECT (seat->logical_keyboard), property_name: "modifier-state");
2359}
2360
2361static void
2362keyboard_handle_repeat_info (void *data,
2363 struct wl_keyboard *keyboard,
2364 int32_t rate,
2365 int32_t delay)
2366{
2367 GdkWaylandSeat *seat = data;
2368
2369 seat->have_server_repeat = TRUE;
2370 seat->server_repeat_rate = rate;
2371 seat->server_repeat_delay = delay;
2372}
2373
2374static GdkWaylandTouchData *
2375gdk_wayland_seat_add_touch (GdkWaylandSeat *seat,
2376 uint32_t id,
2377 struct wl_surface *surface)
2378{
2379 GdkWaylandTouchData *touch;
2380
2381 touch = g_new0 (GdkWaylandTouchData, 1);
2382 touch->id = id;
2383 touch->surface = wl_surface_get_user_data (wl_surface: surface);
2384 touch->initial_touch = (g_hash_table_size (hash_table: seat->touches) == 0);
2385
2386 g_hash_table_insert (hash_table: seat->touches, GUINT_TO_POINTER (id), value: touch);
2387
2388 return touch;
2389}
2390
2391static GdkWaylandTouchData *
2392gdk_wayland_seat_get_touch (GdkWaylandSeat *seat,
2393 uint32_t id)
2394{
2395 return g_hash_table_lookup (hash_table: seat->touches, GUINT_TO_POINTER (id));
2396}
2397
2398static void
2399gdk_wayland_seat_remove_touch (GdkWaylandSeat *seat,
2400 uint32_t id)
2401{
2402 g_hash_table_remove (hash_table: seat->touches, GUINT_TO_POINTER (id));
2403}
2404
2405void
2406gdk_wayland_seat_clear_touchpoints (GdkWaylandSeat *seat,
2407 GdkSurface *surface)
2408{
2409 GHashTableIter iter;
2410 GdkWaylandTouchData *touch;
2411
2412 g_hash_table_iter_init (iter: &iter, hash_table: seat->touches);
2413
2414 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer *) &touch))
2415 {
2416 if (touch->surface == surface)
2417 g_hash_table_iter_remove (iter: &iter);
2418 }
2419}
2420
2421static void
2422mimic_pointer_emulating_touch_info (GdkDevice *device,
2423 GdkWaylandTouchData *touch)
2424{
2425 GdkWaylandPointerData *pointer;
2426
2427 pointer = GDK_WAYLAND_DEVICE (device)->pointer;
2428 g_set_object (&pointer->focus, touch->surface);
2429 pointer->press_serial = pointer->enter_serial = touch->touch_down_serial;
2430 pointer->surface_x = touch->x;
2431 pointer->surface_y = touch->y;
2432}
2433
2434static void
2435touch_handle_logical_pointer_crossing (GdkWaylandSeat *seat,
2436 GdkWaylandTouchData *touch,
2437 uint32_t time)
2438{
2439 GdkWaylandPointerData *pointer;
2440
2441 pointer = GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer;
2442
2443 if (pointer->focus == touch->surface)
2444 return;
2445
2446 if (pointer->focus)
2447 {
2448 emulate_touch_crossing (surface: pointer->focus, NULL,
2449 device: seat->logical_touch, source: seat->touch, touch,
2450 type: GDK_LEAVE_NOTIFY, mode: GDK_CROSSING_NORMAL, time_: time);
2451 }
2452
2453 if (touch->surface)
2454 {
2455 emulate_touch_crossing (surface: touch->surface, NULL,
2456 device: seat->logical_touch, source: seat->touch, touch,
2457 type: GDK_ENTER_NOTIFY, mode: GDK_CROSSING_NORMAL, time_: time);
2458 }
2459}
2460
2461static void
2462touch_handle_down (void *data,
2463 struct wl_touch *wl_touch,
2464 uint32_t serial,
2465 uint32_t time,
2466 struct wl_surface *wl_surface,
2467 int32_t id,
2468 wl_fixed_t x,
2469 wl_fixed_t y)
2470{
2471 GdkWaylandSeat *seat = data;
2472 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2473 GdkWaylandTouchData *touch;
2474 GdkEvent *event;
2475
2476 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2477
2478 if (!wl_surface)
2479 return;
2480
2481 touch = gdk_wayland_seat_add_touch (seat, id, surface: wl_surface);
2482 touch->x = wl_fixed_to_double (f: x);
2483 touch->y = wl_fixed_to_double (f: y);
2484 touch->touch_down_serial = serial;
2485
2486 event = gdk_touch_event_new (type: GDK_TOUCH_BEGIN,
2487 GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
2488 surface: touch->surface,
2489 device: seat->logical_touch,
2490 time,
2491 state: device_get_modifiers (device: seat->logical_touch),
2492 x: touch->x, y: touch->y,
2493 NULL,
2494 emulating: touch->initial_touch);
2495
2496 if (touch->initial_touch)
2497 {
2498 touch_handle_logical_pointer_crossing (seat, touch, time);
2499 GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = touch;
2500 mimic_pointer_emulating_touch_info (device: seat->logical_touch, touch);
2501 }
2502
2503 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
2504 {
2505 double xx, yy;
2506 gdk_event_get_position (event, x: &xx, y: &yy);
2507 g_message ("touch begin %f %f", xx, yy);
2508 }
2509
2510 _gdk_wayland_display_deliver_event (display: seat->display, event);
2511}
2512
2513static void
2514touch_handle_up (void *data,
2515 struct wl_touch *wl_touch,
2516 uint32_t serial,
2517 uint32_t time,
2518 int32_t id)
2519{
2520 GdkWaylandSeat *seat = data;
2521 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2522 GdkWaylandTouchData *touch;
2523 GdkEvent *event;
2524
2525 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2526
2527 touch = gdk_wayland_seat_get_touch (seat, id);
2528 if (!touch)
2529 return;
2530
2531 event = gdk_touch_event_new (type: GDK_TOUCH_END,
2532 GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
2533 surface: touch->surface,
2534 device: seat->logical_touch,
2535 time,
2536 state: device_get_modifiers (device: seat->logical_touch),
2537 x: touch->x, y: touch->y,
2538 NULL,
2539 emulating: touch->initial_touch);
2540
2541 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
2542 {
2543 double x, y;
2544 gdk_event_get_position (event, x: &x, y: &y);
2545 g_message ("touch end %f %f", x, y);
2546 }
2547
2548 _gdk_wayland_display_deliver_event (display: seat->display, event);
2549
2550 if (touch->initial_touch)
2551 GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = NULL;
2552
2553 gdk_wayland_seat_remove_touch (seat, id);
2554}
2555
2556static void
2557touch_handle_motion (void *data,
2558 struct wl_touch *wl_touch,
2559 uint32_t time,
2560 int32_t id,
2561 wl_fixed_t x,
2562 wl_fixed_t y)
2563{
2564 GdkWaylandSeat *seat = data;
2565 GdkWaylandTouchData *touch;
2566 GdkEvent *event;
2567
2568 touch = gdk_wayland_seat_get_touch (seat, id);
2569 if (!touch)
2570 return;
2571
2572 touch->x = wl_fixed_to_double (f: x);
2573 touch->y = wl_fixed_to_double (f: y);
2574
2575 if (touch->initial_touch)
2576 mimic_pointer_emulating_touch_info (device: seat->logical_touch, touch);
2577
2578 event = gdk_touch_event_new (type: GDK_TOUCH_UPDATE,
2579 GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
2580 surface: touch->surface,
2581 device: seat->logical_touch,
2582 time,
2583 state: device_get_modifiers (device: seat->logical_touch),
2584 x: touch->x, y: touch->y,
2585 NULL,
2586 emulating: touch->initial_touch);
2587
2588 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
2589 {
2590 double xx, yy;
2591 gdk_event_get_position (event, x: &xx, y: &yy);
2592 g_message ("touch update %f %f", xx, yy);
2593 }
2594
2595 _gdk_wayland_display_deliver_event (display: seat->display, event);
2596}
2597
2598static void
2599touch_handle_frame (void *data,
2600 struct wl_touch *wl_touch)
2601{
2602}
2603
2604static void
2605touch_handle_cancel (void *data,
2606 struct wl_touch *wl_touch)
2607{
2608 GdkWaylandSeat *seat = data;
2609 GdkWaylandTouchData *touch;
2610 GHashTableIter iter;
2611 GdkEvent *event;
2612
2613 if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch)
2614 {
2615 touch = GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch;
2616 GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL;
2617 }
2618
2619 g_hash_table_iter_init (iter: &iter, hash_table: seat->touches);
2620
2621 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer *) &touch))
2622 {
2623 event = gdk_touch_event_new (type: GDK_TOUCH_CANCEL,
2624 GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
2625 surface: touch->surface,
2626 device: seat->logical_touch,
2627 GDK_CURRENT_TIME,
2628 state: device_get_modifiers (device: seat->logical_touch),
2629 x: touch->x, y: touch->y,
2630 NULL,
2631 emulating: touch->initial_touch);
2632 _gdk_wayland_display_deliver_event (display: seat->display, event);
2633 g_hash_table_iter_remove (iter: &iter);
2634 }
2635
2636 GDK_SEAT_NOTE (seat, EVENTS, g_message ("touch cancel"));
2637}
2638
2639static void
2640touch_handle_shape (void *data,
2641 struct wl_touch *touch,
2642 int32_t id,
2643 wl_fixed_t major,
2644 wl_fixed_t minor)
2645{
2646}
2647
2648static void
2649touch_handle_orientation (void *data,
2650 struct wl_touch *touch,
2651 int32_t id,
2652 wl_fixed_t orientation)
2653{
2654}
2655
2656static void
2657emit_gesture_swipe_event (GdkWaylandSeat *seat,
2658 GdkTouchpadGesturePhase phase,
2659 guint32 _time,
2660 guint32 n_fingers,
2661 double dx,
2662 double dy)
2663{
2664 GdkEvent *event;
2665
2666 if (!seat->pointer_info.focus)
2667 return;
2668
2669 seat->pointer_info.time = _time;
2670
2671 if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
2672 seat->pointer_info.touchpad_event_sequence++;
2673
2674 event = gdk_touchpad_event_new_swipe (surface: seat->pointer_info.focus,
2675 GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence),
2676 device: seat->logical_pointer,
2677 time: _time,
2678 state: device_get_modifiers (device: seat->logical_pointer),
2679 phase,
2680 x: seat->pointer_info.surface_x,
2681 y: seat->pointer_info.surface_y,
2682 n_fingers,
2683 dx, dy);
2684
2685 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
2686 {
2687 double x, y;
2688 gdk_event_get_position (event, x: &x, y: &y);
2689 g_message ("swipe event %d, coords: %f %f, seat %p state %d",
2690 gdk_event_get_event_type (event), x, y, seat,
2691 gdk_event_get_modifier_state (event));
2692 }
2693
2694 _gdk_wayland_display_deliver_event (display: seat->display, event);
2695}
2696
2697static void
2698gesture_swipe_begin (void *data,
2699 struct zwp_pointer_gesture_swipe_v1 *swipe,
2700 uint32_t serial,
2701 uint32_t time,
2702 struct wl_surface *surface,
2703 uint32_t fingers)
2704{
2705 GdkWaylandSeat *seat = data;
2706 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2707
2708 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2709
2710 emit_gesture_swipe_event (seat,
2711 phase: GDK_TOUCHPAD_GESTURE_PHASE_BEGIN,
2712 time: time, n_fingers: fingers, dx: 0, dy: 0);
2713 seat->gesture_n_fingers = fingers;
2714}
2715
2716static void
2717gesture_swipe_update (void *data,
2718 struct zwp_pointer_gesture_swipe_v1 *swipe,
2719 uint32_t time,
2720 wl_fixed_t dx,
2721 wl_fixed_t dy)
2722{
2723 GdkWaylandSeat *seat = data;
2724
2725 emit_gesture_swipe_event (seat,
2726 phase: GDK_TOUCHPAD_GESTURE_PHASE_UPDATE,
2727 time: time,
2728 n_fingers: seat->gesture_n_fingers,
2729 dx: wl_fixed_to_double (f: dx),
2730 dy: wl_fixed_to_double (f: dy));
2731}
2732
2733static void
2734gesture_swipe_end (void *data,
2735 struct zwp_pointer_gesture_swipe_v1 *swipe,
2736 uint32_t serial,
2737 uint32_t time,
2738 int32_t cancelled)
2739{
2740 GdkWaylandSeat *seat = data;
2741 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2742 GdkTouchpadGesturePhase phase;
2743
2744 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2745
2746 phase = (cancelled) ?
2747 GDK_TOUCHPAD_GESTURE_PHASE_CANCEL :
2748 GDK_TOUCHPAD_GESTURE_PHASE_END;
2749
2750 emit_gesture_swipe_event (seat, phase, time: time,
2751 n_fingers: seat->gesture_n_fingers, dx: 0, dy: 0);
2752}
2753
2754static void
2755emit_gesture_pinch_event (GdkWaylandSeat *seat,
2756 GdkTouchpadGesturePhase phase,
2757 guint32 _time,
2758 guint n_fingers,
2759 double dx,
2760 double dy,
2761 double scale,
2762 double angle_delta)
2763{
2764 GdkEvent *event;
2765
2766 if (!seat->pointer_info.focus)
2767 return;
2768
2769 seat->pointer_info.time = _time;
2770
2771 if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
2772 seat->pointer_info.touchpad_event_sequence++;
2773
2774 event = gdk_touchpad_event_new_pinch (surface: seat->pointer_info.focus,
2775 GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence),
2776 device: seat->logical_pointer,
2777 time: _time,
2778 state: device_get_modifiers (device: seat->logical_pointer),
2779 phase,
2780 x: seat->pointer_info.surface_x,
2781 y: seat->pointer_info.surface_y,
2782 n_fingers,
2783 dx, dy,
2784 scale, angle_delta: angle_delta * G_PI / 180);
2785
2786 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
2787 {
2788 double x, y;
2789 gdk_event_get_position (event, x: &x, y: &y);
2790 g_message ("pinch event %d, coords: %f %f, seat %p state %d",
2791 gdk_event_get_event_type (event),
2792 x, y, seat,
2793 gdk_event_get_modifier_state (event));
2794 }
2795
2796 _gdk_wayland_display_deliver_event (display: seat->display, event);
2797}
2798
2799static void
2800gesture_pinch_begin (void *data,
2801 struct zwp_pointer_gesture_pinch_v1 *pinch,
2802 uint32_t serial,
2803 uint32_t time,
2804 struct wl_surface *surface,
2805 uint32_t fingers)
2806{
2807 GdkWaylandSeat *seat = data;
2808 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2809
2810 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2811 emit_gesture_pinch_event (seat,
2812 phase: GDK_TOUCHPAD_GESTURE_PHASE_BEGIN,
2813 time: time, n_fingers: fingers, dx: 0, dy: 0, scale: 1, angle_delta: 0);
2814 seat->gesture_n_fingers = fingers;
2815}
2816
2817static void
2818gesture_pinch_update (void *data,
2819 struct zwp_pointer_gesture_pinch_v1 *pinch,
2820 uint32_t time,
2821 wl_fixed_t dx,
2822 wl_fixed_t dy,
2823 wl_fixed_t scale,
2824 wl_fixed_t rotation)
2825{
2826 GdkWaylandSeat *seat = data;
2827
2828 emit_gesture_pinch_event (seat,
2829 phase: GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, time: time,
2830 n_fingers: seat->gesture_n_fingers,
2831 dx: wl_fixed_to_double (f: dx),
2832 dy: wl_fixed_to_double (f: dy),
2833 scale: wl_fixed_to_double (f: scale),
2834 angle_delta: wl_fixed_to_double (f: rotation));
2835}
2836
2837static void
2838gesture_pinch_end (void *data,
2839 struct zwp_pointer_gesture_pinch_v1 *pinch,
2840 uint32_t serial,
2841 uint32_t time,
2842 int32_t cancelled)
2843{
2844 GdkWaylandSeat *seat = data;
2845 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2846 GdkTouchpadGesturePhase phase;
2847
2848 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2849
2850 phase = (cancelled) ?
2851 GDK_TOUCHPAD_GESTURE_PHASE_CANCEL :
2852 GDK_TOUCHPAD_GESTURE_PHASE_END;
2853
2854 emit_gesture_pinch_event (seat, phase,
2855 time: time, n_fingers: seat->gesture_n_fingers,
2856 dx: 0, dy: 0, scale: 1, angle_delta: 0);
2857}
2858
2859static void
2860emit_gesture_hold_event (GdkWaylandSeat *seat,
2861 GdkTouchpadGesturePhase phase,
2862 guint32 _time,
2863 guint32 n_fingers)
2864{
2865 GdkEvent *event;
2866
2867 if (!seat->pointer_info.focus)
2868 return;
2869
2870 seat->pointer_info.time = _time;
2871
2872 event = gdk_touchpad_event_new_hold (surface: seat->pointer_info.focus,
2873 device: seat->logical_pointer,
2874 time: _time,
2875 state: device_get_modifiers (device: seat->logical_pointer),
2876 phase,
2877 x: seat->pointer_info.surface_x,
2878 y: seat->pointer_info.surface_y,
2879 n_fingers);
2880
2881 if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS))
2882 {
2883 double x, y;
2884 gdk_event_get_position (event, x: &x, y: &y);
2885 g_message ("hold event %d, coords: %f %f, seat %p state %d",
2886 gdk_event_get_event_type (event),
2887 x, y, seat,
2888 gdk_event_get_modifier_state (event));
2889 }
2890
2891 _gdk_wayland_display_deliver_event (display: seat->display, event);
2892}
2893
2894static void
2895gesture_hold_begin (void *data,
2896 struct zwp_pointer_gesture_hold_v1 *hold,
2897 uint32_t serial,
2898 uint32_t time,
2899 struct wl_surface *surface,
2900 uint32_t fingers)
2901{
2902 GdkWaylandSeat *seat = data;
2903 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2904
2905 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2906
2907 emit_gesture_hold_event (seat,
2908 phase: GDK_TOUCHPAD_GESTURE_PHASE_BEGIN,
2909 time: time, n_fingers: fingers);
2910 seat->gesture_n_fingers = fingers;
2911}
2912
2913static void
2914gesture_hold_end (void *data,
2915 struct zwp_pointer_gesture_hold_v1 *hold,
2916 uint32_t serial,
2917 uint32_t time,
2918 int32_t cancelled)
2919{
2920 GdkWaylandSeat *seat = data;
2921 GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display);
2922 GdkTouchpadGesturePhase phase;
2923
2924 _gdk_wayland_display_update_serial (display_wayland: display, serial);
2925
2926 phase = (cancelled) ?
2927 GDK_TOUCHPAD_GESTURE_PHASE_CANCEL :
2928 GDK_TOUCHPAD_GESTURE_PHASE_END;
2929
2930 emit_gesture_hold_event (seat, phase, time: time,
2931 n_fingers: seat->gesture_n_fingers);
2932}
2933
2934static void
2935_gdk_wayland_seat_remove_tool (GdkWaylandSeat *seat,
2936 GdkWaylandTabletToolData *tool)
2937{
2938 seat->tablet_tools = g_list_remove (list: seat->tablet_tools, data: tool);
2939
2940 gdk_seat_tool_removed (GDK_SEAT (seat), tool: tool->tool);
2941
2942 zwp_tablet_tool_v2_destroy (tool->wp_tablet_tool);
2943 g_object_unref (object: tool->tool);
2944 g_free (mem: tool);
2945}
2946
2947static void
2948_gdk_wayland_seat_remove_tablet (GdkWaylandSeat *seat,
2949 GdkWaylandTabletData *tablet)
2950{
2951 seat->tablets = g_list_remove (list: seat->tablets, data: tablet);
2952
2953 gdk_seat_device_removed (GDK_SEAT (seat), device: tablet->stylus_device);
2954 gdk_seat_device_removed (GDK_SEAT (seat), device: tablet->logical_device);
2955
2956 while (tablet->pads)
2957 {
2958 GdkWaylandTabletPadData *pad = tablet->pads->data;
2959
2960 pad->current_tablet = NULL;
2961 tablet->pads = g_list_remove (list: tablet->pads, data: pad);
2962 }
2963
2964 zwp_tablet_v2_destroy (tablet->wp_tablet);
2965
2966 _gdk_device_set_associated_device (device: tablet->logical_device, NULL);
2967 _gdk_device_set_associated_device (device: tablet->stylus_device, NULL);
2968
2969 if (tablet->pointer_info.focus)
2970 g_object_unref (object: tablet->pointer_info.focus);
2971
2972 wl_surface_destroy (wl_surface: tablet->pointer_info.pointer_surface);
2973 g_object_unref (object: tablet->logical_device);
2974 g_object_unref (object: tablet->stylus_device);
2975 g_free (mem: tablet);
2976}
2977
2978static void
2979_gdk_wayland_seat_remove_tablet_pad (GdkWaylandSeat *seat,
2980 GdkWaylandTabletPadData *pad)
2981{
2982 seat->tablet_pads = g_list_remove (list: seat->tablet_pads, data: pad);
2983
2984 gdk_seat_device_removed (GDK_SEAT (seat), device: pad->device);
2985 _gdk_device_set_associated_device (device: pad->device, NULL);
2986
2987 g_object_unref (object: pad->device);
2988 g_free (mem: pad);
2989}
2990
2991static GdkWaylandTabletPadGroupData *
2992tablet_pad_lookup_button_group (GdkWaylandTabletPadData *pad,
2993 uint32_t button)
2994{
2995 GdkWaylandTabletPadGroupData *group;
2996 GList *l;
2997
2998 for (l = pad->mode_groups; l; l = l->next)
2999 {
3000 group = l->data;
3001
3002 if (g_list_find (list: group->buttons, GUINT_TO_POINTER (button)))
3003 return group;
3004 }
3005
3006 return NULL;
3007}
3008
3009static void
3010tablet_handle_name (void *data,
3011 struct zwp_tablet_v2 *wp_tablet,
3012 const char *name)
3013{
3014 GdkWaylandTabletData *tablet = data;
3015
3016 tablet->name = g_strdup (str: name);
3017}
3018
3019static void
3020tablet_handle_id (void *data,
3021 struct zwp_tablet_v2 *wp_tablet,
3022 uint32_t vid,
3023 uint32_t pid)
3024{
3025 GdkWaylandTabletData *tablet = data;
3026
3027 tablet->vid = vid;
3028 tablet->pid = pid;
3029}
3030
3031static void
3032tablet_handle_path (void *data,
3033 struct zwp_tablet_v2 *wp_tablet,
3034 const char *path)
3035{
3036 GdkWaylandTabletData *tablet = data;
3037
3038 tablet->path = g_strdup (str: path);
3039}
3040
3041static void
3042tablet_handle_done (void *data,
3043 struct zwp_tablet_v2 *wp_tablet)
3044{
3045 GdkWaylandTabletData *tablet = data;
3046 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
3047 GdkDisplay *display = gdk_seat_get_display (GDK_SEAT (seat));
3048 GdkDevice *logical_device, *stylus_device;
3049 char *logical_name;
3050 char *vid, *pid;
3051
3052 vid = g_strdup_printf (format: "%.4x", tablet->vid);
3053 pid = g_strdup_printf (format: "%.4x", tablet->pid);
3054
3055 logical_name = g_strdup_printf (format: "Logical pointer for %s", tablet->name);
3056 logical_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3057 first_property_name: "name", logical_name,
3058 "source", GDK_SOURCE_MOUSE,
3059 "has-cursor", TRUE,
3060 "display", display,
3061 "seat", seat,
3062 NULL);
3063 GDK_WAYLAND_DEVICE (logical_device)->pointer = &tablet->pointer_info;
3064
3065 stylus_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3066 first_property_name: "name", tablet->name,
3067 "source", GDK_SOURCE_PEN,
3068 "has-cursor", FALSE,
3069 "display", display,
3070 "seat", seat,
3071 "vendor-id", vid,
3072 "product-id", pid,
3073 NULL);
3074
3075 tablet->logical_device = logical_device;
3076 init_pointer_data (pointer_data: &tablet->pointer_info, display_wayland: display, logical_device: tablet->logical_device);
3077
3078 tablet->stylus_device = stylus_device;
3079
3080 _gdk_device_set_associated_device (device: logical_device, relative: seat->logical_keyboard);
3081 _gdk_device_set_associated_device (device: stylus_device, relative: logical_device);
3082
3083 gdk_seat_device_added (GDK_SEAT (seat), device: logical_device);
3084 gdk_seat_device_added (GDK_SEAT (seat), device: stylus_device);
3085
3086 g_free (mem: logical_name);
3087 g_free (mem: vid);
3088 g_free (mem: pid);
3089}
3090
3091static void
3092tablet_handle_removed (void *data,
3093 struct zwp_tablet_v2 *wp_tablet)
3094{
3095 GdkWaylandTabletData *tablet = data;
3096
3097 _gdk_wayland_seat_remove_tablet (GDK_WAYLAND_SEAT (tablet->seat), tablet);
3098}
3099
3100static const struct wl_pointer_listener pointer_listener = {
3101 pointer_handle_enter,
3102 pointer_handle_leave,
3103 pointer_handle_motion,
3104 pointer_handle_button,
3105 pointer_handle_axis,
3106 pointer_handle_frame,
3107 pointer_handle_axis_source,
3108 pointer_handle_axis_stop,
3109 pointer_handle_axis_discrete,
3110};
3111
3112static const struct wl_keyboard_listener keyboard_listener = {
3113 keyboard_handle_keymap,
3114 keyboard_handle_enter,
3115 keyboard_handle_leave,
3116 keyboard_handle_key,
3117 keyboard_handle_modifiers,
3118 keyboard_handle_repeat_info,
3119};
3120
3121static const struct wl_touch_listener touch_listener = {
3122 touch_handle_down,
3123 touch_handle_up,
3124 touch_handle_motion,
3125 touch_handle_frame,
3126 touch_handle_cancel,
3127 touch_handle_shape,
3128 touch_handle_orientation,
3129};
3130
3131static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = {
3132 gesture_swipe_begin,
3133 gesture_swipe_update,
3134 gesture_swipe_end
3135};
3136
3137static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = {
3138 gesture_pinch_begin,
3139 gesture_pinch_update,
3140 gesture_pinch_end
3141};
3142
3143static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = {
3144 gesture_hold_begin,
3145 gesture_hold_end
3146};
3147
3148static const struct zwp_tablet_v2_listener tablet_listener = {
3149 tablet_handle_name,
3150 tablet_handle_id,
3151 tablet_handle_path,
3152 tablet_handle_done,
3153 tablet_handle_removed,
3154};
3155
3156static void
3157seat_handle_capabilities (void *data,
3158 struct wl_seat *wl_seat,
3159 enum wl_seat_capability caps)
3160{
3161 GdkWaylandSeat *seat = data;
3162 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
3163
3164 GDK_SEAT_NOTE (seat, MISC,
3165 g_message ("seat %p with %s%s%s", wl_seat,
3166 (caps & WL_SEAT_CAPABILITY_POINTER) ? " pointer, " : "",
3167 (caps & WL_SEAT_CAPABILITY_KEYBOARD) ? " keyboard, " : "",
3168 (caps & WL_SEAT_CAPABILITY_TOUCH) ? " touch" : ""));
3169
3170 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer)
3171 {
3172 seat->wl_pointer = wl_seat_get_pointer (wl_seat);
3173 wl_pointer_set_user_data (wl_pointer: seat->wl_pointer, user_data: seat);
3174 wl_pointer_add_listener (wl_pointer: seat->wl_pointer, listener: &pointer_listener, data: seat);
3175
3176 seat->pointer = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3177 first_property_name: "name", "Wayland Pointer",
3178 "source", GDK_SOURCE_MOUSE,
3179 "has-cursor", TRUE,
3180 "display", seat->display,
3181 "seat", seat,
3182 NULL);
3183 _gdk_device_set_associated_device (device: seat->pointer, relative: seat->logical_pointer);
3184 gdk_seat_device_added (GDK_SEAT (seat), device: seat->pointer);
3185
3186 if (display_wayland->pointer_gestures)
3187 {
3188 seat->wp_pointer_gesture_swipe =
3189 zwp_pointer_gestures_v1_get_swipe_gesture (display_wayland->pointer_gestures,
3190 seat->wl_pointer);
3191 zwp_pointer_gesture_swipe_v1_set_user_data (seat->wp_pointer_gesture_swipe,
3192 seat);
3193 zwp_pointer_gesture_swipe_v1_add_listener (seat->wp_pointer_gesture_swipe,
3194 &gesture_swipe_listener, seat);
3195
3196 seat->wp_pointer_gesture_pinch =
3197 zwp_pointer_gestures_v1_get_pinch_gesture (display_wayland->pointer_gestures,
3198 seat->wl_pointer);
3199 zwp_pointer_gesture_pinch_v1_set_user_data (seat->wp_pointer_gesture_pinch,
3200 seat);
3201 zwp_pointer_gesture_pinch_v1_add_listener (seat->wp_pointer_gesture_pinch,
3202 &gesture_pinch_listener, seat);
3203
3204 if (display_wayland->pointer_gestures_version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE_SINCE_VERSION)
3205 {
3206 seat->wp_pointer_gesture_hold =
3207 zwp_pointer_gestures_v1_get_hold_gesture (display_wayland->pointer_gestures,
3208 seat->wl_pointer);
3209 zwp_pointer_gesture_hold_v1_set_user_data (seat->wp_pointer_gesture_hold,
3210 seat);
3211 zwp_pointer_gesture_hold_v1_add_listener (seat->wp_pointer_gesture_hold,
3212 &gesture_hold_listener, seat);
3213 }
3214 }
3215 }
3216 else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer)
3217 {
3218 g_clear_pointer (&seat->wp_pointer_gesture_swipe,
3219 zwp_pointer_gesture_swipe_v1_destroy);
3220 g_clear_pointer (&seat->wp_pointer_gesture_pinch,
3221 zwp_pointer_gesture_pinch_v1_destroy);
3222
3223 wl_pointer_release (wl_pointer: seat->wl_pointer);
3224 seat->wl_pointer = NULL;
3225 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->pointer);
3226 _gdk_device_set_associated_device (device: seat->pointer, NULL);
3227
3228 g_clear_object (&seat->pointer);
3229
3230 if (seat->wheel_scrolling)
3231 {
3232 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->wheel_scrolling);
3233 _gdk_device_set_associated_device (device: seat->wheel_scrolling, NULL);
3234
3235 g_clear_object (&seat->wheel_scrolling);
3236 }
3237
3238 if (seat->finger_scrolling)
3239 {
3240 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->finger_scrolling);
3241 _gdk_device_set_associated_device (device: seat->finger_scrolling, NULL);
3242
3243 g_clear_object (&seat->finger_scrolling);
3244 }
3245
3246 if (seat->continuous_scrolling)
3247 {
3248 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->continuous_scrolling);
3249 _gdk_device_set_associated_device (device: seat->continuous_scrolling, NULL);
3250
3251 g_clear_object (&seat->continuous_scrolling);
3252 }
3253 }
3254
3255 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !seat->wl_keyboard)
3256 {
3257 seat->wl_keyboard = wl_seat_get_keyboard (wl_seat);
3258 wl_keyboard_set_user_data (wl_keyboard: seat->wl_keyboard, user_data: seat);
3259 wl_keyboard_add_listener (wl_keyboard: seat->wl_keyboard, listener: &keyboard_listener, data: seat);
3260
3261 seat->keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3262 first_property_name: "name", "Wayland Keyboard",
3263 "source", GDK_SOURCE_KEYBOARD,
3264 "has-cursor", FALSE,
3265 "display", seat->display,
3266 "seat", seat,
3267 NULL);
3268 _gdk_device_reset_axes (device: seat->keyboard);
3269 _gdk_device_set_associated_device (device: seat->keyboard, relative: seat->logical_keyboard);
3270 gdk_seat_device_added (GDK_SEAT (seat), device: seat->keyboard);
3271 }
3272 else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard)
3273 {
3274 wl_keyboard_release (wl_keyboard: seat->wl_keyboard);
3275 seat->wl_keyboard = NULL;
3276 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->keyboard);
3277 _gdk_device_set_associated_device (device: seat->keyboard, NULL);
3278
3279 g_clear_object (&seat->keyboard);
3280 }
3281
3282 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !seat->wl_touch)
3283 {
3284 seat->wl_touch = wl_seat_get_touch (wl_seat);
3285 wl_touch_set_user_data (wl_touch: seat->wl_touch, user_data: seat);
3286 wl_touch_add_listener (wl_touch: seat->wl_touch, listener: &touch_listener, data: seat);
3287
3288 seat->logical_touch = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3289 first_property_name: "name", "Wayland Touch Logical Pointer",
3290 "source", GDK_SOURCE_TOUCHSCREEN,
3291 "has-cursor", TRUE,
3292 "display", seat->display,
3293 "seat", seat,
3294 NULL);
3295 GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer = &seat->touch_info;
3296 _gdk_device_set_associated_device (device: seat->logical_touch, relative: seat->logical_keyboard);
3297 gdk_seat_device_added (GDK_SEAT (seat), device: seat->logical_touch);
3298
3299 seat->touch = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3300 first_property_name: "name", "Wayland Touch",
3301 "source", GDK_SOURCE_TOUCHSCREEN,
3302 "has-cursor", FALSE,
3303 "display", seat->display,
3304 "seat", seat,
3305 NULL);
3306 _gdk_device_set_associated_device (device: seat->touch, relative: seat->logical_touch);
3307 gdk_seat_device_added (GDK_SEAT (seat), device: seat->touch);
3308 }
3309 else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch)
3310 {
3311 wl_touch_release (wl_touch: seat->wl_touch);
3312 seat->wl_touch = NULL;
3313 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->touch);
3314 gdk_seat_device_removed (GDK_SEAT (seat), device: seat->logical_touch);
3315 _gdk_device_set_associated_device (device: seat->logical_touch, NULL);
3316 _gdk_device_set_associated_device (device: seat->touch, NULL);
3317
3318 g_clear_object (&seat->logical_touch);
3319 g_clear_object (&seat->touch);
3320 }
3321}
3322
3323static GdkDevice *
3324get_scroll_device (GdkWaylandSeat *seat,
3325 enum wl_pointer_axis_source source)
3326{
3327 if (!seat->pointer)
3328 return NULL;
3329
3330 switch (source)
3331 {
3332 case WL_POINTER_AXIS_SOURCE_WHEEL:
3333 if (seat->wheel_scrolling == NULL)
3334 {
3335 seat->wheel_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3336 first_property_name: "name", "Wayland Wheel Scrolling",
3337 "source", GDK_SOURCE_MOUSE,
3338 "has-cursor", TRUE,
3339 "display", seat->display,
3340 "seat", seat,
3341 NULL);
3342 gdk_seat_device_added (GDK_SEAT (seat), device: seat->wheel_scrolling);
3343 }
3344 return seat->wheel_scrolling;
3345
3346 case WL_POINTER_AXIS_SOURCE_FINGER:
3347 if (seat->finger_scrolling == NULL)
3348 {
3349 seat->finger_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3350 first_property_name: "name", "Wayland Finger Scrolling",
3351 "source", GDK_SOURCE_TOUCHPAD,
3352 "has-cursor", TRUE,
3353 "display", seat->display,
3354 "seat", seat,
3355 NULL);
3356 gdk_seat_device_added (GDK_SEAT (seat), device: seat->finger_scrolling);
3357 }
3358 return seat->finger_scrolling;
3359
3360 case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
3361 if (seat->continuous_scrolling == NULL)
3362 {
3363 seat->continuous_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
3364 first_property_name: "name", "Wayland Continuous Scrolling",
3365 "source", GDK_SOURCE_TRACKPOINT,
3366 "has-cursor", TRUE,
3367 "display", seat->display,
3368 "seat", seat,
3369 NULL);
3370 gdk_seat_device_added (GDK_SEAT (seat), device: seat->continuous_scrolling);
3371 }
3372 return seat->continuous_scrolling;
3373
3374 case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
3375 default:
3376 return seat->pointer;
3377 }
3378}
3379
3380static void
3381seat_handle_name (void *data,
3382 struct wl_seat *seat,
3383 const char *name)
3384{
3385 /* We don't care about the name. */
3386 GDK_SEAT_NOTE (GDK_WAYLAND_SEAT (data), MISC,
3387 g_message ("seat %p name %s", seat, name));
3388}
3389
3390static const struct wl_seat_listener seat_listener = {
3391 seat_handle_capabilities,
3392 seat_handle_name,
3393};
3394
3395static void
3396tablet_tool_handle_type (void *data,
3397 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3398 uint32_t tool_type)
3399{
3400 GdkWaylandTabletToolData *tool = data;
3401
3402 switch (tool_type)
3403 {
3404 case ZWP_TABLET_TOOL_V2_TYPE_PEN:
3405 tool->type = GDK_DEVICE_TOOL_TYPE_PEN;
3406 break;
3407 case ZWP_TABLET_TOOL_V2_TYPE_BRUSH:
3408 tool->type = GDK_DEVICE_TOOL_TYPE_BRUSH;
3409 break;
3410 case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH:
3411 tool->type = GDK_DEVICE_TOOL_TYPE_AIRBRUSH;
3412 break;
3413 case ZWP_TABLET_TOOL_V2_TYPE_PENCIL:
3414 tool->type = GDK_DEVICE_TOOL_TYPE_PENCIL;
3415 break;
3416 case ZWP_TABLET_TOOL_V2_TYPE_ERASER:
3417 tool->type = GDK_DEVICE_TOOL_TYPE_ERASER;
3418 break;
3419 case ZWP_TABLET_TOOL_V2_TYPE_MOUSE:
3420 tool->type = GDK_DEVICE_TOOL_TYPE_MOUSE;
3421 break;
3422 case ZWP_TABLET_TOOL_V2_TYPE_LENS:
3423 tool->type = GDK_DEVICE_TOOL_TYPE_LENS;
3424 break;
3425 default:
3426 tool->type = GDK_DEVICE_TOOL_TYPE_UNKNOWN;
3427 break;
3428 };
3429}
3430
3431static void
3432tablet_tool_handle_hardware_serial (void *data,
3433 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3434 uint32_t serial_hi,
3435 uint32_t serial_lo)
3436{
3437 GdkWaylandTabletToolData *tool = data;
3438
3439 tool->hardware_serial = ((guint64) serial_hi) << 32 | serial_lo;
3440}
3441
3442static void
3443tablet_tool_handle_hardware_id_wacom (void *data,
3444 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3445 uint32_t id_hi,
3446 uint32_t id_lo)
3447{
3448 GdkWaylandTabletToolData *tool = data;
3449
3450 tool->hardware_id_wacom = ((guint64) id_hi) << 32 | id_lo;
3451}
3452
3453static void
3454tablet_tool_handle_capability (void *data,
3455 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3456 uint32_t capability)
3457{
3458 GdkWaylandTabletToolData *tool = data;
3459
3460 switch (capability)
3461 {
3462 case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT:
3463 tool->axes |= GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT;
3464 break;
3465 case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE:
3466 tool->axes |= GDK_AXIS_FLAG_PRESSURE;
3467 break;
3468 case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE:
3469 tool->axes |= GDK_AXIS_FLAG_DISTANCE;
3470 break;
3471 case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION:
3472 tool->axes |= GDK_AXIS_FLAG_ROTATION;
3473 break;
3474 case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER:
3475 tool->axes |= GDK_AXIS_FLAG_SLIDER;
3476 break;
3477 default:
3478 break;
3479 }
3480}
3481
3482static void
3483tablet_tool_handle_done (void *data,
3484 struct zwp_tablet_tool_v2 *wp_tablet_tool)
3485{
3486 GdkWaylandTabletToolData *tool = data;
3487
3488 tool->tool = gdk_device_tool_new (serial: tool->hardware_serial,
3489 hw_id: tool->hardware_id_wacom,
3490 type: tool->type, tool_axes: tool->axes);
3491 gdk_seat_tool_added (seat: tool->seat, tool: tool->tool);
3492}
3493
3494static void
3495tablet_tool_handle_removed (void *data,
3496 struct zwp_tablet_tool_v2 *wp_tablet_tool)
3497{
3498 GdkWaylandTabletToolData *tool = data;
3499
3500 _gdk_wayland_seat_remove_tool (GDK_WAYLAND_SEAT (tool->seat), tool);
3501}
3502
3503static void
3504gdk_wayland_tablet_flush_frame_event (GdkWaylandTabletData *tablet,
3505 guint32 time)
3506{
3507 GdkEvent *event;
3508 GdkEventType type;
3509
3510 event = tablet->pointer_info.frame.event;
3511 tablet->pointer_info.frame.event = NULL;
3512
3513 if (!event)
3514 return;
3515
3516 gdk_event_ref (event);
3517
3518 type = gdk_event_get_event_type (event);
3519
3520 if (type == GDK_PROXIMITY_OUT)
3521 emulate_crossing (surface: gdk_event_get_surface (event), NULL,
3522 device: tablet->logical_device, type: GDK_LEAVE_NOTIFY,
3523 mode: GDK_CROSSING_NORMAL, time_: time);
3524
3525 _gdk_wayland_display_deliver_event (display: gdk_seat_get_display (seat: tablet->seat),
3526 event);
3527
3528 if (type == GDK_PROXIMITY_IN)
3529 emulate_crossing (surface: gdk_event_get_surface (event), NULL,
3530 device: tablet->logical_device, type: GDK_ENTER_NOTIFY,
3531 mode: GDK_CROSSING_NORMAL, time_: time);
3532
3533 gdk_event_unref (event);
3534}
3535
3536static void
3537gdk_wayland_tablet_set_frame_event (GdkWaylandTabletData *tablet,
3538 GdkEvent *event)
3539{
3540 if (tablet->pointer_info.frame.event &&
3541 gdk_event_get_event_type (event: tablet->pointer_info.frame.event) != gdk_event_get_event_type (event))
3542 gdk_wayland_tablet_flush_frame_event (tablet, GDK_CURRENT_TIME);
3543
3544 tablet->pointer_info.frame.event = event;
3545}
3546
3547static void
3548gdk_wayland_device_tablet_clone_tool_axes (GdkWaylandTabletData *tablet,
3549 GdkDeviceTool *tool)
3550{
3551 int axis_pos;
3552
3553 g_object_freeze_notify (G_OBJECT (tablet->stylus_device));
3554 _gdk_device_reset_axes (device: tablet->stylus_device);
3555
3556 _gdk_device_add_axis (device: tablet->stylus_device, use: GDK_AXIS_X, min_value: 0, max_value: 0, resolution: 0);
3557 _gdk_device_add_axis (device: tablet->stylus_device, use: GDK_AXIS_Y, min_value: 0, max_value: 0, resolution: 0);
3558
3559 if (tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT))
3560 {
3561 axis_pos = _gdk_device_add_axis (device: tablet->stylus_device,
3562 use: GDK_AXIS_XTILT, min_value: -90, max_value: 90, resolution: 0);
3563 tablet->axis_indices[GDK_AXIS_XTILT] = axis_pos;
3564
3565 axis_pos = _gdk_device_add_axis (device: tablet->stylus_device,
3566 use: GDK_AXIS_YTILT, min_value: -90, max_value: 90, resolution: 0);
3567 tablet->axis_indices[GDK_AXIS_YTILT] = axis_pos;
3568 }
3569 if (tool->tool_axes & GDK_AXIS_FLAG_DISTANCE)
3570 {
3571 axis_pos = _gdk_device_add_axis (device: tablet->stylus_device,
3572 use: GDK_AXIS_DISTANCE, min_value: 0, max_value: 65535, resolution: 0);
3573 tablet->axis_indices[GDK_AXIS_DISTANCE] = axis_pos;
3574 }
3575 if (tool->tool_axes & GDK_AXIS_FLAG_PRESSURE)
3576 {
3577 axis_pos = _gdk_device_add_axis (device: tablet->stylus_device,
3578 use: GDK_AXIS_PRESSURE, min_value: 0, max_value: 65535, resolution: 0);
3579 tablet->axis_indices[GDK_AXIS_PRESSURE] = axis_pos;
3580 }
3581
3582 if (tool->tool_axes & GDK_AXIS_FLAG_ROTATION)
3583 {
3584 axis_pos = _gdk_device_add_axis (device: tablet->stylus_device,
3585 use: GDK_AXIS_ROTATION, min_value: 0, max_value: 360, resolution: 0);
3586 tablet->axis_indices[GDK_AXIS_ROTATION] = axis_pos;
3587 }
3588
3589 if (tool->tool_axes & GDK_AXIS_FLAG_SLIDER)
3590 {
3591 axis_pos = _gdk_device_add_axis (device: tablet->stylus_device,
3592 use: GDK_AXIS_SLIDER, min_value: -65535, max_value: 65535, resolution: 0);
3593 tablet->axis_indices[GDK_AXIS_SLIDER] = axis_pos;
3594 }
3595
3596 g_object_thaw_notify (G_OBJECT (tablet->stylus_device));
3597}
3598
3599static void
3600gdk_wayland_mimic_device_axes (GdkDevice *logical,
3601 GdkDevice *physical)
3602{
3603 double axis_min, axis_max, axis_resolution;
3604 GdkAxisUse axis_use;
3605 int axis_count;
3606 int i;
3607
3608 g_object_freeze_notify (G_OBJECT (logical));
3609 _gdk_device_reset_axes (device: logical);
3610 axis_count = gdk_device_get_n_axes (device: physical);
3611
3612 for (i = 0; i < axis_count; i++)
3613 {
3614 _gdk_device_get_axis_info (device: physical, index: i, use: &axis_use, min_value: &axis_min,
3615 max_value: &axis_max, resolution: &axis_resolution);
3616 _gdk_device_add_axis (device: logical, use: axis_use, min_value: axis_min,
3617 max_value: axis_max, resolution: axis_resolution);
3618 }
3619
3620 g_object_thaw_notify (G_OBJECT (logical));
3621}
3622
3623static void
3624tablet_tool_handle_proximity_in (void *data,
3625 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3626 uint32_t serial,
3627 struct zwp_tablet_v2 *wp_tablet,
3628 struct wl_surface *wsurface)
3629{
3630 GdkWaylandTabletToolData *tool = data;
3631 GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet);
3632 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat);
3633 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
3634 GdkSurface *surface;
3635 GdkEvent *event;
3636
3637 if (!wsurface)
3638 return;
3639
3640 surface = wl_surface_get_user_data (wl_surface: wsurface);
3641
3642 if (!surface)
3643 return;
3644 if (!GDK_IS_SURFACE (surface))
3645 return;
3646
3647 tool->current_tablet = tablet;
3648 tablet->current_tool = tool;
3649
3650 _gdk_wayland_display_update_serial (display_wayland, serial);
3651 tablet->pointer_info.enter_serial = serial;
3652
3653 tablet->pointer_info.focus = g_object_ref (surface);
3654
3655 gdk_device_update_tool (device: tablet->stylus_device, tool: tool->tool);
3656 gdk_wayland_device_tablet_clone_tool_axes (tablet, tool: tool->tool);
3657 gdk_wayland_mimic_device_axes (logical: tablet->logical_device, physical: tablet->stylus_device);
3658
3659 event = gdk_proximity_event_new (type: GDK_PROXIMITY_IN,
3660 surface: tablet->pointer_info.focus,
3661 device: tablet->logical_device,
3662 tool: tool->tool,
3663 time: tablet->pointer_info.time);
3664 gdk_wayland_tablet_set_frame_event (tablet, event);
3665
3666 tablet->pointer_info.pointer_surface_outputs =
3667 g_slist_append (list: tablet->pointer_info.pointer_surface_outputs,
3668 data: gdk_wayland_surface_get_wl_output (surface));
3669 pointer_surface_update_scale (device: tablet->logical_device);
3670
3671 GDK_SEAT_NOTE (seat, EVENTS,
3672 g_message ("proximity in, seat %p surface %p tool %d",
3673 seat, tablet->pointer_info.focus,
3674 gdk_device_tool_get_tool_type (tool->tool)));
3675}
3676
3677static void
3678tablet_tool_handle_proximity_out (void *data,
3679 struct zwp_tablet_tool_v2 *wp_tablet_tool)
3680{
3681 GdkWaylandTabletToolData *tool = data;
3682 GdkWaylandTabletData *tablet = tool->current_tablet;
3683 GdkEvent *event;
3684
3685 if (!tablet)
3686 return;
3687
3688 GDK_SEAT_NOTE (tool->seat, EVENTS,
3689 g_message ("proximity out, seat %p, tool %d", tool->seat,
3690 gdk_device_tool_get_tool_type (tool->tool)));
3691
3692 event = gdk_proximity_event_new (type: GDK_PROXIMITY_OUT,
3693 surface: tablet->pointer_info.focus,
3694 device: tablet->logical_device,
3695 tool: tool->tool,
3696 time: tablet->pointer_info.time);
3697 gdk_wayland_tablet_set_frame_event (tablet, event);
3698
3699 gdk_wayland_pointer_stop_cursor_animation (pointer: &tablet->pointer_info);
3700
3701 tablet->pointer_info.pointer_surface_outputs =
3702 g_slist_remove (list: tablet->pointer_info.pointer_surface_outputs,
3703 data: gdk_wayland_surface_get_wl_output (surface: tablet->pointer_info.focus));
3704 pointer_surface_update_scale (device: tablet->logical_device);
3705
3706 g_object_unref (object: tablet->pointer_info.focus);
3707 tablet->pointer_info.focus = NULL;
3708
3709 tablet->pointer_info.button_modifiers &=
3710 ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
3711 GDK_BUTTON4_MASK | GDK_BUTTON5_MASK);
3712
3713 gdk_device_update_tool (device: tablet->stylus_device, NULL);
3714 g_clear_object (&tablet->pointer_info.cursor);
3715}
3716
3717static double *
3718tablet_copy_axes (GdkWaylandTabletData *tablet)
3719{
3720 return g_memdup2 (mem: tablet->axes, byte_size: sizeof (double) * GDK_AXIS_LAST);
3721}
3722
3723static void
3724tablet_create_button_event_frame (GdkWaylandTabletData *tablet,
3725 GdkEventType evtype,
3726 guint button)
3727{
3728 GdkEvent *event;
3729
3730 event = gdk_button_event_new (type: evtype,
3731 surface: tablet->pointer_info.focus,
3732 device: tablet->logical_device,
3733 tool: tablet->current_tool->tool,
3734 time: tablet->pointer_info.time,
3735 state: device_get_modifiers (device: tablet->logical_device),
3736 button,
3737 x: tablet->pointer_info.surface_x,
3738 y: tablet->pointer_info.surface_y,
3739 axes: tablet_copy_axes (tablet));
3740 gdk_wayland_tablet_set_frame_event (tablet, event);
3741}
3742
3743static void
3744tablet_tool_handle_down (void *data,
3745 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3746 uint32_t serial)
3747{
3748 GdkWaylandTabletToolData *tool = data;
3749 GdkWaylandTabletData *tablet = tool->current_tablet;
3750 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tool->seat);
3751 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
3752
3753 if (!tablet || !tablet->pointer_info.focus)
3754 return;
3755
3756 _gdk_wayland_display_update_serial (display_wayland, serial);
3757 tablet->pointer_info.press_serial = serial;
3758
3759 tablet_create_button_event_frame (tablet, evtype: GDK_BUTTON_PRESS, GDK_BUTTON_PRIMARY);
3760 tablet->pointer_info.button_modifiers |= GDK_BUTTON1_MASK;
3761}
3762
3763static void
3764tablet_tool_handle_up (void *data,
3765 struct zwp_tablet_tool_v2 *wp_tablet_tool)
3766{
3767 GdkWaylandTabletToolData *tool = data;
3768 GdkWaylandTabletData *tablet = tool->current_tablet;
3769
3770 if (!tablet || !tablet->pointer_info.focus)
3771 return;
3772
3773 tablet_create_button_event_frame (tablet, evtype: GDK_BUTTON_RELEASE, GDK_BUTTON_PRIMARY);
3774 tablet->pointer_info.button_modifiers &= ~GDK_BUTTON1_MASK;
3775}
3776
3777static void
3778tablet_tool_handle_motion (void *data,
3779 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3780 wl_fixed_t sx,
3781 wl_fixed_t sy)
3782{
3783 GdkWaylandTabletToolData *tool = data;
3784 GdkWaylandTabletData *tablet = tool->current_tablet;
3785 GdkEvent *event;
3786
3787 if (!tablet)
3788 return;
3789
3790 tablet->pointer_info.surface_x = wl_fixed_to_double (f: sx);
3791 tablet->pointer_info.surface_y = wl_fixed_to_double (f: sy);
3792
3793 GDK_SEAT_NOTE (tool->seat, EVENTS,
3794 g_message ("tablet motion %f %f",
3795 tablet->pointer_info.surface_x,
3796 tablet->pointer_info.surface_y));
3797
3798 event = gdk_motion_event_new (surface: tablet->pointer_info.focus,
3799 device: tablet->logical_device,
3800 tool: tool->tool,
3801 time: tablet->pointer_info.time,
3802 state: device_get_modifiers (device: tablet->logical_device),
3803 x: tablet->pointer_info.surface_x,
3804 y: tablet->pointer_info.surface_y,
3805 axes: tablet_copy_axes (tablet));
3806
3807 gdk_wayland_tablet_set_frame_event (tablet, event);
3808}
3809
3810static void
3811tablet_tool_handle_pressure (void *data,
3812 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3813 uint32_t pressure)
3814{
3815 GdkWaylandTabletToolData *tool = data;
3816 GdkWaylandTabletData *tablet = tool->current_tablet;
3817 int axis_index;
3818
3819 if (!tablet)
3820 return;
3821
3822 axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE];
3823
3824 _gdk_device_translate_axis (device: tablet->stylus_device, index: axis_index,
3825 value: pressure, axis_value: &tablet->axes[GDK_AXIS_PRESSURE]);
3826
3827 GDK_SEAT_NOTE (tool->seat, EVENTS,
3828 g_message ("tablet tool %d pressure %d",
3829 gdk_device_tool_get_tool_type (tool->tool), pressure));
3830}
3831
3832static void
3833tablet_tool_handle_distance (void *data,
3834 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3835 uint32_t distance)
3836{
3837 GdkWaylandTabletToolData *tool = data;
3838 GdkWaylandTabletData *tablet = tool->current_tablet;
3839 int axis_index;
3840
3841 if (!tablet)
3842 return;
3843
3844 axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE];
3845
3846 _gdk_device_translate_axis (device: tablet->stylus_device, index: axis_index,
3847 value: distance, axis_value: &tablet->axes[GDK_AXIS_DISTANCE]);
3848
3849 GDK_SEAT_NOTE (tool->seat, EVENTS,
3850 g_message ("tablet tool %d distance %d",
3851 gdk_device_tool_get_tool_type (tool->tool), distance));
3852}
3853
3854static void
3855tablet_tool_handle_tilt (void *data,
3856 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3857 wl_fixed_t xtilt,
3858 wl_fixed_t ytilt)
3859{
3860 GdkWaylandTabletToolData *tool = data;
3861 GdkWaylandTabletData *tablet = tool->current_tablet;
3862 int xtilt_axis_index;
3863 int ytilt_axis_index;
3864
3865 if (!tablet)
3866 return;
3867
3868 xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT];
3869 ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT];
3870
3871 _gdk_device_translate_axis (device: tablet->stylus_device, index: xtilt_axis_index,
3872 value: wl_fixed_to_double (f: xtilt),
3873 axis_value: &tablet->axes[GDK_AXIS_XTILT]);
3874 _gdk_device_translate_axis (device: tablet->stylus_device, index: ytilt_axis_index,
3875 value: wl_fixed_to_double (f: ytilt),
3876 axis_value: &tablet->axes[GDK_AXIS_YTILT]);
3877
3878 GDK_SEAT_NOTE (tool->seat, EVENTS,
3879 g_message ("tablet tool %d tilt %f/%f",
3880 gdk_device_tool_get_tool_type (tool->tool),
3881 wl_fixed_to_double (xtilt), wl_fixed_to_double (ytilt)));
3882}
3883
3884static void
3885tablet_tool_handle_button (void *data,
3886 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3887 uint32_t serial,
3888 uint32_t button,
3889 uint32_t state)
3890{
3891 GdkWaylandTabletToolData *tool = data;
3892 GdkWaylandTabletData *tablet = tool->current_tablet;
3893 GdkEventType evtype;
3894 guint n_button;
3895
3896 if (!tablet || !tablet->pointer_info.focus)
3897 return;
3898
3899 tablet->pointer_info.press_serial = serial;
3900
3901 if (button == BTN_STYLUS)
3902 n_button = GDK_BUTTON_SECONDARY;
3903 else if (button == BTN_STYLUS2)
3904 n_button = GDK_BUTTON_MIDDLE;
3905 else if (button == BTN_STYLUS3)
3906 n_button = 8; /* Back */
3907 else
3908 return;
3909
3910 if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED)
3911 evtype = GDK_BUTTON_PRESS;
3912 else if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED)
3913 evtype = GDK_BUTTON_RELEASE;
3914 else
3915 return;
3916
3917 tablet_create_button_event_frame (tablet, evtype, button: n_button);
3918}
3919
3920static void
3921tablet_tool_handle_rotation (void *data,
3922 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3923 wl_fixed_t degrees)
3924{
3925 GdkWaylandTabletToolData *tool = data;
3926 GdkWaylandTabletData *tablet = tool->current_tablet;
3927 int axis_index;
3928
3929 if (!tablet)
3930 return;
3931
3932 axis_index = tablet->axis_indices[GDK_AXIS_ROTATION];
3933
3934 _gdk_device_translate_axis (device: tablet->stylus_device, index: axis_index,
3935 value: wl_fixed_to_double (f: degrees),
3936 axis_value: &tablet->axes[GDK_AXIS_ROTATION]);
3937
3938 GDK_SEAT_NOTE (tool->seat, EVENTS,
3939 g_message ("tablet tool %d rotation %f",
3940 gdk_device_tool_get_tool_type (tool->tool),
3941 wl_fixed_to_double (degrees)));
3942}
3943
3944static void
3945tablet_tool_handle_slider (void *data,
3946 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3947 int32_t position)
3948{
3949 GdkWaylandTabletToolData *tool = data;
3950 GdkWaylandTabletData *tablet = tool->current_tablet;
3951 int axis_index;
3952
3953 if (!tablet)
3954 return;
3955
3956 axis_index = tablet->axis_indices[GDK_AXIS_SLIDER];
3957
3958 _gdk_device_translate_axis (device: tablet->stylus_device, index: axis_index,
3959 value: position, axis_value: &tablet->axes[GDK_AXIS_SLIDER]);
3960
3961 GDK_SEAT_NOTE (tool->seat, EVENTS,
3962 g_message ("tablet tool %d slider %d",
3963 gdk_device_tool_get_tool_type (tool->tool), position));
3964}
3965
3966static void
3967tablet_tool_handle_wheel (void *data,
3968 struct zwp_tablet_tool_v2 *wp_tablet_tool,
3969 int32_t degrees,
3970 int32_t clicks)
3971{
3972 GdkWaylandTabletToolData *tool = data;
3973 GdkWaylandTabletData *tablet = tool->current_tablet;
3974 GdkWaylandSeat *seat;
3975 GdkEvent *event;
3976
3977 if (!tablet)
3978 return;
3979
3980 seat = GDK_WAYLAND_SEAT (tablet->seat);
3981
3982 GDK_SEAT_NOTE (seat, EVENTS,
3983 g_message ("tablet tool %d wheel %d/%d",
3984 gdk_device_tool_get_tool_type (tool->tool), degrees, clicks));
3985
3986 if (clicks == 0)
3987 return;
3988
3989 /* Send smooth event */
3990 event = gdk_scroll_event_new (surface: tablet->pointer_info.focus,
3991 device: tablet->logical_device,
3992 tool: tablet->current_tool->tool,
3993 time: tablet->pointer_info.time,
3994 state: device_get_modifiers (device: tablet->logical_device),
3995 delta_x: 0, delta_y: clicks,
3996 FALSE);
3997
3998 _gdk_wayland_display_deliver_event (display: seat->display, event);
3999
4000 /* Send discrete event */
4001 event = gdk_scroll_event_new_discrete (surface: tablet->pointer_info.focus,
4002 device: tablet->stylus_device,
4003 tool: tablet->current_tool->tool,
4004 time: tablet->pointer_info.time,
4005 state: device_get_modifiers (device: tablet->logical_device),
4006 direction: clicks > 0 ? GDK_SCROLL_DOWN : GDK_SCROLL_UP,
4007 TRUE);
4008
4009 _gdk_wayland_display_deliver_event (display: seat->display, event);
4010}
4011
4012static void
4013tablet_tool_handle_frame (void *data,
4014 struct zwp_tablet_tool_v2 *wl_tablet_tool,
4015 uint32_t time)
4016{
4017 GdkWaylandTabletToolData *tool = data;
4018 GdkWaylandTabletData *tablet = tool->current_tablet;
4019 GdkEvent *frame_event;
4020
4021 if (!tablet)
4022 return;
4023
4024 GDK_SEAT_NOTE (tablet->seat, EVENTS,
4025 g_message ("tablet frame, time %d", time));
4026
4027 frame_event = tablet->pointer_info.frame.event;
4028
4029 if (frame_event && gdk_event_get_event_type (event: frame_event) == GDK_PROXIMITY_OUT)
4030 {
4031 tool->current_tablet = NULL;
4032 tablet->current_tool = NULL;
4033 }
4034
4035 tablet->pointer_info.time = time;
4036 gdk_wayland_tablet_flush_frame_event (tablet, time);
4037}
4038
4039static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
4040 tablet_tool_handle_type,
4041 tablet_tool_handle_hardware_serial,
4042 tablet_tool_handle_hardware_id_wacom,
4043 tablet_tool_handle_capability,
4044 tablet_tool_handle_done,
4045 tablet_tool_handle_removed,
4046 tablet_tool_handle_proximity_in,
4047 tablet_tool_handle_proximity_out,
4048 tablet_tool_handle_down,
4049 tablet_tool_handle_up,
4050 tablet_tool_handle_motion,
4051 tablet_tool_handle_pressure,
4052 tablet_tool_handle_distance,
4053 tablet_tool_handle_tilt,
4054 tablet_tool_handle_rotation,
4055 tablet_tool_handle_slider,
4056 tablet_tool_handle_wheel,
4057 tablet_tool_handle_button,
4058 tablet_tool_handle_frame,
4059};
4060
4061static void
4062tablet_pad_ring_handle_source (void *data,
4063 struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring,
4064 uint32_t source)
4065{
4066 GdkWaylandTabletPadGroupData *group = data;
4067
4068 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4069 g_message ("tablet pad ring handle source, ring = %p source = %d",
4070 wp_tablet_pad_ring, source));
4071
4072 group->axis_tmp_info.source = source;
4073}
4074
4075static void
4076tablet_pad_ring_handle_angle (void *data,
4077 struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring,
4078 wl_fixed_t angle)
4079{
4080 GdkWaylandTabletPadGroupData *group = data;
4081
4082 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4083 g_message ("tablet pad ring handle angle, ring = %p angle = %f",
4084 wp_tablet_pad_ring, wl_fixed_to_double (angle)));
4085
4086 group->axis_tmp_info.value = wl_fixed_to_double (f: angle);
4087}
4088
4089static void
4090tablet_pad_ring_handle_stop (void *data,
4091 struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring)
4092{
4093 GdkWaylandTabletPadGroupData *group = data;
4094
4095 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4096 g_message ("tablet pad ring handle stop, ring = %p", wp_tablet_pad_ring));
4097
4098 group->axis_tmp_info.is_stop = TRUE;
4099}
4100
4101static void
4102tablet_pad_ring_handle_frame (void *data,
4103 struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring,
4104 uint32_t time)
4105{
4106 GdkWaylandTabletPadGroupData *group = data;
4107 GdkWaylandTabletPadData *pad = group->pad;
4108 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat);
4109 GdkEvent *event;
4110
4111 GDK_SEAT_NOTE (seat, EVENTS,
4112 g_message ("tablet pad ring handle frame, ring = %p", wp_tablet_pad_ring));
4113
4114 event = gdk_pad_event_new_ring (surface: seat->keyboard_focus,
4115 device: pad->device,
4116 time,
4117 group: g_list_index (list: pad->mode_groups, data: group),
4118 index: g_list_index (list: pad->rings, data: wp_tablet_pad_ring),
4119 mode: group->current_mode,
4120 value: group->axis_tmp_info.value);
4121
4122 _gdk_wayland_display_deliver_event (display: gdk_seat_get_display (seat: pad->seat),
4123 event);
4124}
4125
4126static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = {
4127 tablet_pad_ring_handle_source,
4128 tablet_pad_ring_handle_angle,
4129 tablet_pad_ring_handle_stop,
4130 tablet_pad_ring_handle_frame,
4131};
4132
4133static void
4134tablet_pad_strip_handle_source (void *data,
4135 struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip,
4136 uint32_t source)
4137{
4138 GdkWaylandTabletPadGroupData *group = data;
4139
4140 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4141 g_message ("tablet pad strip handle source, strip = %p source = %d",
4142 wp_tablet_pad_strip, source));
4143
4144 group->axis_tmp_info.source = source;
4145}
4146
4147static void
4148tablet_pad_strip_handle_position (void *data,
4149 struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip,
4150 uint32_t position)
4151{
4152 GdkWaylandTabletPadGroupData *group = data;
4153
4154 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4155 g_message ("tablet pad strip handle position, strip = %p position = %d",
4156 wp_tablet_pad_strip, position));
4157
4158 group->axis_tmp_info.value = (double) position / 65535;
4159}
4160
4161static void
4162tablet_pad_strip_handle_stop (void *data,
4163 struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip)
4164{
4165 GdkWaylandTabletPadGroupData *group = data;
4166
4167 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4168 g_message ("tablet pad strip handle stop, strip = %p",
4169 wp_tablet_pad_strip));
4170
4171 group->axis_tmp_info.is_stop = TRUE;
4172}
4173
4174static void
4175tablet_pad_strip_handle_frame (void *data,
4176 struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip,
4177 uint32_t time)
4178{
4179 GdkWaylandTabletPadGroupData *group = data;
4180 GdkWaylandTabletPadData *pad = group->pad;
4181 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat);
4182 GdkEvent *event;
4183
4184 GDK_SEAT_NOTE (seat, EVENTS,
4185 g_message ("tablet pad strip handle frame, strip = %p",
4186 wp_tablet_pad_strip));
4187
4188 event = gdk_pad_event_new_strip (surface: seat->keyboard_focus,
4189 device: pad->device,
4190 time,
4191 group: g_list_index (list: pad->mode_groups, data: group),
4192 index: g_list_index (list: pad->strips, data: wp_tablet_pad_strip),
4193 mode: group->current_mode,
4194 value: group->axis_tmp_info.value);
4195
4196 _gdk_wayland_display_deliver_event (display: gdk_seat_get_display (seat: pad->seat),
4197 event);
4198}
4199
4200static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener = {
4201 tablet_pad_strip_handle_source,
4202 tablet_pad_strip_handle_position,
4203 tablet_pad_strip_handle_stop,
4204 tablet_pad_strip_handle_frame,
4205};
4206
4207static void
4208tablet_pad_group_handle_buttons (void *data,
4209 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group,
4210 struct wl_array *buttons)
4211{
4212 GdkWaylandTabletPadGroupData *group = data;
4213 uint32_t *p;
4214
4215 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4216 g_message ("tablet pad group handle buttons, pad group = %p, n_buttons = %" G_GSIZE_FORMAT,
4217 wp_tablet_pad_group, buttons->size));
4218
4219 wl_array_for_each (p, buttons)
4220 {
4221 group->buttons = g_list_prepend (list: group->buttons, GUINT_TO_POINTER (*p));
4222 }
4223
4224 group->buttons = g_list_reverse (list: group->buttons);
4225}
4226
4227static void
4228tablet_pad_group_handle_ring (void *data,
4229 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group,
4230 struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring)
4231{
4232 GdkWaylandTabletPadGroupData *group = data;
4233
4234 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4235 g_message ("tablet pad group handle ring, pad group = %p, ring = %p",
4236 wp_tablet_pad_group, wp_tablet_pad_ring));
4237
4238 zwp_tablet_pad_ring_v2_add_listener (wp_tablet_pad_ring,
4239 &tablet_pad_ring_listener, group);
4240 zwp_tablet_pad_ring_v2_set_user_data (wp_tablet_pad_ring, group);
4241
4242 group->rings = g_list_append (list: group->rings, data: wp_tablet_pad_ring);
4243 group->pad->rings = g_list_append (list: group->pad->rings, data: wp_tablet_pad_ring);
4244}
4245
4246static void
4247tablet_pad_group_handle_strip (void *data,
4248 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group,
4249 struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip)
4250{
4251 GdkWaylandTabletPadGroupData *group = data;
4252
4253 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4254 g_message ("tablet pad group handle strip, pad group = %p, strip = %p",
4255 wp_tablet_pad_group, wp_tablet_pad_strip));
4256
4257 zwp_tablet_pad_strip_v2_add_listener (wp_tablet_pad_strip,
4258 &tablet_pad_strip_listener, group);
4259 zwp_tablet_pad_strip_v2_set_user_data (wp_tablet_pad_strip, group);
4260
4261 group->strips = g_list_append (list: group->strips, data: wp_tablet_pad_strip);
4262 group->pad->strips = g_list_append (list: group->pad->strips, data: wp_tablet_pad_strip);
4263}
4264
4265static void
4266tablet_pad_group_handle_modes (void *data,
4267 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group,
4268 uint32_t modes)
4269{
4270 GdkWaylandTabletPadGroupData *group = data;
4271
4272 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4273 g_message ("tablet pad group handle modes, pad group = %p, n_modes = %d",
4274 wp_tablet_pad_group, modes));
4275
4276 group->n_modes = modes;
4277}
4278
4279static void
4280tablet_pad_group_handle_done (void *data,
4281 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group)
4282{
4283#ifdef G_ENABLE_DEBUG
4284 GdkWaylandTabletPadGroupData *group = data;
4285#endif
4286
4287 GDK_SEAT_NOTE (group->pad->seat, EVENTS,
4288 g_message ("tablet pad group handle done, pad group = %p",
4289 wp_tablet_pad_group));
4290}
4291
4292static void
4293tablet_pad_group_handle_mode (void *data,
4294 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group,
4295 uint32_t time,
4296 uint32_t serial,
4297 uint32_t mode)
4298{
4299 GdkWaylandTabletPadGroupData *group = data;
4300 GdkWaylandTabletPadData *pad = group->pad;
4301 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat);
4302 GdkEvent *event;
4303 guint n_group;
4304
4305 GDK_SEAT_NOTE (seat, EVENTS,
4306 g_message ("tablet pad group handle mode, pad group = %p, mode = %d",
4307 wp_tablet_pad_group, mode));
4308
4309 group->mode_switch_serial = serial;
4310 group->current_mode = mode;
4311 n_group = g_list_index (list: pad->mode_groups, data: group);
4312
4313 event = gdk_pad_event_new_group_mode (surface: seat->keyboard_focus,
4314 device: pad->device,
4315 time,
4316 group: n_group,
4317 mode);
4318
4319 _gdk_wayland_display_deliver_event (display: gdk_seat_get_display (seat: pad->seat),
4320 event);
4321}
4322
4323static const struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener = {
4324 tablet_pad_group_handle_buttons,
4325 tablet_pad_group_handle_ring,
4326 tablet_pad_group_handle_strip,
4327 tablet_pad_group_handle_modes,
4328 tablet_pad_group_handle_done,
4329 tablet_pad_group_handle_mode,
4330};
4331
4332static void
4333tablet_pad_handle_group (void *data,
4334 struct zwp_tablet_pad_v2 *wp_tablet_pad,
4335 struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group)
4336{
4337 GdkWaylandTabletPadData *pad = data;
4338 GdkWaylandTabletPadGroupData *group;
4339
4340 GDK_SEAT_NOTE (pad->seat, EVENTS,
4341 g_message ("tablet pad handle group, pad group = %p, group = %p",
4342 wp_tablet_pad_group, wp_tablet_pad_group));
4343
4344 group = g_new0 (GdkWaylandTabletPadGroupData, 1);
4345 group->wp_tablet_pad_group = wp_tablet_pad_group;
4346 group->pad = pad;
4347
4348 zwp_tablet_pad_group_v2_add_listener (wp_tablet_pad_group,
4349 &tablet_pad_group_listener, group);
4350 zwp_tablet_pad_group_v2_set_user_data (wp_tablet_pad_group, group);
4351 pad->mode_groups = g_list_append (list: pad->mode_groups, data: group);
4352}
4353
4354static void
4355tablet_pad_handle_path (void *data,
4356 struct zwp_tablet_pad_v2 *wp_tablet_pad,
4357 const char *path)
4358{
4359 GdkWaylandTabletPadData *pad = data;
4360
4361 GDK_SEAT_NOTE (pad->seat, EVENTS,
4362 g_message ("tablet pad handle path, pad = %p, path = %s",
4363 wp_tablet_pad, path));
4364
4365 pad->path = g_strdup (str: path);
4366}
4367
4368static void
4369tablet_pad_handle_buttons (void *data,
4370 struct zwp_tablet_pad_v2 *wp_tablet_pad,
4371 uint32_t buttons)
4372{
4373 GdkWaylandTabletPadData *pad = data;
4374
4375 GDK_SEAT_NOTE (pad->seat, EVENTS,
4376 g_message ("tablet pad handle buttons, pad = %p, n_buttons = %d",
4377 wp_tablet_pad, buttons));
4378
4379 pad->n_buttons = buttons;
4380}
4381
4382static void
4383tablet_pad_handle_done (void *data,
4384 struct zwp_tablet_pad_v2 *wp_tablet_pad)
4385{
4386 GdkWaylandTabletPadData *pad = data;
4387
4388 GDK_SEAT_NOTE (pad->seat, EVENTS,
4389 g_message ("tablet pad handle done, pad = %p", wp_tablet_pad));
4390
4391 pad->device =
4392 g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD,
4393 first_property_name: "name", "Pad device",
4394 "source", GDK_SOURCE_TABLET_PAD,
4395 "display", gdk_seat_get_display (seat: pad->seat),
4396 "seat", pad->seat,
4397 NULL);
4398
4399 _gdk_device_set_associated_device (device: pad->device, GDK_WAYLAND_SEAT (pad->seat)->logical_keyboard);
4400 gdk_seat_device_added (GDK_SEAT (pad->seat), device: pad->device);
4401}
4402
4403static void
4404tablet_pad_handle_button (void *data,
4405 struct zwp_tablet_pad_v2 *wp_tablet_pad,
4406 uint32_t time,
4407 uint32_t button,
4408 uint32_t state)
4409{
4410 GdkWaylandTabletPadData *pad = data;
4411 GdkWaylandTabletPadGroupData *group;
4412 GdkEvent *event;
4413 int n_group;
4414
4415 GDK_SEAT_NOTE (pad->seat, EVENTS,
4416 g_message ("tablet pad handle button, pad = %p, button = %d, state = %d",
4417 wp_tablet_pad, button, state));
4418
4419 group = tablet_pad_lookup_button_group (pad, button);
4420
4421#ifdef G_DISABLE_ASSERT
4422 if (group == NULL)
4423 return;
4424#else
4425 g_assert (group != NULL);
4426#endif
4427
4428 n_group = g_list_index (list: pad->mode_groups, data: group);
4429
4430 event = gdk_pad_event_new_button (type: state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED
4431 ? GDK_PAD_BUTTON_PRESS
4432 : GDK_PAD_BUTTON_RELEASE,
4433 GDK_WAYLAND_SEAT (pad->seat)->keyboard_focus,
4434 device: pad->device,
4435 time,
4436 group: n_group,
4437 button,
4438 mode: group->current_mode);
4439
4440 _gdk_wayland_display_deliver_event (display: gdk_seat_get_display (seat: pad->seat), event);
4441}
4442
4443static void
4444tablet_pad_handle_enter (void *data,
4445 struct zwp_tablet_pad_v2 *wp_tablet_pad,
4446 uint32_t serial,
4447 struct zwp_tablet_v2 *wp_tablet,
4448 struct wl_surface *surface)
4449{
4450 GdkWaylandTabletPadData *pad = data;
4451 GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet);
4452
4453 GDK_SEAT_NOTE (pad->seat, EVENTS,
4454 g_message ("tablet pad handle enter, pad = %p, tablet = %p surface = %p",
4455 wp_tablet_pad, wp_tablet, surface));
4456
4457 /* Relate pad and tablet */
4458 tablet->pads = g_list_prepend (list: tablet->pads, data: pad);
4459 pad->current_tablet = tablet;
4460}
4461
4462static void
4463tablet_pad_handle_leave (void *data,
4464 struct zwp_tablet_pad_v2 *wp_tablet_pad,
4465 uint32_t serial,
4466 struct wl_surface *surface)
4467{
4468 GdkWaylandTabletPadData *pad = data;
4469
4470 GDK_SEAT_NOTE (pad->seat, EVENTS,
4471 g_message ("tablet pad handle leave, pad = %p, surface = %p",
4472 wp_tablet_pad, surface));
4473
4474 if (pad->current_tablet)
4475 {
4476 pad->current_tablet->pads = g_list_remove (list: pad->current_tablet->pads, data: pad);
4477 pad->current_tablet = NULL;
4478 }
4479}
4480
4481static void
4482tablet_pad_handle_removed (void *data,
4483 struct zwp_tablet_pad_v2 *wp_tablet_pad)
4484{
4485 GdkWaylandTabletPadData *pad = data;
4486
4487 GDK_SEAT_NOTE (pad->seat, EVENTS,
4488 g_message ("tablet pad handle removed, pad = %p", wp_tablet_pad));
4489
4490 /* Remove from the current tablet */
4491 if (pad->current_tablet)
4492 {
4493 pad->current_tablet->pads = g_list_remove (list: pad->current_tablet->pads, data: pad);
4494 pad->current_tablet = NULL;
4495 }
4496
4497 _gdk_wayland_seat_remove_tablet_pad (GDK_WAYLAND_SEAT (pad->seat), pad);
4498}
4499
4500static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = {
4501 tablet_pad_handle_group,
4502 tablet_pad_handle_path,
4503 tablet_pad_handle_buttons,
4504 tablet_pad_handle_done,
4505 tablet_pad_handle_button,
4506 tablet_pad_handle_enter,
4507 tablet_pad_handle_leave,
4508 tablet_pad_handle_removed,
4509};
4510
4511static void
4512tablet_seat_handle_tablet_added (void *data,
4513 struct zwp_tablet_seat_v2 *wp_tablet_seat,
4514 struct zwp_tablet_v2 *wp_tablet)
4515{
4516 GdkWaylandSeat *seat = data;
4517 GdkWaylandTabletData *tablet;
4518
4519 tablet = g_new0 (GdkWaylandTabletData, 1);
4520 tablet->seat = GDK_SEAT (seat);
4521
4522 tablet->wp_tablet = wp_tablet;
4523
4524 seat->tablets = g_list_prepend (list: seat->tablets, data: tablet);
4525
4526 zwp_tablet_v2_add_listener (wp_tablet, &tablet_listener, tablet);
4527 zwp_tablet_v2_set_user_data (wp_tablet, tablet);
4528}
4529
4530static void
4531tablet_seat_handle_tool_added (void *data,
4532 struct zwp_tablet_seat_v2 *wp_tablet_seat,
4533 struct zwp_tablet_tool_v2 *wp_tablet_tool)
4534{
4535 GdkWaylandSeat *seat = data;
4536 GdkWaylandTabletToolData *tool;
4537
4538 tool = g_new0 (GdkWaylandTabletToolData, 1);
4539 tool->wp_tablet_tool = wp_tablet_tool;
4540 tool->seat = GDK_SEAT (seat);
4541
4542 zwp_tablet_tool_v2_add_listener (wp_tablet_tool, &tablet_tool_listener, tool);
4543 zwp_tablet_tool_v2_set_user_data (wp_tablet_tool, tool);
4544
4545 seat->tablet_tools = g_list_prepend (list: seat->tablet_tools, data: tool);
4546}
4547
4548static void
4549tablet_seat_handle_pad_added (void *data,
4550 struct zwp_tablet_seat_v2 *wp_tablet_seat,
4551 struct zwp_tablet_pad_v2 *wp_tablet_pad)
4552{
4553 GdkWaylandSeat *seat = data;
4554 GdkWaylandTabletPadData *pad;
4555
4556 pad = g_new0 (GdkWaylandTabletPadData, 1);
4557 pad->wp_tablet_pad = wp_tablet_pad;
4558 pad->seat = GDK_SEAT (seat);
4559
4560 zwp_tablet_pad_v2_add_listener (wp_tablet_pad, &tablet_pad_listener, pad);
4561 zwp_tablet_pad_v2_set_user_data (wp_tablet_pad, pad);
4562
4563 seat->tablet_pads = g_list_prepend (list: seat->tablet_pads, data: pad);
4564}
4565
4566static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
4567 tablet_seat_handle_tablet_added,
4568 tablet_seat_handle_tool_added,
4569 tablet_seat_handle_pad_added,
4570};
4571
4572static void
4573init_devices (GdkWaylandSeat *seat)
4574{
4575 /* pointer */
4576 seat->logical_pointer = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
4577 first_property_name: "name", "Core Pointer",
4578 "source", GDK_SOURCE_MOUSE,
4579 "has-cursor", TRUE,
4580 "display", seat->display,
4581 "seat", seat,
4582 NULL);
4583
4584 GDK_WAYLAND_DEVICE (seat->logical_pointer)->pointer = &seat->pointer_info;
4585
4586 /* keyboard */
4587 seat->logical_keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE,
4588 first_property_name: "name", "Core Keyboard",
4589 "source", GDK_SOURCE_KEYBOARD,
4590 "has-cursor", FALSE,
4591 "display", seat->display,
4592 "seat", seat,
4593 NULL);
4594 _gdk_device_reset_axes (device: seat->logical_keyboard);
4595
4596 /* link both */
4597 _gdk_device_set_associated_device (device: seat->logical_pointer, relative: seat->logical_keyboard);
4598 _gdk_device_set_associated_device (device: seat->logical_keyboard, relative: seat->logical_pointer);
4599
4600 gdk_seat_device_added (GDK_SEAT (seat), device: seat->logical_pointer);
4601 gdk_seat_device_added (GDK_SEAT (seat), device: seat->logical_keyboard);
4602}
4603
4604static void
4605pointer_surface_update_scale (GdkDevice *device)
4606{
4607 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
4608 GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
4609 GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
4610 guint32 scale;
4611 GSList *l;
4612
4613 if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
4614 {
4615 /* We can't set the scale on this surface */
4616 return;
4617 }
4618
4619 if (!pointer->pointer_surface_outputs)
4620 return;
4621
4622 scale = 1;
4623 for (l = pointer->pointer_surface_outputs; l != NULL; l = l->next)
4624 {
4625 guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, output: l->data);
4626 scale = MAX (scale, output_scale);
4627 }
4628
4629 if (pointer->current_output_scale == scale)
4630 return;
4631 pointer->current_output_scale = scale;
4632
4633 gdk_wayland_device_update_surface_cursor (device);
4634}
4635
4636void
4637gdk_wayland_seat_update_cursor_scale (GdkWaylandSeat *seat)
4638{
4639 GList *l;
4640
4641 pointer_surface_update_scale (device: seat->logical_pointer);
4642
4643 for (l = seat->tablets; l; l = l->next)
4644 {
4645 GdkWaylandTabletData *tablet = l->data;
4646 pointer_surface_update_scale (device: tablet->logical_device);
4647 }
4648}
4649
4650static void
4651pointer_surface_enter (void *data,
4652 struct wl_surface *wl_surface,
4653 struct wl_output *output)
4654
4655{
4656 GdkDevice *device = data;
4657 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
4658 GdkWaylandTabletData *tablet;
4659
4660 GDK_SEAT_NOTE (seat, EVENTS,
4661 g_message ("pointer surface of seat %p entered output %p",
4662 seat, output));
4663
4664 tablet = gdk_wayland_seat_find_tablet (seat, device);
4665
4666 if (tablet)
4667 {
4668 tablet->pointer_info.pointer_surface_outputs =
4669 g_slist_append (list: tablet->pointer_info.pointer_surface_outputs, data: output);
4670 }
4671 else
4672 {
4673 seat->pointer_info.pointer_surface_outputs =
4674 g_slist_append (list: seat->pointer_info.pointer_surface_outputs, data: output);
4675 }
4676
4677 pointer_surface_update_scale (device);
4678}
4679
4680static void
4681pointer_surface_leave (void *data,
4682 struct wl_surface *wl_surface,
4683 struct wl_output *output)
4684{
4685 GdkDevice *device = data;
4686 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
4687 GdkWaylandTabletData *tablet;
4688
4689 GDK_SEAT_NOTE (seat, EVENTS,
4690 g_message ("pointer surface of seat %p left output %p",
4691 seat, output));
4692
4693 tablet = gdk_wayland_seat_find_tablet (seat, device);
4694
4695 if (tablet)
4696 {
4697 tablet->pointer_info.pointer_surface_outputs =
4698 g_slist_remove (list: tablet->pointer_info.pointer_surface_outputs, data: output);
4699 }
4700 else
4701 {
4702 seat->pointer_info.pointer_surface_outputs =
4703 g_slist_remove (list: seat->pointer_info.pointer_surface_outputs, data: output);
4704 }
4705
4706 pointer_surface_update_scale (device);
4707}
4708
4709static const struct wl_surface_listener pointer_surface_listener = {
4710 pointer_surface_enter,
4711 pointer_surface_leave
4712};
4713
4714static void
4715gdk_wayland_pointer_data_finalize (GdkWaylandPointerData *pointer)
4716{
4717 g_clear_object (&pointer->focus);
4718 g_clear_object (&pointer->cursor);
4719 wl_surface_destroy (wl_surface: pointer->pointer_surface);
4720 g_slist_free (list: pointer->pointer_surface_outputs);
4721}
4722
4723static void
4724gdk_wayland_seat_finalize (GObject *object)
4725{
4726 GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (object);
4727 GList *l;
4728
4729 for (l = seat->tablet_tools; l != NULL; l = l->next)
4730 _gdk_wayland_seat_remove_tool (seat, tool: l->data);
4731
4732 for (l = seat->tablet_pads; l != NULL; l = l->next)
4733 _gdk_wayland_seat_remove_tablet_pad (seat, pad: l->data);
4734
4735 for (l = seat->tablets; l != NULL; l = l->next)
4736 _gdk_wayland_seat_remove_tablet (seat, tablet: l->data);
4737
4738 seat_handle_capabilities (data: seat, wl_seat: seat->wl_seat, caps: 0);
4739 g_object_unref (object: seat->keymap);
4740 gdk_wayland_pointer_data_finalize (pointer: &seat->pointer_info);
4741 /* FIXME: destroy data_device */
4742 g_clear_object (&seat->drag);
4743 g_clear_object (&seat->drop);
4744 g_clear_object (&seat->clipboard);
4745 g_clear_object (&seat->primary_clipboard);
4746 g_hash_table_destroy (hash_table: seat->touches);
4747 zwp_tablet_seat_v2_destroy (seat->wp_tablet_seat);
4748 stop_key_repeat (seat);
4749
4750 G_OBJECT_CLASS (gdk_wayland_seat_parent_class)->finalize (object);
4751}
4752
4753static GdkSeatCapabilities
4754gdk_wayland_seat_get_capabilities (GdkSeat *seat)
4755{
4756 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
4757 GdkSeatCapabilities caps = 0;
4758
4759 if (wayland_seat->logical_pointer)
4760 caps |= GDK_SEAT_CAPABILITY_POINTER;
4761 if (wayland_seat->logical_keyboard)
4762 caps |= GDK_SEAT_CAPABILITY_KEYBOARD;
4763 if (wayland_seat->logical_touch)
4764 caps |= GDK_SEAT_CAPABILITY_TOUCH;
4765
4766 return caps;
4767}
4768
4769static void
4770gdk_wayland_seat_set_grab_surface (GdkWaylandSeat *seat,
4771 GdkSurface *surface)
4772{
4773 if (seat->grab_surface)
4774 {
4775 _gdk_wayland_surface_set_grab_seat (surface: seat->grab_surface, NULL);
4776 g_object_remove_weak_pointer (G_OBJECT (seat->grab_surface),
4777 weak_pointer_location: (gpointer *) &seat->grab_surface);
4778 seat->grab_surface = NULL;
4779 }
4780
4781 if (surface)
4782 {
4783 seat->grab_surface = surface;
4784 g_object_add_weak_pointer (G_OBJECT (surface),
4785 weak_pointer_location: (gpointer *) &seat->grab_surface);
4786 _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (seat));
4787 }
4788}
4789
4790static GdkGrabStatus
4791gdk_wayland_seat_grab (GdkSeat *seat,
4792 GdkSurface *surface,
4793 GdkSeatCapabilities capabilities,
4794 gboolean owner_events,
4795 GdkCursor *cursor,
4796 GdkEvent *event,
4797 GdkSeatGrabPrepareFunc prepare_func,
4798 gpointer prepare_func_data)
4799{
4800 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
4801 guint32 evtime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME;
4802 GdkDisplay *display = gdk_seat_get_display (seat);
4803 GList *l;
4804
4805 if (surface == NULL || GDK_SURFACE_DESTROYED (surface))
4806 return GDK_GRAB_NOT_VIEWABLE;
4807
4808 gdk_wayland_seat_set_grab_surface (seat: wayland_seat, surface);
4809 wayland_seat->grab_time = evtime;
4810
4811 if (prepare_func)
4812 (prepare_func) (seat, surface, prepare_func_data);
4813
4814 if (!gdk_wayland_surface_has_surface (surface))
4815 {
4816 gdk_wayland_seat_set_grab_surface (seat: wayland_seat, NULL);
4817 return GDK_GRAB_NOT_VIEWABLE;
4818 }
4819
4820 if (wayland_seat->logical_pointer &&
4821 capabilities & GDK_SEAT_CAPABILITY_POINTER)
4822 {
4823 device_maybe_emit_grab_crossing (device: wayland_seat->logical_pointer,
4824 window: surface, time: evtime);
4825
4826 _gdk_display_add_device_grab (display,
4827 device: wayland_seat->logical_pointer,
4828 surface,
4829 owner_events,
4830 event_mask: GDK_ALL_EVENTS_MASK,
4831 serial_start: _gdk_display_get_next_serial (display),
4832 time: evtime,
4833 FALSE);
4834
4835 gdk_wayland_seat_set_global_cursor (seat, cursor);
4836 g_set_object (&wayland_seat->cursor, cursor);
4837 gdk_wayland_device_update_surface_cursor (device: wayland_seat->logical_pointer);
4838 }
4839
4840 if (wayland_seat->logical_touch &&
4841 capabilities & GDK_SEAT_CAPABILITY_TOUCH)
4842 {
4843 device_maybe_emit_grab_crossing (device: wayland_seat->logical_touch,
4844 window: surface, time: evtime);
4845
4846 _gdk_display_add_device_grab (display,
4847 device: wayland_seat->logical_touch,
4848 surface,
4849 owner_events,
4850 event_mask: GDK_ALL_EVENTS_MASK,
4851 serial_start: _gdk_display_get_next_serial (display),
4852 time: evtime,
4853 FALSE);
4854 }
4855
4856 if (wayland_seat->logical_keyboard &&
4857 capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)
4858 {
4859 device_maybe_emit_grab_crossing (device: wayland_seat->logical_keyboard,
4860 window: surface, time: evtime);
4861
4862 _gdk_display_add_device_grab (display,
4863 device: wayland_seat->logical_keyboard,
4864 surface,
4865 owner_events,
4866 event_mask: GDK_ALL_EVENTS_MASK,
4867 serial_start: _gdk_display_get_next_serial (display),
4868 time: evtime,
4869 FALSE);
4870
4871 /* Inhibit shortcuts if the seat grab is for the keyboard only */
4872 if (capabilities == GDK_SEAT_CAPABILITY_KEYBOARD)
4873 gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat: seat);
4874 }
4875
4876 if (wayland_seat->tablets &&
4877 capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS)
4878 {
4879 for (l = wayland_seat->tablets; l; l = l->next)
4880 {
4881 GdkWaylandTabletData *tablet = l->data;
4882
4883 device_maybe_emit_grab_crossing (device: tablet->logical_device,
4884 window: surface,
4885 time: evtime);
4886
4887 _gdk_display_add_device_grab (display,
4888 device: tablet->logical_device,
4889 surface,
4890 owner_events,
4891 event_mask: GDK_ALL_EVENTS_MASK,
4892 serial_start: _gdk_display_get_next_serial (display),
4893 time: evtime,
4894 FALSE);
4895
4896 gdk_wayland_device_update_surface_cursor (device: tablet->logical_device);
4897 }
4898 }
4899
4900 return GDK_GRAB_SUCCESS;
4901}
4902
4903static void
4904gdk_wayland_seat_ungrab (GdkSeat *seat)
4905{
4906 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
4907 GdkDisplay *display = gdk_seat_get_display (seat);
4908 GdkDeviceGrabInfo *grab;
4909 GList *l;
4910
4911 g_clear_object (&wayland_seat->grab_cursor);
4912
4913 gdk_wayland_seat_set_grab_surface (seat: wayland_seat, NULL);
4914
4915 if (wayland_seat->logical_pointer)
4916 {
4917 device_maybe_emit_ungrab_crossing (device: wayland_seat->logical_pointer,
4918 GDK_CURRENT_TIME);
4919
4920 gdk_wayland_device_update_surface_cursor (device: wayland_seat->logical_pointer);
4921 }
4922
4923 if (wayland_seat->logical_keyboard)
4924 {
4925 GdkSurface *prev_focus;
4926
4927 prev_focus = device_maybe_emit_ungrab_crossing (device: wayland_seat->logical_keyboard,
4928 GDK_CURRENT_TIME);
4929 if (prev_focus)
4930 gdk_wayland_surface_restore_shortcuts (surface: prev_focus, gdk_seat: seat);
4931 }
4932
4933 if (wayland_seat->logical_touch)
4934 {
4935 grab = _gdk_display_get_last_device_grab (display, device: wayland_seat->logical_touch);
4936
4937 if (grab)
4938 grab->serial_end = grab->serial_start;
4939 }
4940
4941 for (l = wayland_seat->tablets; l; l = l->next)
4942 {
4943 GdkWaylandTabletData *tablet = l->data;
4944
4945 grab = _gdk_display_get_last_device_grab (display, device: tablet->logical_device);
4946
4947 if (grab)
4948 grab->serial_end = grab->serial_start;
4949 }
4950}
4951
4952static GdkDevice *
4953gdk_wayland_seat_get_logical_device (GdkSeat *seat,
4954 GdkSeatCapabilities capabilities)
4955{
4956 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
4957
4958 if (capabilities == GDK_SEAT_CAPABILITY_POINTER)
4959 return wayland_seat->logical_pointer;
4960 else if (capabilities == GDK_SEAT_CAPABILITY_KEYBOARD)
4961 return wayland_seat->logical_keyboard;
4962 else if (capabilities == GDK_SEAT_CAPABILITY_TOUCH)
4963 return wayland_seat->logical_touch;
4964
4965 return NULL;
4966}
4967
4968static GList *
4969gdk_wayland_seat_get_devices (GdkSeat *seat,
4970 GdkSeatCapabilities capabilities)
4971{
4972 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
4973 GList *physical_devices = NULL;
4974
4975 if (wayland_seat->finger_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER))
4976 physical_devices = g_list_prepend (list: physical_devices, data: wayland_seat->finger_scrolling);
4977 if (wayland_seat->continuous_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER))
4978 physical_devices = g_list_prepend (list: physical_devices, data: wayland_seat->continuous_scrolling);
4979 if (wayland_seat->wheel_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER))
4980 physical_devices = g_list_prepend (list: physical_devices, data: wayland_seat->wheel_scrolling);
4981 if (wayland_seat->pointer && (capabilities & GDK_SEAT_CAPABILITY_POINTER))
4982 physical_devices = g_list_prepend (list: physical_devices, data: wayland_seat->pointer);
4983 if (wayland_seat->keyboard && (capabilities & GDK_SEAT_CAPABILITY_KEYBOARD))
4984 physical_devices = g_list_prepend (list: physical_devices, data: wayland_seat->keyboard);
4985 if (wayland_seat->touch && (capabilities & GDK_SEAT_CAPABILITY_TOUCH))
4986 physical_devices = g_list_prepend (list: physical_devices, data: wayland_seat->touch);
4987
4988 if (wayland_seat->tablets && (capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS))
4989 {
4990 GList *l;
4991
4992 for (l = wayland_seat->tablets; l; l = l->next)
4993 {
4994 GdkWaylandTabletData *tablet = l->data;
4995
4996 physical_devices = g_list_prepend (list: physical_devices, data: tablet->stylus_device);
4997 }
4998 }
4999
5000 if (wayland_seat->tablet_pads && (capabilities & GDK_SEAT_CAPABILITY_TABLET_PAD))
5001 {
5002 GList *l;
5003
5004 for (l = wayland_seat->tablet_pads; l; l = l->next)
5005 {
5006 GdkWaylandTabletPadData *data = l->data;
5007 physical_devices = g_list_prepend (list: physical_devices, data: data->device);
5008 }
5009 }
5010
5011 return physical_devices;
5012}
5013
5014static GList *
5015gdk_wayland_seat_get_tools (GdkSeat *seat)
5016{
5017 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
5018 GList *tools = NULL, *l;
5019
5020 for (l = wayland_seat->tablet_tools; l; l = l->next)
5021 {
5022 GdkWaylandTabletToolData *tool = l->data;
5023
5024 tools = g_list_prepend (list: tools, data: tool->tool);
5025 }
5026
5027 return tools;
5028}
5029
5030static void
5031gdk_wayland_seat_class_init (GdkWaylandSeatClass *klass)
5032{
5033 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5034 GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass);
5035
5036 object_class->finalize = gdk_wayland_seat_finalize;
5037
5038 seat_class->get_capabilities = gdk_wayland_seat_get_capabilities;
5039 seat_class->grab = gdk_wayland_seat_grab;
5040 seat_class->ungrab = gdk_wayland_seat_ungrab;
5041 seat_class->get_logical_device = gdk_wayland_seat_get_logical_device;
5042 seat_class->get_devices = gdk_wayland_seat_get_devices;
5043 seat_class->get_tools = gdk_wayland_seat_get_tools;
5044}
5045
5046static void
5047gdk_wayland_seat_init (GdkWaylandSeat *seat)
5048{
5049}
5050
5051static void
5052init_pointer_data (GdkWaylandPointerData *pointer_data,
5053 GdkDisplay *display,
5054 GdkDevice *logical_device)
5055{
5056 GdkWaylandDisplay *display_wayland;
5057
5058 display_wayland = GDK_WAYLAND_DISPLAY (display);
5059
5060 pointer_data->current_output_scale = 1;
5061 pointer_data->pointer_surface =
5062 wl_compositor_create_surface (wl_compositor: display_wayland->compositor);
5063 wl_surface_add_listener (wl_surface: pointer_data->pointer_surface,
5064 listener: &pointer_surface_listener,
5065 data: logical_device);
5066}
5067
5068void
5069_gdk_wayland_display_create_seat (GdkWaylandDisplay *display_wayland,
5070 guint32 id,
5071 struct wl_seat *wl_seat)
5072{
5073 GdkDisplay *display = GDK_DISPLAY (display_wayland);
5074 GdkWaylandSeat *seat;
5075
5076 seat = g_object_new (GDK_TYPE_WAYLAND_SEAT,
5077 first_property_name: "display", display_wayland,
5078 NULL);
5079 seat->id = id;
5080 seat->keymap = _gdk_wayland_keymap_new (display);
5081 seat->display = display;
5082 seat->touches = g_hash_table_new_full (NULL, NULL, NULL, value_destroy_func: (GDestroyNotify) g_free);
5083 seat->wl_seat = wl_seat;
5084
5085 wl_seat_add_listener (wl_seat: seat->wl_seat, listener: &seat_listener, data: seat);
5086 wl_seat_set_user_data (wl_seat: seat->wl_seat, user_data: seat);
5087
5088 if (display_wayland->primary_selection_manager)
5089 {
5090 seat->primary_clipboard = gdk_wayland_primary_new (seat);
5091 }
5092 else
5093 {
5094 /* If the compositor doesn't support primary clipboard,
5095 * just do it local-only */
5096 seat->primary_clipboard = gdk_clipboard_new (display);
5097 }
5098
5099 seat->data_device =
5100 wl_data_device_manager_get_data_device (wl_data_device_manager: display_wayland->data_device_manager,
5101 seat: seat->wl_seat);
5102 seat->clipboard = gdk_wayland_clipboard_new (display);
5103 wl_data_device_add_listener (wl_data_device: seat->data_device,
5104 listener: &data_device_listener, data: seat);
5105
5106 init_devices (seat);
5107 init_pointer_data (pointer_data: &seat->pointer_info, display, logical_device: seat->logical_pointer);
5108
5109 if (display_wayland->tablet_manager)
5110 {
5111 seat->wp_tablet_seat =
5112 zwp_tablet_manager_v2_get_tablet_seat (display_wayland->tablet_manager,
5113 wl_seat);
5114 zwp_tablet_seat_v2_add_listener (seat->wp_tablet_seat, &tablet_seat_listener,
5115 seat);
5116 }
5117
5118 if (display->clipboard == NULL)
5119 display->clipboard = g_object_ref (seat->clipboard);
5120 if (display->primary_clipboard == NULL)
5121 display->primary_clipboard = g_object_ref (seat->primary_clipboard);
5122
5123 gdk_display_add_seat (display, GDK_SEAT (seat));
5124}
5125
5126void
5127_gdk_wayland_display_remove_seat (GdkWaylandDisplay *display_wayland,
5128 guint32 id)
5129{
5130 GdkDisplay *display = GDK_DISPLAY (display_wayland);
5131 GList *l, *seats;
5132
5133 seats = gdk_display_list_seats (display);
5134
5135 for (l = seats; l != NULL; l = l->next)
5136 {
5137 GdkWaylandSeat *seat = l->data;
5138
5139 if (seat->id != id)
5140 continue;
5141
5142 gdk_display_remove_seat (display, GDK_SEAT (seat));
5143 break;
5144 }
5145
5146 g_list_free (list: seats);
5147}
5148
5149uint32_t
5150_gdk_wayland_seat_get_implicit_grab_serial (GdkSeat *seat,
5151 GdkEvent *event)
5152{
5153 GdkEventSequence *sequence = NULL;
5154 GdkWaylandTouchData *touch = NULL;
5155
5156 if (event)
5157 sequence = gdk_event_get_event_sequence (event);
5158
5159 if (sequence)
5160 touch = gdk_wayland_seat_get_touch (GDK_WAYLAND_SEAT (seat),
5161 GDK_EVENT_SEQUENCE_TO_SLOT (sequence));
5162
5163 if (touch)
5164 return touch->touch_down_serial;
5165
5166 if (event)
5167 {
5168 GdkDevice *source = gdk_event_get_device (event);
5169 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
5170 GList *l;
5171
5172 for (l = wayland_seat->tablets; l; l = l->next)
5173 {
5174 GdkWaylandTabletData *tablet = l->data;
5175
5176 if (tablet->stylus_device == source)
5177 return tablet->pointer_info.press_serial;
5178 }
5179 }
5180
5181 return GDK_WAYLAND_SEAT (seat)->pointer_info.press_serial;
5182}
5183
5184uint32_t
5185_gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat,
5186 GdkEventSequence **sequence)
5187{
5188 GdkWaylandTouchData *touch;
5189 GHashTableIter iter;
5190 GList *l;
5191 uint32_t serial;
5192
5193 g_hash_table_iter_init (iter: &iter, hash_table: seat->touches);
5194
5195 if (sequence)
5196 *sequence = NULL;
5197
5198 serial = seat->keyboard_key_serial;
5199
5200 if (seat->pointer_info.press_serial > serial)
5201 serial = seat->pointer_info.press_serial;
5202
5203 for (l = seat->tablets; l; l = l->next)
5204 {
5205 GdkWaylandTabletData *tablet = l->data;
5206
5207 if (tablet->pointer_info.press_serial > serial)
5208 serial = tablet->pointer_info.press_serial;
5209 }
5210
5211 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer *) &touch))
5212 {
5213 if (touch->touch_down_serial > serial)
5214 {
5215 if (sequence)
5216 *sequence = GDK_SLOT_TO_EVENT_SEQUENCE (touch->id);
5217 serial = touch->touch_down_serial;
5218 }
5219 }
5220
5221 return serial;
5222}
5223
5224void
5225gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device,
5226 GdkEventSequence *sequence)
5227{
5228 GdkWaylandSeat *seat;
5229 GdkWaylandTouchData *touch;
5230 GdkEvent *event;
5231
5232 g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device));
5233
5234 seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device));
5235 touch = gdk_wayland_seat_get_touch (seat,
5236 GDK_EVENT_SEQUENCE_TO_SLOT (sequence));
5237
5238 if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch == touch)
5239 {
5240 GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL;
5241 emulate_touch_crossing (surface: touch->surface, NULL,
5242 device: seat->logical_touch, source: seat->touch,
5243 touch, type: GDK_LEAVE_NOTIFY, mode: GDK_CROSSING_NORMAL,
5244 GDK_CURRENT_TIME);
5245 }
5246
5247 event = gdk_touch_event_new (type: GDK_TOUCH_CANCEL,
5248 GDK_SLOT_TO_EVENT_SEQUENCE (touch->id),
5249 surface: touch->surface,
5250 device: seat->logical_touch,
5251 GDK_CURRENT_TIME,
5252 state: device_get_modifiers (device: seat->logical_touch),
5253 x: touch->x, y: touch->y,
5254 NULL,
5255 emulating: touch->initial_touch);
5256 _gdk_wayland_display_deliver_event (display: seat->display, event);
5257}
5258
5259void
5260gdk_wayland_seat_set_global_cursor (GdkSeat *seat,
5261 GdkCursor *cursor)
5262{
5263 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
5264 GdkDevice *pointer;
5265
5266 pointer = gdk_seat_get_pointer (seat);
5267
5268 g_set_object (&wayland_seat->grab_cursor, cursor);
5269 gdk_wayland_device_set_surface_cursor (device: pointer,
5270 surface: gdk_wayland_device_get_focus (device: pointer),
5271 NULL);
5272}
5273
5274void
5275gdk_wayland_seat_set_drag (GdkSeat *seat,
5276 GdkDrag *drag)
5277{
5278 GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat);
5279
5280 g_set_object (&wayland_seat->drag, drag);
5281}
5282
5283/**
5284 * gdk_wayland_device_get_data_device: (skip)
5285 * @gdk_device: (type GdkWaylandDevice): a `GdkDevice`
5286 *
5287 * Returns the Wayland `wl_data_device` of a `GdkDevice`.
5288 *
5289 * Returns: (transfer none): a Wayland `wl_data_device`
5290 */
5291struct wl_data_device *
5292gdk_wayland_device_get_data_device (GdkDevice *gdk_device)
5293{
5294 GdkWaylandSeat *seat;
5295
5296 g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device), NULL);
5297
5298 seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device));
5299 return seat->data_device;
5300}
5301
5302/**
5303 * gdk_wayland_device_set_selection: (skip)
5304 * @gdk_device: (type GdkWaylandDevice): a `GdkDevice`
5305 * @source: the data source for the selection
5306 *
5307 * Sets the selection of the `GdkDevice.
5308 *
5309 * This is calling wl_data_device_set_selection() on
5310 * the `wl_data_device` of @gdk_device.
5311 */
5312void
5313gdk_wayland_device_set_selection (GdkDevice *gdk_device,
5314 struct wl_data_source *source)
5315{
5316 GdkWaylandSeat *seat;
5317 GdkWaylandDisplay *display_wayland;
5318
5319 g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device));
5320
5321 seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device));
5322 display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
5323
5324 wl_data_device_set_selection (wl_data_device: seat->data_device, source,
5325 serial: _gdk_wayland_display_get_serial (display_wayland));
5326}
5327
5328/**
5329 * gdk_wayland_seat_get_wl_seat: (skip)
5330 * @seat: (type GdkWaylandSeat): a `GdkSeat`
5331 *
5332 * Returns the Wayland `wl_seat` of a `GdkSeat`.
5333 *
5334 * Returns: (transfer none): a Wayland `wl_seat`
5335 */
5336struct wl_seat *
5337gdk_wayland_seat_get_wl_seat (GdkSeat *seat)
5338{
5339 g_return_val_if_fail (GDK_IS_WAYLAND_SEAT (seat), NULL);
5340
5341 return GDK_WAYLAND_SEAT (seat)->wl_seat;
5342}
5343
5344/**
5345 * gdk_wayland_device_get_node_path:
5346 * @device: (type GdkWaylandDevice): a `GdkDevice`
5347 *
5348 * Returns the `/dev/input/event*` path of this device.
5349 *
5350 * For `GdkDevice`s that possibly coalesce multiple hardware
5351 * devices (eg. mouse, keyboard, touch,...), this function
5352 * will return %NULL.
5353 *
5354 * This is most notably implemented for devices of type
5355 * %GDK_SOURCE_PEN, %GDK_SOURCE_TABLET_PAD.
5356 *
5357 * Returns: (nullable) (transfer none): the `/dev/input/event*`
5358 * path of this device
5359 */
5360const char *
5361gdk_wayland_device_get_node_path (GdkDevice *device)
5362{
5363 GdkWaylandTabletData *tablet;
5364 GdkWaylandTabletPadData *pad;
5365
5366 GdkSeat *seat;
5367
5368 g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
5369
5370 seat = gdk_device_get_seat (device);
5371 tablet = gdk_wayland_seat_find_tablet (GDK_WAYLAND_SEAT (seat), device);
5372 if (tablet)
5373 return tablet->path;
5374
5375 pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device);
5376 if (pad)
5377 return pad->path;
5378
5379 return NULL;
5380}
5381
5382/*<private>
5383 * gdk_wayland_device_pad_set_feedback:
5384 * @device: (type GdkWaylandDevice): a %GDK_SOURCE_TABLET_PAD device
5385 * @feature: Feature to set the feedback label for
5386 * @feature_idx: 0-indexed index of the feature to set the feedback label for
5387 * @label: Feedback label
5388 *
5389 * Sets the feedback label for the given feature/index.
5390 *
5391 * This may be used by the compositor to provide user feedback
5392 * of the actions available/performed.
5393 */
5394void
5395gdk_wayland_device_pad_set_feedback (GdkDevice *device,
5396 GdkDevicePadFeature feature,
5397 guint feature_idx,
5398 const char *label)
5399{
5400 GdkWaylandTabletPadData *pad;
5401 GdkWaylandTabletPadGroupData *group;
5402 GdkSeat *seat;
5403
5404 seat = gdk_device_get_seat (device);
5405 pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device);
5406 if (!pad)
5407 return;
5408
5409 if (feature == GDK_DEVICE_PAD_FEATURE_BUTTON)
5410 {
5411 group = tablet_pad_lookup_button_group (pad, button: feature_idx);
5412 if (!group)
5413 return;
5414
5415 zwp_tablet_pad_v2_set_feedback (pad->wp_tablet_pad, feature_idx, label,
5416 group->mode_switch_serial);
5417 }
5418 else if (feature == GDK_DEVICE_PAD_FEATURE_RING)
5419 {
5420 struct zwp_tablet_pad_ring_v2 *wp_pad_ring;
5421
5422 wp_pad_ring = g_list_nth_data (list: pad->rings, n: feature_idx);
5423 if (!wp_pad_ring)
5424 return;
5425
5426 group = zwp_tablet_pad_ring_v2_get_user_data (wp_pad_ring);
5427 zwp_tablet_pad_ring_v2_set_feedback (wp_pad_ring, label,
5428 group->mode_switch_serial);
5429
5430 }
5431 else if (feature == GDK_DEVICE_PAD_FEATURE_STRIP)
5432 {
5433 struct zwp_tablet_pad_strip_v2 *wp_pad_strip;
5434
5435 wp_pad_strip = g_list_nth_data (list: pad->strips, n: feature_idx);
5436 if (!wp_pad_strip)
5437 return;
5438
5439 group = zwp_tablet_pad_strip_v2_get_user_data (wp_pad_strip);
5440 zwp_tablet_pad_strip_v2_set_feedback (wp_pad_strip, label,
5441 group->mode_switch_serial);
5442 }
5443}
5444

source code of gtk/gdk/wayland/gdkdevice-wayland.c