From 6426ab74667d6efbc9427d95135383cac158f532 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 2 Feb 2023 15:53:57 +0100 Subject: gdk/wayland: Rename gdkdevice-wayland.c to gdkseat-wayland.c This file, event though a clump of input-y objects, has more of seats than anything else. Rename it so that we can start splitting these objects out of it. --- gdk/wayland/gdkdevice-wayland.c | 5461 --------------------------------------- gdk/wayland/gdkseat-wayland.c | 5461 +++++++++++++++++++++++++++++++++++++++ gdk/wayland/meson.build | 2 +- 3 files changed, 5462 insertions(+), 5462 deletions(-) delete mode 100644 gdk/wayland/gdkdevice-wayland.c create mode 100644 gdk/wayland/gdkseat-wayland.c diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c deleted file mode 100644 index 90ecad458a..0000000000 --- a/gdk/wayland/gdkdevice-wayland.c +++ /dev/null @@ -1,5461 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * Copyright (C) 2009 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -#include "config.h" - -#include "gdkdevice-wayland-private.h" - -#include "gdkclipboard-wayland.h" -#include "gdkclipboardprivate.h" -#include "gdkcursorprivate.h" -#include "gdkdeviceprivate.h" -#include "gdkdevicepadprivate.h" -#include "gdkdevicetoolprivate.h" -#include "gdkdropprivate.h" -#include "gdkeventsprivate.h" -#include "gdkkeysprivate.h" -#include "gdkkeysyms.h" -#include "gdkprimary-wayland.h" -#include "gdkprivate-wayland.h" -#include "gdkseat-wayland.h" -#include "gdkseatprivate.h" -#include "gdksurfaceprivate.h" -#include "gdktypes.h" -#include "gdkwayland.h" -#include "gdkprivate.h" - -#include "pointer-gestures-unstable-v1-client-protocol.h" -#include "tablet-unstable-v2-client-protocol.h" - -#include - -#include -#include -#include -#include -#include -#include -#if defined(HAVE_DEV_EVDEV_INPUT_H) -#include -#elif defined(HAVE_LINUX_INPUT_H) -#include -#endif - -/** - * GdkWaylandDevice: - * - * The Wayland implementation of `GdkDevice`. - * - * Beyond the regular [class@Gdk.Device] API, the Wayland implementation - * provides access to Wayland objects such as the `wl_seat` with - * [method@GdkWayland.WaylandDevice.get_wl_seat], the `wl_keyboard` with - * [method@GdkWayland.WaylandDevice.get_wl_keyboard] and the `wl_pointer` with - * [method@GdkWayland.WaylandDevice.get_wl_pointer]. - */ - -/** - * GdkWaylandSeat: - * - * The Wayland implementation of `GdkSeat`. - * - * Beyond the regular [class@Gdk.Seat] API, the Wayland implementation - * provides access to the Wayland `wl_seat` object with - * [method@GdkWayland.WaylandSeat.get_wl_seat]. - */ - -#define BUTTON_BASE (BTN_LEFT - 1) /* Used to translate to 1-indexed buttons */ - -#ifndef BTN_STYLUS3 -#define BTN_STYLUS3 0x149 /* Linux 4.15 */ -#endif - -#define ALL_BUTTONS_MASK (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | \ - GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | \ - GDK_BUTTON5_MASK) - -#define GDK_SEAT_DEBUG(seat,type,...) GDK_DISPLAY_DEBUG(gdk_seat_get_display (GDK_SEAT (seat)),type,__VA_ARGS__) - -typedef struct _GdkWaylandDevicePad GdkWaylandDevicePad; -typedef struct _GdkWaylandDevicePadClass GdkWaylandDevicePadClass; - -typedef struct _GdkWaylandTouchData GdkWaylandTouchData; -typedef struct _GdkWaylandPointerFrameData GdkWaylandPointerFrameData; -typedef struct _GdkWaylandPointerData GdkWaylandPointerData; -typedef struct _GdkWaylandTabletData GdkWaylandTabletData; -typedef struct _GdkWaylandTabletToolData GdkWaylandTabletToolData; -typedef struct _GdkWaylandTabletPadGroupData GdkWaylandTabletPadGroupData; -typedef struct _GdkWaylandTabletPadData GdkWaylandTabletPadData; - -struct _GdkWaylandTouchData -{ - uint32_t id; - double x; - double y; - GdkSurface *surface; - uint32_t touch_down_serial; - guint initial_touch : 1; -}; - -struct _GdkWaylandPointerFrameData -{ - GdkEvent *event; - - /* Specific to the scroll event */ - double delta_x, delta_y; - int32_t value120_x, value120_y; - gint8 is_scroll_stop; - enum wl_pointer_axis_source source; -}; - -struct _GdkWaylandPointerData { - GdkSurface *focus; - - double surface_x, surface_y; - - GdkModifierType button_modifiers; - - uint32_t time; - uint32_t enter_serial; - uint32_t press_serial; - - GdkSurface *grab_surface; - uint32_t grab_time; - - struct wl_surface *pointer_surface; - guint cursor_is_default: 1; - GdkCursor *cursor; - guint cursor_timeout_id; - guint cursor_image_index; - guint cursor_image_delay; - guint touchpad_event_sequence; - - guint current_output_scale; - GSList *pointer_surface_outputs; - - /* Accumulated event data for a pointer frame */ - GdkWaylandPointerFrameData frame; -}; - -struct _GdkWaylandTabletToolData -{ - GdkSeat *seat; - struct zwp_tablet_tool_v2 *wp_tablet_tool; - GdkAxisFlags axes; - GdkDeviceToolType type; - guint64 hardware_serial; - guint64 hardware_id_wacom; - - GdkDeviceTool *tool; - GdkWaylandTabletData *current_tablet; -}; - -struct _GdkWaylandTabletPadGroupData -{ - GdkWaylandTabletPadData *pad; - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group; - GList *rings; - GList *strips; - GList *buttons; - - guint mode_switch_serial; - guint n_modes; - guint current_mode; - - struct { - guint source; - gboolean is_stop; - double value; - } axis_tmp_info; -}; - -struct _GdkWaylandTabletPadData -{ - GdkSeat *seat; - struct zwp_tablet_pad_v2 *wp_tablet_pad; - GdkDevice *device; - - GdkWaylandTabletData *current_tablet; - - guint enter_serial; - uint32_t n_buttons; - char *path; - - GList *rings; - GList *strips; - GList *mode_groups; -}; - -struct _GdkWaylandTabletData -{ - struct zwp_tablet_v2 *wp_tablet; - char *name; - char *path; - uint32_t vid; - uint32_t pid; - - GdkDevice *logical_device; - GdkDevice *stylus_device; - GdkSeat *seat; - GdkWaylandPointerData pointer_info; - - GList *pads; - - GdkWaylandTabletToolData *current_tool; - - int axis_indices[GDK_AXIS_LAST]; - double axes[GDK_AXIS_LAST]; -}; - -struct _GdkWaylandSeat -{ - GdkSeat parent_instance; - - guint32 id; - struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; - struct wl_keyboard *wl_keyboard; - struct wl_touch *wl_touch; - struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe; - struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch; - struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold; - struct zwp_tablet_seat_v2 *wp_tablet_seat; - - GdkDisplay *display; - - GdkDevice *logical_pointer; - GdkDevice *logical_keyboard; - GdkDevice *pointer; - GdkDevice *wheel_scrolling; - GdkDevice *finger_scrolling; - GdkDevice *continuous_scrolling; - GdkDevice *keyboard; - GdkDevice *logical_touch; - GdkDevice *touch; - GdkCursor *cursor; - GdkKeymap *keymap; - - GHashTable *touches; - GList *tablets; - GList *tablet_tools; - GList *tablet_pads; - - GdkWaylandPointerData pointer_info; - GdkWaylandPointerData touch_info; - - GdkModifierType key_modifiers; - GdkSurface *keyboard_focus; - GdkSurface *grab_surface; - uint32_t grab_time; - gboolean have_server_repeat; - uint32_t server_repeat_rate; - uint32_t server_repeat_delay; - - struct wl_data_offer *pending_offer; - GdkContentFormatsBuilder *pending_builder; - GdkDragAction pending_source_actions; - GdkDragAction pending_action; - - struct wl_callback *repeat_callback; - guint32 repeat_timer; - guint32 repeat_key; - guint32 repeat_count; - gint64 repeat_deadline; - uint32_t keyboard_time; - uint32_t keyboard_key_serial; - - GdkClipboard *clipboard; - GdkClipboard *primary_clipboard; - struct wl_data_device *data_device; - GdkDrag *drag; - GdkDrop *drop; - - /* Some tracking on gesture events */ - guint gesture_n_fingers; - double gesture_scale; - - GdkCursor *grab_cursor; -}; - -G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT) - -struct _GdkWaylandDevice -{ - GdkDevice parent_instance; - GdkWaylandTouchData *emulating_touch; /* Only used on wd->logical_touch */ - GdkWaylandPointerData *pointer; -}; - -struct _GdkWaylandDeviceClass -{ - GdkDeviceClass parent_class; -}; - -G_DEFINE_TYPE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) - -struct _GdkWaylandDevicePad -{ - GdkWaylandDevice parent_instance; -}; - -struct _GdkWaylandDevicePadClass -{ - GdkWaylandDeviceClass parent_class; -}; - -static void gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface); -static void init_pointer_data (GdkWaylandPointerData *pointer_data, - GdkDisplay *display_wayland, - GdkDevice *logical_device); -static void pointer_surface_update_scale (GdkDevice *device); - -#define GDK_TYPE_WAYLAND_DEVICE_PAD (gdk_wayland_device_pad_get_type ()) -GType gdk_wayland_device_pad_get_type (void); - -G_DEFINE_TYPE_WITH_CODE (GdkWaylandDevicePad, gdk_wayland_device_pad, - GDK_TYPE_WAYLAND_DEVICE, - G_IMPLEMENT_INTERFACE (GDK_TYPE_DEVICE_PAD, - gdk_wayland_device_pad_iface_init)) - -#define GDK_SLOT_TO_EVENT_SEQUENCE(s) ((GdkEventSequence *) GUINT_TO_POINTER((s) + 1)) -#define GDK_EVENT_SEQUENCE_TO_SLOT(s) (GPOINTER_TO_UINT(s) - 1) - -static void deliver_key_event (GdkWaylandSeat *seat, - uint32_t time_, - uint32_t key, - uint32_t state, - gboolean from_key_repeat); - -static void -gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer) -{ - if (pointer->cursor_timeout_id > 0) - { - g_source_remove (pointer->cursor_timeout_id); - pointer->cursor_timeout_id = 0; - pointer->cursor_image_delay = 0; - } - - pointer->cursor_image_index = 0; -} - -static GdkWaylandTabletData * -gdk_wayland_seat_find_tablet (GdkWaylandSeat *seat, - GdkDevice *device) -{ - GList *l; - - for (l = seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - - if (tablet->logical_device == device || - tablet->stylus_device == device) - return tablet; - } - - return NULL; -} - -static GdkWaylandTabletPadData * -gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, - GdkDevice *device) -{ - GList *l; - - for (l = seat->tablet_pads; l; l = l->next) - { - GdkWaylandTabletPadData *pad = l->data; - - if (pad->device == device) - return pad; - } - - return NULL; -} - - -static gboolean -gdk_wayland_device_update_surface_cursor (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; - struct wl_buffer *buffer; - int x, y, w, h, scale; - guint next_image_index, next_image_delay; - gboolean retval = G_SOURCE_REMOVE; - GdkWaylandTabletData *tablet; - - tablet = gdk_wayland_seat_find_tablet (seat, device); - - if (pointer->cursor) - { - buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display), - pointer->cursor, - pointer->current_output_scale, - pointer->cursor_image_index, - &x, &y, &w, &h, &scale); - } - else - { - pointer->cursor_timeout_id = 0; - return G_SOURCE_REMOVE; - } - - if (tablet) - { - if (!tablet->current_tool) - { - pointer->cursor_timeout_id = 0; - return G_SOURCE_REMOVE; - } - - zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool, - pointer->enter_serial, - pointer->pointer_surface, - x, y); - } - else if (seat->wl_pointer) - { - wl_pointer_set_cursor (seat->wl_pointer, - pointer->enter_serial, - pointer->pointer_surface, - x, y); - } - else - { - pointer->cursor_timeout_id = 0; - return G_SOURCE_REMOVE; - } - - if (buffer) - { - wl_surface_attach (pointer->pointer_surface, buffer, 0, 0); - wl_surface_set_buffer_scale (pointer->pointer_surface, scale); - wl_surface_damage (pointer->pointer_surface, 0, 0, w, h); - wl_surface_commit (pointer->pointer_surface); - } - else - { - wl_surface_attach (pointer->pointer_surface, NULL, 0, 0); - wl_surface_commit (pointer->pointer_surface); - } - - next_image_index = - _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display), - pointer->cursor, - pointer->current_output_scale, - pointer->cursor_image_index, - &next_image_delay); - - if (next_image_index != pointer->cursor_image_index) - { - if (next_image_delay != pointer->cursor_image_delay || - pointer->cursor_timeout_id == 0) - { - guint id; - GSource *source; - - gdk_wayland_pointer_stop_cursor_animation (pointer); - - /* Queue timeout for next frame */ - id = g_timeout_add (next_image_delay, - (GSourceFunc) gdk_wayland_device_update_surface_cursor, - device); - source = g_main_context_find_source_by_id (NULL, id); - g_source_set_static_name (source, "[gtk] gdk_wayland_device_update_surface_cursor"); - pointer->cursor_timeout_id = id; - } - else - retval = G_SOURCE_CONTINUE; - - pointer->cursor_image_index = next_image_index; - pointer->cursor_image_delay = next_image_delay; - } - else - gdk_wayland_pointer_stop_cursor_animation (pointer); - - return retval; -} - -static void -gdk_wayland_device_set_surface_cursor (GdkDevice *device, - GdkSurface *surface, - GdkCursor *cursor) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; - - if (device == seat->logical_touch) - return; - - if (seat->grab_cursor) - cursor = seat->grab_cursor; - - if (pointer->cursor != NULL && - cursor != NULL && - gdk_cursor_equal (cursor, pointer->cursor)) - return; - - if (cursor == NULL) - { - if (!pointer->cursor_is_default) - { - g_clear_object (&pointer->cursor); - pointer->cursor = gdk_cursor_new_from_name ("default", NULL); - pointer->cursor_is_default = TRUE; - - gdk_wayland_pointer_stop_cursor_animation (pointer); - gdk_wayland_device_update_surface_cursor (device); - } - else - { - /* Nothing to do, we'already using the default cursor */ - } - } - else - { - g_set_object (&pointer->cursor, cursor); - pointer->cursor_is_default = FALSE; - - gdk_wayland_pointer_stop_cursor_animation (pointer); - gdk_wayland_device_update_surface_cursor (device); - } -} - -static GdkModifierType -device_get_modifiers (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; - GdkModifierType mask; - - mask = seat->key_modifiers; - - if (pointer) - mask |= pointer->button_modifiers; - - return mask; -} - -void -gdk_wayland_device_query_state (GdkDevice *device, - GdkSurface *surface, - double *win_x, - double *win_y, - GdkModifierType *mask) -{ - GdkWaylandPointerData *pointer; - double x, y; - - if (mask) - *mask = device_get_modifiers (device); - - pointer = GDK_WAYLAND_DEVICE (device)->pointer; - - if (pointer->focus == surface) - { - x = pointer->surface_x; - y = pointer->surface_y; - } - else - { - x = y = -1; - } - - if (win_x) - *win_x = x; - if (win_y) - *win_y = y; -} - -static void -emulate_crossing (GdkSurface *surface, - GdkSurface *child_surface, - GdkDevice *device, - GdkEventType type, - GdkCrossingMode mode, - guint32 time_) -{ - GdkEvent *event; - GdkModifierType state; - double x, y; - - gdk_surface_get_device_position (surface, device, &x, &y, &state); - event = gdk_crossing_event_new (type, - surface, - device, - time_, - state, - x, y, - mode, - GDK_NOTIFY_NONLINEAR); - - _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); -} - -static void -emulate_touch_crossing (GdkSurface *surface, - GdkSurface *child_surface, - GdkDevice *device, - GdkDevice *source, - GdkWaylandTouchData *touch, - GdkEventType type, - GdkCrossingMode mode, - guint32 time_) -{ - GdkEvent *event; - - event = gdk_crossing_event_new (type, - surface, - device, - time_, - 0, - touch->x, touch->y, - mode, - GDK_NOTIFY_NONLINEAR); - - _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); -} - -static void -emulate_focus (GdkSurface *surface, - GdkDevice *device, - gboolean focus_in, - guint32 time_) -{ - GdkEvent *event = gdk_focus_event_new (surface, device, focus_in); - - _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); -} - -static void -device_emit_grab_crossing (GdkDevice *device, - GdkSurface *from, - GdkSurface *to, - GdkCrossingMode mode, - guint32 time_) -{ - if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) - { - if (from) - emulate_focus (from, device, FALSE, time_); - if (to) - emulate_focus (to, device, TRUE, time_); - } - else - { - if (from) - emulate_crossing (from, to, device, GDK_LEAVE_NOTIFY, mode, time_); - if (to) - emulate_crossing (to, from, device, GDK_ENTER_NOTIFY, mode, time_); - } -} - -GdkSurface * -gdk_wayland_device_get_focus (GdkDevice *device) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer; - - if (device == wayland_seat->logical_keyboard) - return wayland_seat->keyboard_focus; - else - { - pointer = GDK_WAYLAND_DEVICE (device)->pointer; - - if (pointer) - return pointer->focus; - } - - return NULL; -} - -static void -device_maybe_emit_grab_crossing (GdkDevice *device, - GdkSurface *window, - guint32 time) -{ - GdkSurface *surface = gdk_wayland_device_get_focus (device); - GdkSurface *focus = window; - - if (focus != surface) - device_emit_grab_crossing (device, focus, window, GDK_CROSSING_GRAB, time); -} - -static GdkSurface* -device_maybe_emit_ungrab_crossing (GdkDevice *device, - guint32 time_) -{ - GdkDeviceGrabInfo *grab; - GdkSurface *focus = NULL; - GdkSurface *surface = NULL; - GdkSurface *prev_focus = NULL; - - focus = gdk_wayland_device_get_focus (device); - grab = _gdk_display_get_last_device_grab (gdk_device_get_display (device), device); - - if (grab) - { - prev_focus = grab->surface; - surface = grab->surface; - } - - if (focus != surface) - device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time_); - - return prev_focus; -} - -static GdkGrabStatus -gdk_wayland_device_grab (GdkDevice *device, - GdkSurface *surface, - gboolean owner_events, - GdkEventMask event_mask, - GdkSurface *confine_to, - GdkCursor *cursor, - guint32 time_) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; - - if (GDK_IS_DRAG_SURFACE (surface) && - gdk_surface_get_mapped (surface)) - { - g_warning ("Surface %p is already mapped at the time of grabbing. " - "gdk_seat_grab() should be used to simultaneously grab input " - "and show this popup. You may find oddities ahead.", - surface); - } - - device_maybe_emit_grab_crossing (device, surface, time_); - - if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) - { - /* Device is a keyboard */ - gdk_wayland_surface_inhibit_shortcuts (surface, - gdk_device_get_seat (device)); - return GDK_GRAB_SUCCESS; - } - else - { - /* Device is a pointer */ - if (pointer->grab_surface != NULL && - time_ != 0 && pointer->grab_time > time_) - { - return GDK_GRAB_ALREADY_GRABBED; - } - - if (time_ == 0) - time_ = pointer->time; - - pointer->grab_surface = surface; - pointer->grab_time = time_; - _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (wayland_seat)); - - g_clear_object (&wayland_seat->cursor); - - if (cursor) - wayland_seat->cursor = g_object_ref (cursor); - - gdk_wayland_device_update_surface_cursor (device); - } - - return GDK_GRAB_SUCCESS; -} - -static void -gdk_wayland_device_ungrab (GdkDevice *device, - guint32 time_) -{ - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; - GdkSurface *prev_focus; - - prev_focus = device_maybe_emit_ungrab_crossing (device, time_); - - if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) - { - /* Device is a keyboard */ - if (prev_focus) - gdk_wayland_surface_restore_shortcuts (prev_focus, - gdk_device_get_seat (device)); - } - else - { - /* Device is a pointer */ - gdk_wayland_device_update_surface_cursor (device); - - if (pointer->grab_surface) - _gdk_wayland_surface_set_grab_seat (pointer->grab_surface, - NULL); - } -} - -static GdkSurface * -gdk_wayland_device_surface_at_position (GdkDevice *device, - double *win_x, - double *win_y, - GdkModifierType *mask) -{ - GdkWaylandPointerData *pointer; - - pointer = GDK_WAYLAND_DEVICE(device)->pointer; - - if (!pointer) - return NULL; - - if (win_x) - *win_x = pointer->surface_x; - if (win_y) - *win_y = pointer->surface_y; - if (mask) - *mask = device_get_modifiers (device); - - return pointer->focus; -} - -static void -gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass) -{ - GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass); - - device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor; - device_class->grab = gdk_wayland_device_grab; - device_class->ungrab = gdk_wayland_device_ungrab; - device_class->surface_at_position = gdk_wayland_device_surface_at_position; -} - -static void -gdk_wayland_device_init (GdkWaylandDevice *device_core) -{ - GdkDevice *device; - - device = GDK_DEVICE (device_core); - - _gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1); - _gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1); -} - -static int -gdk_wayland_device_pad_get_n_groups (GdkDevicePad *pad) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadData *data; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); -#ifdef G_DISABLE_ASSERT - if (data == NULL) - return 0; -#else - g_assert (data != NULL); -#endif - - return g_list_length (data->mode_groups); -} - -static int -gdk_wayland_device_pad_get_group_n_modes (GdkDevicePad *pad, - int n_group) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadGroupData *group; - GdkWaylandTabletPadData *data; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); -#ifdef G_DISABLE_ASSERT - if (data == NULL) - return 0; -#else - g_assert (data != NULL); -#endif - - group = g_list_nth_data (data->mode_groups, n_group); - if (!group) - return -1; - - return group->n_modes; -} - -static int -gdk_wayland_device_pad_get_n_features (GdkDevicePad *pad, - GdkDevicePadFeature feature) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadData *data; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); - g_assert (data != NULL); - - switch (feature) - { - case GDK_DEVICE_PAD_FEATURE_BUTTON: - return data->n_buttons; - case GDK_DEVICE_PAD_FEATURE_RING: - return g_list_length (data->rings); - case GDK_DEVICE_PAD_FEATURE_STRIP: - return g_list_length (data->strips); - default: - return -1; - } -} - -static int -gdk_wayland_device_pad_get_feature_group (GdkDevicePad *pad, - GdkDevicePadFeature feature, - int idx) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadGroupData *group; - GdkWaylandTabletPadData *data; - GList *l; - int i; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); -#ifdef G_DISABLE_ASSERT - if (data == NULL) - return -1; -#else - g_assert (data != NULL); -#endif - - for (l = data->mode_groups, i = 0; l; l = l->next, i++) - { - group = l->data; - - switch (feature) - { - case GDK_DEVICE_PAD_FEATURE_BUTTON: - if (g_list_find (group->buttons, GINT_TO_POINTER (idx))) - return i; - break; - case GDK_DEVICE_PAD_FEATURE_RING: - { - gpointer ring; - - ring = g_list_nth_data (data->rings, idx); - if (ring && g_list_find (group->rings, ring)) - return i; - break; - } - case GDK_DEVICE_PAD_FEATURE_STRIP: - { - gpointer strip; - strip = g_list_nth_data (data->strips, idx); - if (strip && g_list_find (group->strips, strip)) - return i; - break; - } - default: - break; - } - } - - return -1; -} - -static void -gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface) -{ - iface->get_n_groups = gdk_wayland_device_pad_get_n_groups; - iface->get_group_n_modes = gdk_wayland_device_pad_get_group_n_modes; - iface->get_n_features = gdk_wayland_device_pad_get_n_features; - iface->get_feature_group = gdk_wayland_device_pad_get_feature_group; -} - -static void -gdk_wayland_device_pad_class_init (GdkWaylandDevicePadClass *klass) -{ -} - -static void -gdk_wayland_device_pad_init (GdkWaylandDevicePad *pad) -{ -} - -/** - * gdk_wayland_device_get_wl_seat: (skip) - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_seat` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_seat` - */ -struct wl_seat * -gdk_wayland_device_get_wl_seat (GdkDevice *device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->wl_seat; -} - -/** - * gdk_wayland_device_get_wl_pointer: (skip) - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_pointer` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_pointer` - */ -struct wl_pointer * -gdk_wayland_device_get_wl_pointer (GdkDevice *device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->wl_pointer; -} - -/** - * gdk_wayland_device_get_wl_keyboard: (skip) - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_keyboard` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_keyboard` - */ -struct wl_keyboard * -gdk_wayland_device_get_wl_keyboard (GdkDevice *device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->wl_keyboard; -} - -/** - * gdk_wayland_device_get_xkb_keymap: - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the `xkb_keymap` of a `GdkDevice`. - * - * Returns: (transfer none): a `struct xkb_keymap` - * - * Since: 4.4 - */ -struct xkb_keymap * -gdk_wayland_device_get_xkb_keymap (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return _gdk_wayland_keymap_get_xkb_keymap (seat->keymap); -} - -GdkKeymap * -_gdk_wayland_device_get_keymap (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->keymap; -} - -static void -gdk_wayland_seat_discard_pending_offer (GdkWaylandSeat *seat) -{ - if (seat->pending_builder) - { - GdkContentFormats *ignore = gdk_content_formats_builder_free_to_formats (seat->pending_builder); - gdk_content_formats_unref (ignore); - seat->pending_builder = NULL; - } - g_clear_pointer (&seat->pending_offer, wl_data_offer_destroy); - seat->pending_source_actions = 0; - seat->pending_action = 0; -} - -static inline GdkDragAction -gdk_wayland_actions_to_gdk_actions (uint32_t dnd_actions) -{ - GdkDragAction actions = 0; - - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) - actions |= GDK_ACTION_COPY; - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) - actions |= GDK_ACTION_MOVE; - if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) - actions |= GDK_ACTION_ASK; - - return actions; -} - -static void -data_offer_offer (void *data, - struct wl_data_offer *offer, - const char *type) -{ - GdkWaylandSeat *seat = data; - - if (seat->pending_offer != offer) - { - GDK_SEAT_DEBUG (seat, EVENTS, - "%p: offer for unknown offer %p of %s", - seat, offer, type); - return; - } - - /* skip magic mime types */ - if (g_str_equal (type, GDK_WAYLAND_LOCAL_DND_MIME_TYPE)) - return; - - gdk_content_formats_builder_add_mime_type (seat->pending_builder, type); -} - -static void -data_offer_source_actions (void *data, - struct wl_data_offer *offer, - uint32_t source_actions) -{ - GdkWaylandSeat *seat = data; - - if (offer == seat->pending_offer) - { - seat->pending_source_actions = gdk_wayland_actions_to_gdk_actions (source_actions); - return; - } - - if (seat->drop == NULL) - return; - - gdk_wayland_drop_set_source_actions (seat->drop, source_actions); - - gdk_drop_emit_motion_event (seat->drop, - FALSE, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - GDK_CURRENT_TIME); -} - -static void -data_offer_action (void *data, - struct wl_data_offer *offer, - uint32_t action) -{ - GdkWaylandSeat *seat = data; - - if (offer == seat->pending_offer) - { - seat->pending_action = gdk_wayland_actions_to_gdk_actions (action); - return; - } - - if (seat->drop == NULL) - return; - - gdk_wayland_drop_set_action (seat->drop, action); - - gdk_drop_emit_motion_event (seat->drop, - FALSE, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - GDK_CURRENT_TIME); -} - -static const struct wl_data_offer_listener data_offer_listener = { - data_offer_offer, - data_offer_source_actions, - data_offer_action -}; - -static void -data_device_data_offer (void *data, - struct wl_data_device *data_device, - struct wl_data_offer *offer) -{ - GdkWaylandSeat *seat = data; - - GDK_SEAT_DEBUG (seat, EVENTS, - "data device data offer, data device %p, offer %p", - data_device, offer); - - gdk_wayland_seat_discard_pending_offer (seat); - - seat->pending_offer = offer; - wl_data_offer_add_listener (offer, - &data_offer_listener, - seat); - - seat->pending_builder = gdk_content_formats_builder_new (); - seat->pending_source_actions = 0; - seat->pending_action = 0; -} - -static void -data_device_enter (void *data, - struct wl_data_device *data_device, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t x, - wl_fixed_t y, - struct wl_data_offer *offer) -{ - GdkWaylandSeat *seat = data; - GdkSurface *dest_surface; - GdkContentFormats *formats; - int origin_x, origin_y; - GdkDevice *device; - - dest_surface = wl_surface_get_user_data (surface); - - if (!GDK_IS_SURFACE (dest_surface)) - return; - - if (offer != seat->pending_offer) - { - GDK_SEAT_DEBUG (seat, EVENTS, - "%p: enter event for unknown offer %p, expected %p", - seat, offer, seat->pending_offer); - return; - } - - GDK_SEAT_DEBUG (seat, EVENTS, - "data device enter, data device %p serial %u, surface %p, x %f y %f, offer %p", - data_device, serial, surface, wl_fixed_to_double (x), wl_fixed_to_double (y), offer); - - /* Update pointer state, so device state queries work during DnD */ - seat->pointer_info.focus = g_object_ref (dest_surface); - seat->pointer_info.surface_x = wl_fixed_to_double (x); - seat->pointer_info.surface_y = wl_fixed_to_double (y); - - if (seat->logical_pointer) - device = seat->logical_pointer; - else if (seat->logical_touch) - device = seat->logical_touch; - else - { - g_warning ("No device for DND enter, ignoring."); - return; - } - - formats = gdk_content_formats_builder_free_to_formats (seat->pending_builder); - seat->pending_builder = NULL; - seat->pending_offer = NULL; - - seat->drop = gdk_wayland_drop_new (device, seat->drag, formats, dest_surface, offer, serial); - gdk_wayland_drop_set_source_actions (seat->drop, seat->pending_source_actions); - gdk_wayland_drop_set_action (seat->drop, seat->pending_action); - - gdk_content_formats_unref (formats); - - gdk_wayland_seat_discard_pending_offer (seat); - - gdk_surface_get_origin (gdk_drop_get_surface (seat->drop), &origin_x, &origin_y); - - gdk_drop_emit_enter_event (seat->drop, - FALSE, - origin_x + seat->pointer_info.surface_x, - origin_y + seat->pointer_info.surface_y, - GDK_CURRENT_TIME); -} - -static void -data_device_leave (void *data, - struct wl_data_device *data_device) -{ - GdkWaylandSeat *seat = data; - - GDK_SEAT_DEBUG (seat, EVENTS, - "data device leave, data device %p", data_device); - - if (seat->drop == NULL) - return; - - g_object_unref (seat->pointer_info.focus); - seat->pointer_info.focus = NULL; - - gdk_drop_emit_leave_event (seat->drop, - FALSE, - GDK_CURRENT_TIME); - - g_clear_object (&seat->drop); -} - -static void -data_device_motion (void *data, - struct wl_data_device *data_device, - uint32_t time, - wl_fixed_t x, - wl_fixed_t y) -{ - GdkWaylandSeat *seat = data; - int origin_x, origin_y; - - GDK_SEAT_DEBUG (seat, EVENTS, - "data device motion, data_device = %p, time = %d, x = %f, y = %f", - data_device, time, wl_fixed_to_double (x), wl_fixed_to_double (y)); - - if (seat->drop == NULL) - return; - - /* Update pointer state, so device state queries work during DnD */ - seat->pointer_info.surface_x = wl_fixed_to_double (x); - seat->pointer_info.surface_y = wl_fixed_to_double (y); - - gdk_surface_get_origin (gdk_drop_get_surface (seat->drop), &origin_x, &origin_y); - - gdk_drop_emit_motion_event (seat->drop, - FALSE, - origin_x + seat->pointer_info.surface_x, - origin_y + seat->pointer_info.surface_y, - time); -} - -static void -data_device_drop (void *data, - struct wl_data_device *data_device) -{ - GdkWaylandSeat *seat = data; - int origin_x, origin_y; - - GDK_SEAT_DEBUG (seat, EVENTS, - "data device drop, data device %p", data_device); - - gdk_surface_get_origin (gdk_drop_get_surface (seat->drop), &origin_x, &origin_y); - - gdk_drop_emit_drop_event (seat->drop, - FALSE, - origin_x + seat->pointer_info.surface_x, - origin_y + seat->pointer_info.surface_y, - GDK_CURRENT_TIME); -} - -static void -data_device_selection (void *data, - struct wl_data_device *wl_data_device, - struct wl_data_offer *offer) -{ - GdkWaylandSeat *seat = data; - GdkContentFormats *formats; - - if (offer) - { - if (offer == seat->pending_offer) - { - formats = gdk_content_formats_builder_free_to_formats (seat->pending_builder); - seat->pending_builder = NULL; - seat->pending_offer = NULL; - } - else - { - formats = gdk_content_formats_new (NULL, 0); - offer = NULL; - } - - gdk_wayland_seat_discard_pending_offer (seat); - } - else - { - formats = gdk_content_formats_new (NULL, 0); - } - - gdk_wayland_clipboard_claim_remote (GDK_WAYLAND_CLIPBOARD (seat->clipboard), - offer, - formats); -} - -static const struct wl_data_device_listener data_device_listener = { - data_device_data_offer, - data_device_enter, - data_device_leave, - data_device_motion, - data_device_drop, - data_device_selection -}; - -static GdkDevice * get_scroll_device (GdkWaylandSeat *seat, - enum wl_pointer_axis_source source); - -static void -flush_discrete_scroll_event (GdkWaylandSeat *seat, - gint value120_x, - gint value120_y) -{ - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); - GdkEvent *event = NULL; - GdkDevice *source; - GdkScrollDirection direction; - - if (value120_x > 0) - direction = GDK_SCROLL_LEFT; - else if (value120_x < 0) - direction = GDK_SCROLL_RIGHT; - else if (value120_y > 0) - direction = GDK_SCROLL_DOWN; - else - direction = GDK_SCROLL_UP; - - source = get_scroll_device (seat, seat->pointer_info.frame.source); - - if (display_wayland->seat_version >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION) - { - event = gdk_scroll_event_new_value120 (seat->pointer_info.focus, - source, - NULL, - seat->pointer_info.time, - device_get_modifiers (seat->logical_pointer), - direction, - value120_x, - value120_y); - } - else - { - gint discrete_x = value120_x / 120; - gint discrete_y = value120_y / 120; - - if (discrete_x != 0 || discrete_y != 0) - { - event = gdk_scroll_event_new_discrete (seat->pointer_info.focus, - source, - NULL, - seat->pointer_info.time, - device_get_modifiers (seat->logical_pointer), - direction); - } - } - - if (event) - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -flush_smooth_scroll_event (GdkWaylandSeat *seat, - double delta_x, - double delta_y, - gboolean is_stop) -{ - GdkEvent *event; - GdkDevice *source; - - source = get_scroll_device (seat, seat->pointer_info.frame.source); - event = gdk_scroll_event_new (seat->pointer_info.focus, - source, - NULL, - seat->pointer_info.time, - device_get_modifiers (seat->logical_pointer), - delta_x, delta_y, - is_stop, - GDK_SCROLL_UNIT_SURFACE); - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -flush_scroll_event (GdkWaylandSeat *seat, - GdkWaylandPointerFrameData *pointer_frame) -{ - gboolean is_stop = FALSE; - - if (pointer_frame->value120_x || pointer_frame->value120_y) - { - flush_discrete_scroll_event (seat, - pointer_frame->value120_x, - pointer_frame->value120_y); - pointer_frame->value120_x = 0; - pointer_frame->value120_y = 0; - } - else if (pointer_frame->is_scroll_stop || - pointer_frame->delta_x != 0 || - pointer_frame->delta_y != 0) - { - /* Axes can stop independently, if we stop on one axis but have a - * delta on the other, we don't count it as a stop event. - */ - if (pointer_frame->is_scroll_stop && - pointer_frame->delta_x == 0 && - pointer_frame->delta_y == 0) - is_stop = TRUE; - - flush_smooth_scroll_event (seat, - pointer_frame->delta_x, - pointer_frame->delta_y, - is_stop); - } - - pointer_frame->value120_x = 0; - pointer_frame->value120_y = 0; - pointer_frame->delta_x = 0; - pointer_frame->delta_y = 0; - pointer_frame->is_scroll_stop = FALSE; -} - -static void -gdk_wayland_seat_flush_frame_event (GdkWaylandSeat *seat) -{ - if (seat->pointer_info.frame.event) - { - _gdk_wayland_display_deliver_event (gdk_seat_get_display (GDK_SEAT (seat)), - seat->pointer_info.frame.event); - seat->pointer_info.frame.event = NULL; - } - else - { - flush_scroll_event (seat, &seat->pointer_info.frame); - seat->pointer_info.frame.source = 0; - } -} - -static void -gdk_wayland_seat_set_frame_event (GdkWaylandSeat *seat, - GdkEvent *event) -{ - if (seat->pointer_info.frame.event && - gdk_event_get_event_type (seat->pointer_info.frame.event) != gdk_event_get_event_type (event)) - gdk_wayland_seat_flush_frame_event (seat); - - seat->pointer_info.frame.event = event; -} - -static void -pointer_handle_enter (void *data, - struct wl_pointer *pointer, - uint32_t serial, - struct wl_surface *surface, - wl_fixed_t sx, - wl_fixed_t sy) -{ - GdkWaylandSeat *seat = data; - GdkEvent *event; - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); - - if (!surface) - return; - - if (!GDK_IS_SURFACE (wl_surface_get_user_data (surface))) - return; - - seat->pointer_info.focus = wl_surface_get_user_data (surface); - g_object_ref (seat->pointer_info.focus); - - seat->pointer_info.button_modifiers = 0; - - seat->pointer_info.surface_x = wl_fixed_to_double (sx); - seat->pointer_info.surface_y = wl_fixed_to_double (sy); - seat->pointer_info.enter_serial = serial; - - event = gdk_crossing_event_new (GDK_ENTER_NOTIFY, - seat->pointer_info.focus, - seat->logical_pointer, - 0, - 0, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - GDK_CROSSING_NORMAL, - GDK_NOTIFY_NONLINEAR); - gdk_wayland_seat_set_frame_event (seat, event); - - gdk_wayland_device_update_surface_cursor (seat->logical_pointer); - - GDK_SEAT_DEBUG (seat, EVENTS, - "enter, seat %p surface %p", - seat, seat->pointer_info.focus); - - if (display_wayland->seat_version < WL_POINTER_HAS_FRAME) - gdk_wayland_seat_flush_frame_event (seat); -} - -static void -pointer_handle_leave (void *data, - struct wl_pointer *pointer, - uint32_t serial, - struct wl_surface *surface) -{ - GdkWaylandSeat *seat = data; - GdkEvent *event; - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); - GdkDeviceGrabInfo *grab; - - if (!seat->pointer_info.focus) - return; - - grab = _gdk_display_get_last_device_grab (seat->display, - seat->logical_pointer); - - if (seat->pointer_info.button_modifiers != 0 && - grab && grab->implicit) - { - gulong display_serial; - - display_serial = _gdk_display_get_next_serial (seat->display); - _gdk_display_end_device_grab (seat->display, seat->logical_pointer, - display_serial, NULL, TRUE); - _gdk_display_device_grab_update (seat->display, - seat->logical_pointer, - display_serial); - } - - event = gdk_crossing_event_new (GDK_LEAVE_NOTIFY, - seat->pointer_info.focus, - seat->logical_pointer, - 0, - 0, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - GDK_CROSSING_NORMAL, - GDK_NOTIFY_NONLINEAR); - gdk_wayland_seat_set_frame_event (seat, event); - - gdk_wayland_device_update_surface_cursor (seat->logical_pointer); - - GDK_SEAT_DEBUG (seat, EVENTS, - "leave, seat %p surface %p", - seat, seat->pointer_info.focus); - - g_object_unref (seat->pointer_info.focus); - seat->pointer_info.focus = NULL; - if (seat->cursor) - gdk_wayland_pointer_stop_cursor_animation (&seat->pointer_info); - - if (display_wayland->seat_version < WL_POINTER_HAS_FRAME) - gdk_wayland_seat_flush_frame_event (seat); -} - -static void -pointer_handle_motion (void *data, - struct wl_pointer *pointer, - uint32_t time, - wl_fixed_t sx, - wl_fixed_t sy) -{ - GdkWaylandSeat *seat = data; - GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); - GdkEvent *event; - - if (!seat->pointer_info.focus) - return; - - seat->pointer_info.time = time; - seat->pointer_info.surface_x = wl_fixed_to_double (sx); - seat->pointer_info.surface_y = wl_fixed_to_double (sy); - - event = gdk_motion_event_new (seat->pointer_info.focus, - seat->logical_pointer, - NULL, - time, - device_get_modifiers (seat->logical_pointer), - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - NULL); - gdk_wayland_seat_set_frame_event (seat, event); - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double x, y; - gdk_event_get_position (event, &x, &y); - g_message ("motion %f %f, seat %p state %d", - x, y, seat, gdk_event_get_modifier_state (event)); - } - - if (display->seat_version < WL_POINTER_HAS_FRAME) - gdk_wayland_seat_flush_frame_event (seat); -} - -static void -pointer_handle_button (void *data, - struct wl_pointer *pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - GdkWaylandSeat *seat = data; - GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); - GdkEvent *event; - uint32_t modifier; - int gdk_button; - - if (!seat->pointer_info.focus) - return; - - switch (button) - { - case BTN_LEFT: - gdk_button = GDK_BUTTON_PRIMARY; - break; - case BTN_MIDDLE: - gdk_button = GDK_BUTTON_MIDDLE; - break; - case BTN_RIGHT: - gdk_button = GDK_BUTTON_SECONDARY; - break; - default: - /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */ - gdk_button = button - BUTTON_BASE + 4; - break; - } - - seat->pointer_info.time = time; - if (state) - seat->pointer_info.press_serial = serial; - - event = gdk_button_event_new (state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE, - seat->pointer_info.focus, - seat->logical_pointer, - NULL, - time, - device_get_modifiers (seat->logical_pointer), - gdk_button, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - NULL); - - gdk_wayland_seat_set_frame_event (seat, event); - - switch (button) - { - case BTN_RIGHT: - modifier = GDK_BUTTON3_MASK; - break; - case BTN_MIDDLE: - modifier = GDK_BUTTON2_MASK; - break; - default: - modifier = (GDK_BUTTON1_MASK << (button - BUTTON_BASE - 1)) & ALL_BUTTONS_MASK; - break; - } - - if (state) - seat->pointer_info.button_modifiers |= modifier; - else - seat->pointer_info.button_modifiers &= ~modifier; - - GDK_SEAT_DEBUG (seat, EVENTS, - "button %d %s, seat %p state %d", - gdk_button_event_get_button (event), - state ? "press" : "release", - seat, - gdk_event_get_modifier_state (event)); - - if (display->seat_version < WL_POINTER_HAS_FRAME) - gdk_wayland_seat_flush_frame_event (seat); -} - -#ifdef G_ENABLE_DEBUG - -static const char * -get_axis_name (uint32_t axis) -{ - switch (axis) - { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - return "horizontal"; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - return "vertical"; - default: - return "unknown"; - } -} - -#endif - -static void -pointer_handle_axis (void *data, - struct wl_pointer *pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) -{ - GdkWaylandSeat *seat = data; - GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; - GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); - - if (!seat->pointer_info.focus) - return; - - /* get the delta and convert it into the expected range */ - switch (axis) - { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - pointer_frame->delta_y = wl_fixed_to_double (value); - break; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - pointer_frame->delta_x = wl_fixed_to_double (value); - break; - default: - g_return_if_reached (); - } - - seat->pointer_info.time = time; - - GDK_SEAT_DEBUG (seat, EVENTS, - "scroll, axis %s, value %f, seat %p", - get_axis_name (axis), wl_fixed_to_double (value), - seat); - - if (display->seat_version < WL_POINTER_HAS_FRAME) - gdk_wayland_seat_flush_frame_event (seat); -} - -static void -pointer_handle_frame (void *data, - struct wl_pointer *pointer) -{ - GdkWaylandSeat *seat = data; - - GDK_SEAT_DEBUG (seat, EVENTS, "frame, seat %p", seat); - - gdk_wayland_seat_flush_frame_event (seat); -} - -#ifdef G_ENABLE_DEBUG - -static const char * -get_axis_source_name (enum wl_pointer_axis_source source) -{ - switch (source) - { - case WL_POINTER_AXIS_SOURCE_WHEEL: - return "wheel"; - case WL_POINTER_AXIS_SOURCE_FINGER: - return "finger"; - case WL_POINTER_AXIS_SOURCE_CONTINUOUS: - return "continuous"; - case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: - return "wheel-tilt"; - default: - return "unknown"; - } -} - -#endif - -static void -pointer_handle_axis_source (void *data, - struct wl_pointer *pointer, - enum wl_pointer_axis_source source) -{ - GdkWaylandSeat *seat = data; - GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; - - if (!seat->pointer_info.focus) - return; - - pointer_frame->source = source; - - GDK_SEAT_DEBUG (seat, EVENTS, - "axis source %s, seat %p", get_axis_source_name (source), seat); -} - -static void -pointer_handle_axis_stop (void *data, - struct wl_pointer *pointer, - uint32_t time, - uint32_t axis) -{ - GdkWaylandSeat *seat = data; - GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; - - if (!seat->pointer_info.focus) - return; - - seat->pointer_info.time = time; - - switch (axis) - { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - pointer_frame->delta_y = 0; - break; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - pointer_frame->delta_x = 0; - break; - default: - g_return_if_reached (); - } - - pointer_frame->is_scroll_stop = TRUE; - - GDK_SEAT_DEBUG (seat, EVENTS, - "axis %s stop, seat %p", get_axis_name (axis), seat); -} - -static void -pointer_handle_axis_discrete (void *data, - struct wl_pointer *pointer, - uint32_t axis, - int32_t value) -{ - GdkWaylandSeat *seat = data; - GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; - - if (!seat->pointer_info.focus) - return; - - switch (axis) - { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - pointer_frame->value120_y = value * 120; - break; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - pointer_frame->value120_x = value * 120; - break; - default: - g_return_if_reached (); - } - - GDK_SEAT_DEBUG (seat, EVENTS, - "discrete scroll, axis %s, value %d, seat %p", - get_axis_name (axis), value, seat); -} - -static void -pointer_handle_axis_value120 (void *data, - struct wl_pointer *pointer, - uint32_t axis, - int32_t value) -{ - GdkWaylandSeat *seat = data; - GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; - - if (!seat->pointer_info.focus) - return; - - switch (axis) - { - case WL_POINTER_AXIS_VERTICAL_SCROLL: - pointer_frame->value120_y = value; - break; - case WL_POINTER_AXIS_HORIZONTAL_SCROLL: - pointer_frame->value120_x = value; - break; - default: - g_return_if_reached (); - } - - GDK_SEAT_DEBUG (seat, EVENTS, - "value120 scroll, axis %s, value %d, seat %p", - get_axis_name (axis), value, seat); -} - -static int -get_active_layout (GdkKeymap *keymap) -{ - struct xkb_keymap *xkb_keymap; - struct xkb_state *xkb_state; - - xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap); - xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); - - for (int i = 0; i < xkb_keymap_num_layouts (xkb_keymap); i++) - { - if (xkb_state_layout_index_is_active (xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) - return i; - } - - return -1; -} - -#ifdef G_ENABLE_DEBUG -static const char * -get_active_layout_name (GdkKeymap *keymap) -{ - struct xkb_keymap *xkb_keymap; - - xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap); - - return xkb_keymap_layout_get_name (xkb_keymap, get_active_layout (keymap)); -} -#endif - -static void -keyboard_handle_keymap (void *data, - struct wl_keyboard *keyboard, - uint32_t format, - int fd, - uint32_t size) -{ - GdkWaylandSeat *seat = data; - PangoDirection direction; - gboolean bidi; - gboolean caps_lock; - gboolean num_lock; - gboolean scroll_lock; - GdkModifierType modifiers; - - direction = gdk_keymap_get_direction (seat->keymap); - bidi = gdk_keymap_have_bidi_layouts (seat->keymap); - caps_lock = gdk_keymap_get_caps_lock_state (seat->keymap); - num_lock = gdk_keymap_get_num_lock_state (seat->keymap); - scroll_lock = gdk_keymap_get_scroll_lock_state (seat->keymap); - modifiers = gdk_keymap_get_modifier_state (seat->keymap); - - _gdk_wayland_keymap_update_from_fd (seat->keymap, format, fd, size); - -#ifdef G_ENABLE_DEBUG - if (GDK_DISPLAY_DEBUG_CHECK (seat->keymap->display, INPUT)) - { - GString *s = g_string_new (""); - struct xkb_keymap *xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (seat->keymap); - struct xkb_state *xkb_state = _gdk_wayland_keymap_get_xkb_state (seat->keymap); - for (int i = 0; i < xkb_keymap_num_layouts (xkb_keymap); i++) - { - if (s->len > 0) - g_string_append (s, ", "); - if (xkb_state_layout_index_is_active (xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) - g_string_append (s, "*"); - g_string_append (s, xkb_keymap_layout_get_name (xkb_keymap, i)); - } - gdk_debug_message ("layouts: %s", s->str); - g_string_free (s, TRUE); - } -#endif - - g_signal_emit_by_name (seat->keymap, "keys-changed"); - g_signal_emit_by_name (seat->keymap, "state-changed"); - if (direction != gdk_keymap_get_direction (seat->keymap)) - g_signal_emit_by_name (seat->keymap, "direction-changed"); - - if (direction != gdk_keymap_get_direction (seat->keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "direction"); - if (bidi != gdk_keymap_have_bidi_layouts (seat->keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "has-bidi-layouts"); - if (caps_lock != gdk_keymap_get_caps_lock_state (seat->keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "caps-lock-state"); - if (num_lock != gdk_keymap_get_num_lock_state (seat->keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "num-lock-state"); - if (scroll_lock != gdk_keymap_get_scroll_lock_state (seat->keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "scroll-lock-state"); - if (modifiers != gdk_keymap_get_modifier_state (seat->keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "modifier-state"); -} - -static void -keyboard_handle_enter (void *data, - struct wl_keyboard *keyboard, - uint32_t serial, - struct wl_surface *surface, - struct wl_array *keys) -{ - GdkWaylandSeat *seat = data; - GdkEvent *event; - - if (!surface) - return; - - if (!GDK_IS_SURFACE (wl_surface_get_user_data (surface))) - return; - - seat->keyboard_focus = wl_surface_get_user_data (surface); - g_object_ref (seat->keyboard_focus); - seat->repeat_key = 0; - - event = gdk_focus_event_new (seat->keyboard_focus, - seat->logical_keyboard, - TRUE); - - GDK_SEAT_DEBUG (seat, EVENTS, - "focus in, seat %p surface %p", - seat, seat->keyboard_focus); - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void stop_key_repeat (GdkWaylandSeat *seat); - -static void -keyboard_handle_leave (void *data, - struct wl_keyboard *keyboard, - uint32_t serial, - struct wl_surface *surface) -{ - GdkWaylandSeat *seat = data; - GdkEvent *event; - - if (!seat->keyboard_focus) - return; - - /* gdk_surface_is_destroyed() might already return TRUE for - * seat->keyboard_focus here, which would happen if we destroyed the - * surface before losing keyboard focus. - */ - stop_key_repeat (seat); - - event = gdk_focus_event_new (seat->keyboard_focus, - seat->logical_keyboard, - FALSE); - - g_object_unref (seat->keyboard_focus); - seat->keyboard_focus = NULL; - seat->repeat_key = 0; - seat->key_modifiers = 0; - - GDK_SEAT_DEBUG (seat, EVENTS, - "focus out, seat %p surface %p", - seat, gdk_event_get_surface (event)); - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static gboolean keyboard_repeat (gpointer data); - -static gboolean -get_key_repeat (GdkWaylandSeat *seat, - guint *delay, - guint *interval) -{ - gboolean repeat; - - if (seat->have_server_repeat) - { - if (seat->server_repeat_rate > 0) - { - repeat = TRUE; - *delay = seat->server_repeat_delay; - *interval = (1000 / seat->server_repeat_rate); - } - else - { - repeat = FALSE; - } - } - else - { - repeat = TRUE; - *delay = 400; - *interval = 80; - } - - return repeat; -} - -static void -stop_key_repeat (GdkWaylandSeat *seat) -{ - if (seat->repeat_timer) - { - g_source_remove (seat->repeat_timer); - seat->repeat_timer = 0; - } - - g_clear_pointer (&seat->repeat_callback, wl_callback_destroy); -} - -static void -deliver_key_event (GdkWaylandSeat *seat, - uint32_t time_, - uint32_t key, - uint32_t state, - gboolean from_key_repeat) -{ - GdkEvent *event; - struct xkb_state *xkb_state; - struct xkb_keymap *xkb_keymap; - GdkKeymap *keymap; - guint delay, interval, timeout; - gint64 begin_time, now; - xkb_mod_mask_t consumed; - GdkTranslatedKey translated; - GdkTranslatedKey no_lock; - xkb_mod_mask_t modifiers; - xkb_mod_index_t caps_lock; - - begin_time = g_get_monotonic_time (); - - stop_key_repeat (seat); - - keymap = seat->keymap; - xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); - xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap); - - translated.keyval = xkb_state_key_get_one_sym (xkb_state, key); - modifiers = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); - consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (xkb_state, key, modifiers); - translated.consumed = gdk_wayland_keymap_get_gdk_modifiers (keymap, consumed); - translated.layout = xkb_state_key_get_layout (xkb_state, key); - translated.level = xkb_state_key_get_level (xkb_state, key, translated.layout); - - if (translated.keyval == XKB_KEY_NoSymbol) - return; - - seat->pointer_info.time = time_; - seat->key_modifiers = gdk_keymap_get_modifier_state (keymap); - - - modifiers = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); - caps_lock = xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS); - if (modifiers & (1 << caps_lock)) - { - struct xkb_state *tmp_state = xkb_state_new (xkb_keymap); - xkb_layout_index_t layout; - - modifiers &= ~(1 << caps_lock); - layout = xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - xkb_state_update_mask (tmp_state, modifiers, 0, 0, layout, 0, 0); - - no_lock.keyval = xkb_state_key_get_one_sym (tmp_state, key); - consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (tmp_state, key, modifiers); - no_lock.consumed = gdk_wayland_keymap_get_gdk_modifiers (keymap, consumed); - no_lock.layout = xkb_state_key_get_layout (tmp_state, key); - no_lock.level = xkb_state_key_get_level (tmp_state, key, no_lock.layout); - - xkb_state_unref (tmp_state); - } - else - { - no_lock = translated; - } - - event = gdk_key_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE, - seat->keyboard_focus, - seat->logical_keyboard, - time_, - key, - device_get_modifiers (seat->logical_pointer), - _gdk_wayland_keymap_key_is_modifier (keymap, key), - &translated, - &no_lock, - NULL); - - _gdk_wayland_display_deliver_event (seat->display, event); - - GDK_SEAT_DEBUG (seat, EVENTS, - "keyboard %s event%s, surface %p, code %d, sym %d, " - "mods 0x%x, consumed 0x%x, layout %d level %d", - (state ? "press" : "release"), - (from_key_repeat ? " (repeat)" : ""), - gdk_event_get_surface (event), - gdk_key_event_get_keycode (event), - gdk_key_event_get_keyval (event), - gdk_event_get_modifier_state (event), - gdk_key_event_get_consumed_modifiers (event), - gdk_key_event_get_layout (event), - gdk_key_event_get_level (event)); - - if (!xkb_keymap_key_repeats (xkb_keymap, key)) - return; - - if (!get_key_repeat (seat, &delay, &interval)) - return; - - if (!from_key_repeat) - { - if (state) /* Another key is pressed */ - { - seat->repeat_key = key; - } - else if (seat->repeat_key == key) /* Repeated key is released */ - { - seat->repeat_key = 0; - } - } - - if (!seat->repeat_key) - return; - - seat->repeat_count++; - - interval *= 1000L; - delay *= 1000L; - - now = g_get_monotonic_time (); - - if (seat->repeat_count == 1) - seat->repeat_deadline = begin_time + delay; - else if (seat->repeat_deadline + interval > now) - seat->repeat_deadline += interval; - else - /* frame delay caused us to miss repeat deadline */ - seat->repeat_deadline = now; - - timeout = (seat->repeat_deadline - now) / 1000L; - - seat->repeat_timer = g_timeout_add (timeout, keyboard_repeat, seat); - gdk_source_set_static_name_by_id (seat->repeat_timer, "[gtk] keyboard_repeat"); -} - -static void -sync_after_repeat_callback (void *data, - struct wl_callback *callback, - uint32_t time) -{ - GdkWaylandSeat *seat = data; - - g_clear_pointer (&seat->repeat_callback, wl_callback_destroy); - deliver_key_event (seat, seat->keyboard_time, seat->repeat_key, 1, TRUE); -} - -static const struct wl_callback_listener sync_after_repeat_callback_listener = { - sync_after_repeat_callback -}; - -static gboolean -keyboard_repeat (gpointer data) -{ - GdkWaylandSeat *seat = data; - GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); - - /* Ping the server and wait for the timeout. We won't process - * key repeat until it responds, since a hung server could lead - * to a delayed key release event. We don't want to generate - * repeat events long after the user released the key, just because - * the server is tardy in telling us the user released the key. - */ - seat->repeat_callback = wl_display_sync (display->wl_display); - - wl_callback_add_listener (seat->repeat_callback, - &sync_after_repeat_callback_listener, - seat); - - seat->repeat_timer = 0; - return G_SOURCE_REMOVE; -} - -static void -keyboard_handle_key (void *data, - struct wl_keyboard *keyboard, - uint32_t serial, - uint32_t time, - uint32_t key, - uint32_t state_w) -{ - GdkWaylandSeat *seat = data; - - if (!seat->keyboard_focus) - return; - - seat->keyboard_time = time; - seat->keyboard_key_serial = serial; - seat->repeat_count = 0; - deliver_key_event (data, time, key + 8, state_w, FALSE); - -} - -static void -keyboard_handle_modifiers (void *data, - struct wl_keyboard *keyboard, - uint32_t serial, - uint32_t mods_depressed, - uint32_t mods_latched, - uint32_t mods_locked, - uint32_t group) -{ - GdkWaylandSeat *seat = data; - GdkKeymap *keymap; - struct xkb_state *xkb_state; - PangoDirection direction; - gboolean bidi; - gboolean caps_lock; - gboolean num_lock; - gboolean scroll_lock; - GdkModifierType modifiers; - int layout; - - keymap = seat->keymap; - xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); - - direction = gdk_keymap_get_direction (keymap); - bidi = gdk_keymap_have_bidi_layouts (keymap); - caps_lock = gdk_keymap_get_caps_lock_state (keymap); - num_lock = gdk_keymap_get_num_lock_state (keymap); - scroll_lock = gdk_keymap_get_scroll_lock_state (keymap); - modifiers = gdk_keymap_get_modifier_state (keymap); - layout = get_active_layout (keymap); - - /* Note: the docs for xkb_state_update mask state that all parameters - * must be passed, or we may end up with an 'incoherent' state. But the - * Wayland modifiers event only includes a single group field, so we - * can't pass depressed/latched/locked groups. - * - * We assume that the compositor is sending us the 'effective' group - * (the protocol is not clear on that point), and pass it as the depressed - * group - we are basically pretending that the user holds down a key for - * this group at all times. - * - * This means that our xkb_state would answer a few questions differently - * from the compositors xkb_state - e.g. if you asked it about the latched - * group. But nobody is asking it those questions, so it does not really - * matter. We hope. - */ - xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0); - - seat->key_modifiers = gdk_keymap_get_modifier_state (keymap); - - g_signal_emit_by_name (keymap, "state-changed"); - if (layout != get_active_layout (keymap)) - { - GDK_DISPLAY_DEBUG (keymap->display, INPUT, "active layout now: %s", get_active_layout_name (keymap)); - - g_signal_emit_by_name (keymap, "keys-changed"); - } - if (direction != gdk_keymap_get_direction (keymap)) - { - g_signal_emit_by_name (keymap, "direction-changed"); - g_object_notify (G_OBJECT (seat->logical_keyboard), "direction"); - } - if (bidi != gdk_keymap_have_bidi_layouts (keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "has-bidi-layouts"); - if (caps_lock != gdk_keymap_get_caps_lock_state (keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "caps-lock-state"); - if (num_lock != gdk_keymap_get_num_lock_state (keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "num-lock-state"); - if (scroll_lock != gdk_keymap_get_scroll_lock_state (keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "scroll-lock-state"); - if (modifiers != gdk_keymap_get_modifier_state (keymap)) - g_object_notify (G_OBJECT (seat->logical_keyboard), "modifier-state"); -} - -static void -keyboard_handle_repeat_info (void *data, - struct wl_keyboard *keyboard, - int32_t rate, - int32_t delay) -{ - GdkWaylandSeat *seat = data; - - seat->have_server_repeat = TRUE; - seat->server_repeat_rate = rate; - seat->server_repeat_delay = delay; -} - -static GdkWaylandTouchData * -gdk_wayland_seat_add_touch (GdkWaylandSeat *seat, - uint32_t id, - struct wl_surface *surface) -{ - GdkWaylandTouchData *touch; - - touch = g_new0 (GdkWaylandTouchData, 1); - touch->id = id; - touch->surface = wl_surface_get_user_data (surface); - touch->initial_touch = (g_hash_table_size (seat->touches) == 0); - - g_hash_table_insert (seat->touches, GUINT_TO_POINTER (id), touch); - - return touch; -} - -static GdkWaylandTouchData * -gdk_wayland_seat_get_touch (GdkWaylandSeat *seat, - uint32_t id) -{ - return g_hash_table_lookup (seat->touches, GUINT_TO_POINTER (id)); -} - -static void -gdk_wayland_seat_remove_touch (GdkWaylandSeat *seat, - uint32_t id) -{ - g_hash_table_remove (seat->touches, GUINT_TO_POINTER (id)); -} - -void -gdk_wayland_seat_clear_touchpoints (GdkWaylandSeat *seat, - GdkSurface *surface) -{ - GHashTableIter iter; - GdkWaylandTouchData *touch; - - g_hash_table_iter_init (&iter, seat->touches); - - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) - { - if (touch->surface == surface) - g_hash_table_iter_remove (&iter); - } -} - -static void -mimic_pointer_emulating_touch_info (GdkDevice *device, - GdkWaylandTouchData *touch) -{ - GdkWaylandPointerData *pointer; - - pointer = GDK_WAYLAND_DEVICE (device)->pointer; - g_set_object (&pointer->focus, touch->surface); - pointer->press_serial = pointer->enter_serial = touch->touch_down_serial; - pointer->surface_x = touch->x; - pointer->surface_y = touch->y; -} - -static void -touch_handle_logical_pointer_crossing (GdkWaylandSeat *seat, - GdkWaylandTouchData *touch, - uint32_t time) -{ - GdkWaylandPointerData *pointer; - - pointer = GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer; - - if (pointer->focus == touch->surface) - return; - - if (pointer->focus) - { - emulate_touch_crossing (pointer->focus, NULL, - seat->logical_touch, seat->touch, touch, - GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, time); - } - - if (touch->surface) - { - emulate_touch_crossing (touch->surface, NULL, - seat->logical_touch, seat->touch, touch, - GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, time); - } -} - -static void -touch_handle_down (void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - struct wl_surface *wl_surface, - int32_t id, - wl_fixed_t x, - wl_fixed_t y) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTouchData *touch; - GdkEvent *event; - - if (!wl_surface) - return; - - touch = gdk_wayland_seat_add_touch (seat, id, wl_surface); - touch->x = wl_fixed_to_double (x); - touch->y = wl_fixed_to_double (y); - touch->touch_down_serial = serial; - - event = gdk_touch_event_new (GDK_TOUCH_BEGIN, - GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), - touch->surface, - seat->logical_touch, - time, - device_get_modifiers (seat->logical_touch), - touch->x, touch->y, - NULL, - touch->initial_touch); - - if (touch->initial_touch) - { - touch_handle_logical_pointer_crossing (seat, touch, time); - GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = touch; - mimic_pointer_emulating_touch_info (seat->logical_touch, touch); - } - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double xx, yy; - gdk_event_get_position (event, &xx, &yy); - g_message ("touch begin %f %f", xx, yy); - } - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -touch_handle_up (void *data, - struct wl_touch *wl_touch, - uint32_t serial, - uint32_t time, - int32_t id) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTouchData *touch; - GdkEvent *event; - - touch = gdk_wayland_seat_get_touch (seat, id); - if (!touch) - return; - - event = gdk_touch_event_new (GDK_TOUCH_END, - GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), - touch->surface, - seat->logical_touch, - time, - device_get_modifiers (seat->logical_touch), - touch->x, touch->y, - NULL, - touch->initial_touch); - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double x, y; - gdk_event_get_position (event, &x, &y); - g_message ("touch end %f %f", x, y); - } - - _gdk_wayland_display_deliver_event (seat->display, event); - - if (touch->initial_touch) - GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = NULL; - - gdk_wayland_seat_remove_touch (seat, id); -} - -static void -touch_handle_motion (void *data, - struct wl_touch *wl_touch, - uint32_t time, - int32_t id, - wl_fixed_t x, - wl_fixed_t y) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTouchData *touch; - GdkEvent *event; - - touch = gdk_wayland_seat_get_touch (seat, id); - if (!touch) - return; - - touch->x = wl_fixed_to_double (x); - touch->y = wl_fixed_to_double (y); - - if (touch->initial_touch) - mimic_pointer_emulating_touch_info (seat->logical_touch, touch); - - event = gdk_touch_event_new (GDK_TOUCH_UPDATE, - GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), - touch->surface, - seat->logical_touch, - time, - device_get_modifiers (seat->logical_touch), - touch->x, touch->y, - NULL, - touch->initial_touch); - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double xx, yy; - gdk_event_get_position (event, &xx, &yy); - g_message ("touch update %f %f", xx, yy); - } - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -touch_handle_frame (void *data, - struct wl_touch *wl_touch) -{ -} - -static void -touch_handle_cancel (void *data, - struct wl_touch *wl_touch) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTouchData *touch; - GHashTableIter iter; - GdkEvent *event; - - if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch) - { - touch = GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch; - GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL; - } - - g_hash_table_iter_init (&iter, seat->touches); - - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) - { - event = gdk_touch_event_new (GDK_TOUCH_CANCEL, - GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), - touch->surface, - seat->logical_touch, - GDK_CURRENT_TIME, - device_get_modifiers (seat->logical_touch), - touch->x, touch->y, - NULL, - touch->initial_touch); - _gdk_wayland_display_deliver_event (seat->display, event); - g_hash_table_iter_remove (&iter); - } - - GDK_SEAT_DEBUG (seat, EVENTS, "touch cancel"); -} - -static void -touch_handle_shape (void *data, - struct wl_touch *touch, - int32_t id, - wl_fixed_t major, - wl_fixed_t minor) -{ -} - -static void -touch_handle_orientation (void *data, - struct wl_touch *touch, - int32_t id, - wl_fixed_t orientation) -{ -} - -static void -emit_gesture_swipe_event (GdkWaylandSeat *seat, - GdkTouchpadGesturePhase phase, - guint32 _time, - guint32 n_fingers, - double dx, - double dy) -{ - GdkEvent *event; - - if (!seat->pointer_info.focus) - return; - - seat->pointer_info.time = _time; - - if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) - seat->pointer_info.touchpad_event_sequence++; - - event = gdk_touchpad_event_new_swipe (seat->pointer_info.focus, - GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), - seat->logical_pointer, - _time, - device_get_modifiers (seat->logical_pointer), - phase, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - n_fingers, - dx, dy); - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double x, y; - gdk_event_get_position (event, &x, &y); - g_message ("swipe event %d, coords: %f %f, seat %p state %d", - gdk_event_get_event_type (event), x, y, seat, - gdk_event_get_modifier_state (event)); - } - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -gesture_swipe_begin (void *data, - struct zwp_pointer_gesture_swipe_v1 *swipe, - uint32_t serial, - uint32_t time, - struct wl_surface *surface, - uint32_t fingers) -{ - GdkWaylandSeat *seat = data; - - emit_gesture_swipe_event (seat, - GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, - time, fingers, 0, 0); - seat->gesture_n_fingers = fingers; -} - -static void -gesture_swipe_update (void *data, - struct zwp_pointer_gesture_swipe_v1 *swipe, - uint32_t time, - wl_fixed_t dx, - wl_fixed_t dy) -{ - GdkWaylandSeat *seat = data; - - emit_gesture_swipe_event (seat, - GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, - time, - seat->gesture_n_fingers, - wl_fixed_to_double (dx), - wl_fixed_to_double (dy)); -} - -static void -gesture_swipe_end (void *data, - struct zwp_pointer_gesture_swipe_v1 *swipe, - uint32_t serial, - uint32_t time, - int32_t cancelled) -{ - GdkWaylandSeat *seat = data; - GdkTouchpadGesturePhase phase; - - phase = (cancelled) ? - GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : - GDK_TOUCHPAD_GESTURE_PHASE_END; - - emit_gesture_swipe_event (seat, phase, time, - seat->gesture_n_fingers, 0, 0); -} - -static void -emit_gesture_pinch_event (GdkWaylandSeat *seat, - GdkTouchpadGesturePhase phase, - guint32 _time, - guint n_fingers, - double dx, - double dy, - double scale, - double angle_delta) -{ - GdkEvent *event; - - if (!seat->pointer_info.focus) - return; - - seat->pointer_info.time = _time; - - if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) - seat->pointer_info.touchpad_event_sequence++; - - event = gdk_touchpad_event_new_pinch (seat->pointer_info.focus, - GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), - seat->logical_pointer, - _time, - device_get_modifiers (seat->logical_pointer), - phase, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - n_fingers, - dx, dy, - scale, angle_delta * G_PI / 180); - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double x, y; - gdk_event_get_position (event, &x, &y); - g_message ("pinch event %d, coords: %f %f, seat %p state %d", - gdk_event_get_event_type (event), - x, y, seat, - gdk_event_get_modifier_state (event)); - } - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -gesture_pinch_begin (void *data, - struct zwp_pointer_gesture_pinch_v1 *pinch, - uint32_t serial, - uint32_t time, - struct wl_surface *surface, - uint32_t fingers) -{ - GdkWaylandSeat *seat = data; - - emit_gesture_pinch_event (seat, - GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, - time, fingers, 0, 0, 1, 0); - seat->gesture_n_fingers = fingers; -} - -static void -gesture_pinch_update (void *data, - struct zwp_pointer_gesture_pinch_v1 *pinch, - uint32_t time, - wl_fixed_t dx, - wl_fixed_t dy, - wl_fixed_t scale, - wl_fixed_t rotation) -{ - GdkWaylandSeat *seat = data; - - emit_gesture_pinch_event (seat, - GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, time, - seat->gesture_n_fingers, - wl_fixed_to_double (dx), - wl_fixed_to_double (dy), - wl_fixed_to_double (scale), - wl_fixed_to_double (rotation)); -} - -static void -gesture_pinch_end (void *data, - struct zwp_pointer_gesture_pinch_v1 *pinch, - uint32_t serial, - uint32_t time, - int32_t cancelled) -{ - GdkWaylandSeat *seat = data; - GdkTouchpadGesturePhase phase; - - phase = (cancelled) ? - GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : - GDK_TOUCHPAD_GESTURE_PHASE_END; - - emit_gesture_pinch_event (seat, phase, - time, seat->gesture_n_fingers, - 0, 0, 1, 0); -} - -static void -emit_gesture_hold_event (GdkWaylandSeat *seat, - GdkTouchpadGesturePhase phase, - guint32 _time, - guint32 n_fingers) -{ - GdkEvent *event; - - if (!seat->pointer_info.focus) - return; - - seat->pointer_info.time = _time; - - if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) - seat->pointer_info.touchpad_event_sequence++; - - event = gdk_touchpad_event_new_hold (seat->pointer_info.focus, - GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), - seat->logical_pointer, - _time, - device_get_modifiers (seat->logical_pointer), - phase, - seat->pointer_info.surface_x, - seat->pointer_info.surface_y, - n_fingers); - - if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) - { - double x, y; - gdk_event_get_position (event, &x, &y); - g_message ("hold event %d, coords: %f %f, seat %p state %d", - gdk_event_get_event_type (event), - x, y, seat, - gdk_event_get_modifier_state (event)); - } - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -gesture_hold_begin (void *data, - struct zwp_pointer_gesture_hold_v1 *hold, - uint32_t serial, - uint32_t time, - struct wl_surface *surface, - uint32_t fingers) -{ - GdkWaylandSeat *seat = data; - - emit_gesture_hold_event (seat, - GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, - time, fingers); - seat->gesture_n_fingers = fingers; -} - -static void -gesture_hold_end (void *data, - struct zwp_pointer_gesture_hold_v1 *hold, - uint32_t serial, - uint32_t time, - int32_t cancelled) -{ - GdkWaylandSeat *seat = data; - GdkTouchpadGesturePhase phase; - - phase = (cancelled) ? - GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : - GDK_TOUCHPAD_GESTURE_PHASE_END; - - emit_gesture_hold_event (seat, phase, time, - seat->gesture_n_fingers); -} - -static void -_gdk_wayland_seat_remove_tool (GdkWaylandSeat *seat, - GdkWaylandTabletToolData *tool) -{ - seat->tablet_tools = g_list_remove (seat->tablet_tools, tool); - - gdk_seat_tool_removed (GDK_SEAT (seat), tool->tool); - - zwp_tablet_tool_v2_destroy (tool->wp_tablet_tool); - g_object_unref (tool->tool); - g_free (tool); -} - -static void -_gdk_wayland_seat_remove_tablet (GdkWaylandSeat *seat, - GdkWaylandTabletData *tablet) -{ - seat->tablets = g_list_remove (seat->tablets, tablet); - - gdk_seat_device_removed (GDK_SEAT (seat), tablet->stylus_device); - gdk_seat_device_removed (GDK_SEAT (seat), tablet->logical_device); - - while (tablet->pads) - { - GdkWaylandTabletPadData *pad = tablet->pads->data; - - pad->current_tablet = NULL; - tablet->pads = g_list_remove (tablet->pads, pad); - } - - zwp_tablet_v2_destroy (tablet->wp_tablet); - - _gdk_device_set_associated_device (tablet->logical_device, NULL); - _gdk_device_set_associated_device (tablet->stylus_device, NULL); - - if (tablet->pointer_info.focus) - g_object_unref (tablet->pointer_info.focus); - - wl_surface_destroy (tablet->pointer_info.pointer_surface); - g_object_unref (tablet->logical_device); - g_object_unref (tablet->stylus_device); - g_free (tablet); -} - -static void -_gdk_wayland_seat_remove_tablet_pad (GdkWaylandSeat *seat, - GdkWaylandTabletPadData *pad) -{ - seat->tablet_pads = g_list_remove (seat->tablet_pads, pad); - - gdk_seat_device_removed (GDK_SEAT (seat), pad->device); - _gdk_device_set_associated_device (pad->device, NULL); - - g_object_unref (pad->device); - g_free (pad); -} - -static GdkWaylandTabletPadGroupData * -tablet_pad_lookup_button_group (GdkWaylandTabletPadData *pad, - uint32_t button) -{ - GdkWaylandTabletPadGroupData *group; - GList *l; - - for (l = pad->mode_groups; l; l = l->next) - { - group = l->data; - - if (g_list_find (group->buttons, GUINT_TO_POINTER (button))) - return group; - } - - return NULL; -} - -static void -tablet_handle_name (void *data, - struct zwp_tablet_v2 *wp_tablet, - const char *name) -{ - GdkWaylandTabletData *tablet = data; - - tablet->name = g_strdup (name); -} - -static void -tablet_handle_id (void *data, - struct zwp_tablet_v2 *wp_tablet, - uint32_t vid, - uint32_t pid) -{ - GdkWaylandTabletData *tablet = data; - - tablet->vid = vid; - tablet->pid = pid; -} - -static void -tablet_handle_path (void *data, - struct zwp_tablet_v2 *wp_tablet, - const char *path) -{ - GdkWaylandTabletData *tablet = data; - - tablet->path = g_strdup (path); -} - -static void -tablet_handle_done (void *data, - struct zwp_tablet_v2 *wp_tablet) -{ - GdkWaylandTabletData *tablet = data; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat); - GdkDisplay *display = gdk_seat_get_display (GDK_SEAT (seat)); - GdkDevice *logical_device, *stylus_device; - char *logical_name; - char *vid, *pid; - - vid = g_strdup_printf ("%.4x", tablet->vid); - pid = g_strdup_printf ("%.4x", tablet->pid); - - logical_name = g_strdup_printf ("Logical pointer for %s", tablet->name); - logical_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", logical_name, - "source", GDK_SOURCE_MOUSE, - "has-cursor", TRUE, - "display", display, - "seat", seat, - NULL); - GDK_WAYLAND_DEVICE (logical_device)->pointer = &tablet->pointer_info; - - stylus_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", tablet->name, - "source", GDK_SOURCE_PEN, - "has-cursor", FALSE, - "display", display, - "seat", seat, - "vendor-id", vid, - "product-id", pid, - NULL); - - tablet->logical_device = logical_device; - init_pointer_data (&tablet->pointer_info, display, tablet->logical_device); - - tablet->stylus_device = stylus_device; - - _gdk_device_set_associated_device (logical_device, seat->logical_keyboard); - _gdk_device_set_associated_device (stylus_device, logical_device); - - gdk_seat_device_added (GDK_SEAT (seat), logical_device); - gdk_seat_device_added (GDK_SEAT (seat), stylus_device); - - g_free (logical_name); - g_free (vid); - g_free (pid); -} - -static void -tablet_handle_removed (void *data, - struct zwp_tablet_v2 *wp_tablet) -{ - GdkWaylandTabletData *tablet = data; - - _gdk_wayland_seat_remove_tablet (GDK_WAYLAND_SEAT (tablet->seat), tablet); -} - -static const struct wl_pointer_listener pointer_listener = { - pointer_handle_enter, - pointer_handle_leave, - pointer_handle_motion, - pointer_handle_button, - pointer_handle_axis, - pointer_handle_frame, - pointer_handle_axis_source, - pointer_handle_axis_stop, - pointer_handle_axis_discrete, - pointer_handle_axis_value120, -}; - -static const struct wl_keyboard_listener keyboard_listener = { - keyboard_handle_keymap, - keyboard_handle_enter, - keyboard_handle_leave, - keyboard_handle_key, - keyboard_handle_modifiers, - keyboard_handle_repeat_info, -}; - -static const struct wl_touch_listener touch_listener = { - touch_handle_down, - touch_handle_up, - touch_handle_motion, - touch_handle_frame, - touch_handle_cancel, - touch_handle_shape, - touch_handle_orientation, -}; - -static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = { - gesture_swipe_begin, - gesture_swipe_update, - gesture_swipe_end -}; - -static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = { - gesture_pinch_begin, - gesture_pinch_update, - gesture_pinch_end -}; - -static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = { - gesture_hold_begin, - gesture_hold_end -}; - -static const struct zwp_tablet_v2_listener tablet_listener = { - tablet_handle_name, - tablet_handle_id, - tablet_handle_path, - tablet_handle_done, - tablet_handle_removed, -}; - -static void -seat_handle_capabilities (void *data, - struct wl_seat *wl_seat, - enum wl_seat_capability caps) -{ - GdkWaylandSeat *seat = data; - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); - - GDK_SEAT_DEBUG (seat, MISC, - "seat %p with %s%s%s", wl_seat, - (caps & WL_SEAT_CAPABILITY_POINTER) ? " pointer, " : "", - (caps & WL_SEAT_CAPABILITY_KEYBOARD) ? " keyboard, " : "", - (caps & WL_SEAT_CAPABILITY_TOUCH) ? " touch" : ""); - - if ((caps & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) - { - seat->wl_pointer = wl_seat_get_pointer (wl_seat); - wl_pointer_set_user_data (seat->wl_pointer, seat); - wl_pointer_add_listener (seat->wl_pointer, &pointer_listener, seat); - - seat->pointer = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Pointer", - "source", GDK_SOURCE_MOUSE, - "has-cursor", TRUE, - "display", seat->display, - "seat", seat, - NULL); - _gdk_device_set_associated_device (seat->pointer, seat->logical_pointer); - gdk_seat_device_added (GDK_SEAT (seat), seat->pointer); - - if (display_wayland->pointer_gestures) - { - seat->wp_pointer_gesture_swipe = - zwp_pointer_gestures_v1_get_swipe_gesture (display_wayland->pointer_gestures, - seat->wl_pointer); - zwp_pointer_gesture_swipe_v1_set_user_data (seat->wp_pointer_gesture_swipe, - seat); - zwp_pointer_gesture_swipe_v1_add_listener (seat->wp_pointer_gesture_swipe, - &gesture_swipe_listener, seat); - - seat->wp_pointer_gesture_pinch = - zwp_pointer_gestures_v1_get_pinch_gesture (display_wayland->pointer_gestures, - seat->wl_pointer); - zwp_pointer_gesture_pinch_v1_set_user_data (seat->wp_pointer_gesture_pinch, - seat); - zwp_pointer_gesture_pinch_v1_add_listener (seat->wp_pointer_gesture_pinch, - &gesture_pinch_listener, seat); - - if (display_wayland->pointer_gestures_version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE_SINCE_VERSION) - { - seat->wp_pointer_gesture_hold = - zwp_pointer_gestures_v1_get_hold_gesture (display_wayland->pointer_gestures, - seat->wl_pointer); - zwp_pointer_gesture_hold_v1_set_user_data (seat->wp_pointer_gesture_hold, - seat); - zwp_pointer_gesture_hold_v1_add_listener (seat->wp_pointer_gesture_hold, - &gesture_hold_listener, seat); - } - } - } - else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) - { - g_clear_pointer (&seat->wp_pointer_gesture_swipe, - zwp_pointer_gesture_swipe_v1_destroy); - g_clear_pointer (&seat->wp_pointer_gesture_pinch, - zwp_pointer_gesture_pinch_v1_destroy); - - wl_pointer_release (seat->wl_pointer); - seat->wl_pointer = NULL; - gdk_seat_device_removed (GDK_SEAT (seat), seat->pointer); - _gdk_device_set_associated_device (seat->pointer, NULL); - - g_clear_object (&seat->pointer); - - if (seat->wheel_scrolling) - { - gdk_seat_device_removed (GDK_SEAT (seat), seat->wheel_scrolling); - _gdk_device_set_associated_device (seat->wheel_scrolling, NULL); - - g_clear_object (&seat->wheel_scrolling); - } - - if (seat->finger_scrolling) - { - gdk_seat_device_removed (GDK_SEAT (seat), seat->finger_scrolling); - _gdk_device_set_associated_device (seat->finger_scrolling, NULL); - - g_clear_object (&seat->finger_scrolling); - } - - if (seat->continuous_scrolling) - { - gdk_seat_device_removed (GDK_SEAT (seat), seat->continuous_scrolling); - _gdk_device_set_associated_device (seat->continuous_scrolling, NULL); - - g_clear_object (&seat->continuous_scrolling); - } - } - - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !seat->wl_keyboard) - { - seat->wl_keyboard = wl_seat_get_keyboard (wl_seat); - wl_keyboard_set_user_data (seat->wl_keyboard, seat); - wl_keyboard_add_listener (seat->wl_keyboard, &keyboard_listener, seat); - - seat->keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Keyboard", - "source", GDK_SOURCE_KEYBOARD, - "has-cursor", FALSE, - "display", seat->display, - "seat", seat, - NULL); - _gdk_device_reset_axes (seat->keyboard); - _gdk_device_set_associated_device (seat->keyboard, seat->logical_keyboard); - gdk_seat_device_added (GDK_SEAT (seat), seat->keyboard); - } - else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard) - { - wl_keyboard_release (seat->wl_keyboard); - seat->wl_keyboard = NULL; - gdk_seat_device_removed (GDK_SEAT (seat), seat->keyboard); - _gdk_device_set_associated_device (seat->keyboard, NULL); - - g_clear_object (&seat->keyboard); - } - - if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !seat->wl_touch) - { - seat->wl_touch = wl_seat_get_touch (wl_seat); - wl_touch_set_user_data (seat->wl_touch, seat); - wl_touch_add_listener (seat->wl_touch, &touch_listener, seat); - - seat->logical_touch = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Touch Logical Pointer", - "source", GDK_SOURCE_TOUCHSCREEN, - "has-cursor", TRUE, - "display", seat->display, - "seat", seat, - NULL); - GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer = &seat->touch_info; - _gdk_device_set_associated_device (seat->logical_touch, seat->logical_keyboard); - gdk_seat_device_added (GDK_SEAT (seat), seat->logical_touch); - - seat->touch = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Touch", - "source", GDK_SOURCE_TOUCHSCREEN, - "has-cursor", FALSE, - "display", seat->display, - "seat", seat, - NULL); - _gdk_device_set_associated_device (seat->touch, seat->logical_touch); - gdk_seat_device_added (GDK_SEAT (seat), seat->touch); - } - else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch) - { - wl_touch_release (seat->wl_touch); - seat->wl_touch = NULL; - gdk_seat_device_removed (GDK_SEAT (seat), seat->touch); - gdk_seat_device_removed (GDK_SEAT (seat), seat->logical_touch); - _gdk_device_set_associated_device (seat->logical_touch, NULL); - _gdk_device_set_associated_device (seat->touch, NULL); - - g_clear_object (&seat->logical_touch); - g_clear_object (&seat->touch); - } -} - -static GdkDevice * -get_scroll_device (GdkWaylandSeat *seat, - enum wl_pointer_axis_source source) -{ - if (!seat->pointer) - return NULL; - - switch (source) - { - case WL_POINTER_AXIS_SOURCE_WHEEL: - if (seat->wheel_scrolling == NULL) - { - seat->wheel_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Wheel Scrolling", - "source", GDK_SOURCE_MOUSE, - "has-cursor", TRUE, - "display", seat->display, - "seat", seat, - NULL); - gdk_seat_device_added (GDK_SEAT (seat), seat->wheel_scrolling); - } - return seat->wheel_scrolling; - - case WL_POINTER_AXIS_SOURCE_FINGER: - if (seat->finger_scrolling == NULL) - { - seat->finger_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Finger Scrolling", - "source", GDK_SOURCE_TOUCHPAD, - "has-cursor", TRUE, - "display", seat->display, - "seat", seat, - NULL); - gdk_seat_device_added (GDK_SEAT (seat), seat->finger_scrolling); - } - return seat->finger_scrolling; - - case WL_POINTER_AXIS_SOURCE_CONTINUOUS: - if (seat->continuous_scrolling == NULL) - { - seat->continuous_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Wayland Continuous Scrolling", - "source", GDK_SOURCE_TRACKPOINT, - "has-cursor", TRUE, - "display", seat->display, - "seat", seat, - NULL); - gdk_seat_device_added (GDK_SEAT (seat), seat->continuous_scrolling); - } - return seat->continuous_scrolling; - - case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: - default: - return seat->pointer; - } -} - -static void -seat_handle_name (void *data, - struct wl_seat *seat, - const char *name) -{ - /* We don't care about the name. */ - GDK_SEAT_DEBUG (GDK_WAYLAND_SEAT (data), MISC, - "seat %p name %s", seat, name); -} - -static const struct wl_seat_listener seat_listener = { - seat_handle_capabilities, - seat_handle_name, -}; - -static void -tablet_tool_handle_type (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t tool_type) -{ - GdkWaylandTabletToolData *tool = data; - - switch (tool_type) - { - case ZWP_TABLET_TOOL_V2_TYPE_PEN: - tool->type = GDK_DEVICE_TOOL_TYPE_PEN; - break; - case ZWP_TABLET_TOOL_V2_TYPE_BRUSH: - tool->type = GDK_DEVICE_TOOL_TYPE_BRUSH; - break; - case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH: - tool->type = GDK_DEVICE_TOOL_TYPE_AIRBRUSH; - break; - case ZWP_TABLET_TOOL_V2_TYPE_PENCIL: - tool->type = GDK_DEVICE_TOOL_TYPE_PENCIL; - break; - case ZWP_TABLET_TOOL_V2_TYPE_ERASER: - tool->type = GDK_DEVICE_TOOL_TYPE_ERASER; - break; - case ZWP_TABLET_TOOL_V2_TYPE_MOUSE: - tool->type = GDK_DEVICE_TOOL_TYPE_MOUSE; - break; - case ZWP_TABLET_TOOL_V2_TYPE_LENS: - tool->type = GDK_DEVICE_TOOL_TYPE_LENS; - break; - default: - tool->type = GDK_DEVICE_TOOL_TYPE_UNKNOWN; - break; - }; -} - -static void -tablet_tool_handle_hardware_serial (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t serial_hi, - uint32_t serial_lo) -{ - GdkWaylandTabletToolData *tool = data; - - tool->hardware_serial = ((guint64) serial_hi) << 32 | serial_lo; -} - -static void -tablet_tool_handle_hardware_id_wacom (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t id_hi, - uint32_t id_lo) -{ - GdkWaylandTabletToolData *tool = data; - - tool->hardware_id_wacom = ((guint64) id_hi) << 32 | id_lo; -} - -static void -tablet_tool_handle_capability (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t capability) -{ - GdkWaylandTabletToolData *tool = data; - - switch (capability) - { - case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: - tool->axes |= GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT; - break; - case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: - tool->axes |= GDK_AXIS_FLAG_PRESSURE; - break; - case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: - tool->axes |= GDK_AXIS_FLAG_DISTANCE; - break; - case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: - tool->axes |= GDK_AXIS_FLAG_ROTATION; - break; - case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: - tool->axes |= GDK_AXIS_FLAG_SLIDER; - break; - default: - break; - } -} - -static void -tablet_tool_handle_done (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool) -{ - GdkWaylandTabletToolData *tool = data; - - tool->tool = gdk_device_tool_new (tool->hardware_serial, - tool->hardware_id_wacom, - tool->type, tool->axes); - gdk_seat_tool_added (tool->seat, tool->tool); -} - -static void -tablet_tool_handle_removed (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool) -{ - GdkWaylandTabletToolData *tool = data; - - _gdk_wayland_seat_remove_tool (GDK_WAYLAND_SEAT (tool->seat), tool); -} - -static void -gdk_wayland_tablet_flush_frame_event (GdkWaylandTabletData *tablet, - guint32 time) -{ - GdkEvent *event; - GdkEventType type; - - event = tablet->pointer_info.frame.event; - tablet->pointer_info.frame.event = NULL; - - if (!event) - return; - - gdk_event_ref (event); - - type = gdk_event_get_event_type (event); - - if (type == GDK_PROXIMITY_OUT) - emulate_crossing (gdk_event_get_surface (event), NULL, - tablet->logical_device, GDK_LEAVE_NOTIFY, - GDK_CROSSING_NORMAL, time); - - _gdk_wayland_display_deliver_event (gdk_seat_get_display (tablet->seat), - event); - - if (type == GDK_PROXIMITY_IN) - emulate_crossing (gdk_event_get_surface (event), NULL, - tablet->logical_device, GDK_ENTER_NOTIFY, - GDK_CROSSING_NORMAL, time); - - gdk_event_unref (event); -} - -static void -gdk_wayland_tablet_set_frame_event (GdkWaylandTabletData *tablet, - GdkEvent *event) -{ - if (tablet->pointer_info.frame.event && - gdk_event_get_event_type (tablet->pointer_info.frame.event) != gdk_event_get_event_type (event)) - gdk_wayland_tablet_flush_frame_event (tablet, GDK_CURRENT_TIME); - - tablet->pointer_info.frame.event = event; -} - -static void -gdk_wayland_device_tablet_clone_tool_axes (GdkWaylandTabletData *tablet, - GdkDeviceTool *tool) -{ - int axis_pos; - - g_object_freeze_notify (G_OBJECT (tablet->stylus_device)); - _gdk_device_reset_axes (tablet->stylus_device); - - _gdk_device_add_axis (tablet->stylus_device, GDK_AXIS_X, 0, 0, 0); - _gdk_device_add_axis (tablet->stylus_device, GDK_AXIS_Y, 0, 0, 0); - - if (tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT)) - { - axis_pos = _gdk_device_add_axis (tablet->stylus_device, - GDK_AXIS_XTILT, -90, 90, 0); - tablet->axis_indices[GDK_AXIS_XTILT] = axis_pos; - - axis_pos = _gdk_device_add_axis (tablet->stylus_device, - GDK_AXIS_YTILT, -90, 90, 0); - tablet->axis_indices[GDK_AXIS_YTILT] = axis_pos; - } - if (tool->tool_axes & GDK_AXIS_FLAG_DISTANCE) - { - axis_pos = _gdk_device_add_axis (tablet->stylus_device, - GDK_AXIS_DISTANCE, 0, 65535, 0); - tablet->axis_indices[GDK_AXIS_DISTANCE] = axis_pos; - } - if (tool->tool_axes & GDK_AXIS_FLAG_PRESSURE) - { - axis_pos = _gdk_device_add_axis (tablet->stylus_device, - GDK_AXIS_PRESSURE, 0, 65535, 0); - tablet->axis_indices[GDK_AXIS_PRESSURE] = axis_pos; - } - - if (tool->tool_axes & GDK_AXIS_FLAG_ROTATION) - { - axis_pos = _gdk_device_add_axis (tablet->stylus_device, - GDK_AXIS_ROTATION, 0, 360, 0); - tablet->axis_indices[GDK_AXIS_ROTATION] = axis_pos; - } - - if (tool->tool_axes & GDK_AXIS_FLAG_SLIDER) - { - axis_pos = _gdk_device_add_axis (tablet->stylus_device, - GDK_AXIS_SLIDER, -65535, 65535, 0); - tablet->axis_indices[GDK_AXIS_SLIDER] = axis_pos; - } - - g_object_thaw_notify (G_OBJECT (tablet->stylus_device)); -} - -static void -gdk_wayland_mimic_device_axes (GdkDevice *logical, - GdkDevice *physical) -{ - double axis_min, axis_max, axis_resolution; - GdkAxisUse axis_use; - int axis_count; - int i; - - g_object_freeze_notify (G_OBJECT (logical)); - _gdk_device_reset_axes (logical); - axis_count = gdk_device_get_n_axes (physical); - - for (i = 0; i < axis_count; i++) - { - _gdk_device_get_axis_info (physical, i, &axis_use, &axis_min, - &axis_max, &axis_resolution); - _gdk_device_add_axis (logical, axis_use, axis_min, - axis_max, axis_resolution); - } - - g_object_thaw_notify (G_OBJECT (logical)); -} - -static void -tablet_tool_handle_proximity_in (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t serial, - struct zwp_tablet_v2 *wp_tablet, - struct wl_surface *wsurface) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet); - GdkSurface *surface; - GdkEvent *event; - - if (!wsurface) - return; - - surface = wl_surface_get_user_data (wsurface); - - if (!surface) - return; - if (!GDK_IS_SURFACE (surface)) - return; - - tool->current_tablet = tablet; - tablet->current_tool = tool; - - tablet->pointer_info.enter_serial = serial; - - tablet->pointer_info.focus = g_object_ref (surface); - - gdk_device_update_tool (tablet->stylus_device, tool->tool); - gdk_wayland_device_tablet_clone_tool_axes (tablet, tool->tool); - gdk_wayland_mimic_device_axes (tablet->logical_device, tablet->stylus_device); - - event = gdk_proximity_event_new (GDK_PROXIMITY_IN, - tablet->pointer_info.focus, - tablet->logical_device, - tool->tool, - tablet->pointer_info.time); - gdk_wayland_tablet_set_frame_event (tablet, event); - - tablet->pointer_info.pointer_surface_outputs = - g_slist_append (tablet->pointer_info.pointer_surface_outputs, - gdk_wayland_surface_get_wl_output (surface)); - pointer_surface_update_scale (tablet->logical_device); - - GDK_SEAT_DEBUG (tablet->seat, EVENTS, - "proximity in, seat %p surface %p tool %d", - tablet->seat, tablet->pointer_info.focus, - gdk_device_tool_get_tool_type (tool->tool)); -} - -static void -tablet_tool_handle_proximity_out (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - GdkEvent *event; - - if (!tablet) - return; - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "proximity out, seat %p, tool %d", tool->seat, - gdk_device_tool_get_tool_type (tool->tool)); - - event = gdk_proximity_event_new (GDK_PROXIMITY_OUT, - tablet->pointer_info.focus, - tablet->logical_device, - tool->tool, - tablet->pointer_info.time); - gdk_wayland_tablet_set_frame_event (tablet, event); - - gdk_wayland_pointer_stop_cursor_animation (&tablet->pointer_info); - - tablet->pointer_info.pointer_surface_outputs = - g_slist_remove (tablet->pointer_info.pointer_surface_outputs, - gdk_wayland_surface_get_wl_output (tablet->pointer_info.focus)); - pointer_surface_update_scale (tablet->logical_device); - - g_object_unref (tablet->pointer_info.focus); - tablet->pointer_info.focus = NULL; - - tablet->pointer_info.button_modifiers &= - ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | - GDK_BUTTON4_MASK | GDK_BUTTON5_MASK); - - gdk_device_update_tool (tablet->stylus_device, NULL); - g_clear_object (&tablet->pointer_info.cursor); -} - -static double * -tablet_copy_axes (GdkWaylandTabletData *tablet) -{ - return g_memdup2 (tablet->axes, sizeof (double) * GDK_AXIS_LAST); -} - -static void -tablet_create_button_event_frame (GdkWaylandTabletData *tablet, - GdkEventType evtype, - guint button) -{ - GdkEvent *event; - - event = gdk_button_event_new (evtype, - tablet->pointer_info.focus, - tablet->logical_device, - tablet->current_tool->tool, - tablet->pointer_info.time, - device_get_modifiers (tablet->logical_device), - button, - tablet->pointer_info.surface_x, - tablet->pointer_info.surface_y, - tablet_copy_axes (tablet)); - gdk_wayland_tablet_set_frame_event (tablet, event); -} - -static void -tablet_tool_handle_down (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t serial) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - - if (!tablet || !tablet->pointer_info.focus) - return; - - tablet->pointer_info.press_serial = serial; - - tablet_create_button_event_frame (tablet, GDK_BUTTON_PRESS, GDK_BUTTON_PRIMARY); - tablet->pointer_info.button_modifiers |= GDK_BUTTON1_MASK; -} - -static void -tablet_tool_handle_up (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - - if (!tablet || !tablet->pointer_info.focus) - return; - - tablet_create_button_event_frame (tablet, GDK_BUTTON_RELEASE, GDK_BUTTON_PRIMARY); - tablet->pointer_info.button_modifiers &= ~GDK_BUTTON1_MASK; -} - -static void -tablet_tool_handle_motion (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - wl_fixed_t sx, - wl_fixed_t sy) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - GdkEvent *event; - - if (!tablet) - return; - - tablet->pointer_info.surface_x = wl_fixed_to_double (sx); - tablet->pointer_info.surface_y = wl_fixed_to_double (sy); - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "tablet motion %f %f", - tablet->pointer_info.surface_x, - tablet->pointer_info.surface_y); - - event = gdk_motion_event_new (tablet->pointer_info.focus, - tablet->logical_device, - tool->tool, - tablet->pointer_info.time, - device_get_modifiers (tablet->logical_device), - tablet->pointer_info.surface_x, - tablet->pointer_info.surface_y, - tablet_copy_axes (tablet)); - - gdk_wayland_tablet_set_frame_event (tablet, event); -} - -static void -tablet_tool_handle_pressure (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t pressure) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - int axis_index; - - if (!tablet) - return; - - axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE]; - - _gdk_device_translate_axis (tablet->stylus_device, axis_index, - pressure, &tablet->axes[GDK_AXIS_PRESSURE]); - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "tablet tool %d pressure %d", - gdk_device_tool_get_tool_type (tool->tool), pressure); -} - -static void -tablet_tool_handle_distance (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t distance) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - int axis_index; - - if (!tablet) - return; - - axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE]; - - _gdk_device_translate_axis (tablet->stylus_device, axis_index, - distance, &tablet->axes[GDK_AXIS_DISTANCE]); - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "tablet tool %d distance %d", - gdk_device_tool_get_tool_type (tool->tool), distance); -} - -static void -tablet_tool_handle_tilt (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - wl_fixed_t xtilt, - wl_fixed_t ytilt) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - int xtilt_axis_index; - int ytilt_axis_index; - - if (!tablet) - return; - - xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT]; - ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT]; - - _gdk_device_translate_axis (tablet->stylus_device, xtilt_axis_index, - wl_fixed_to_double (xtilt), - &tablet->axes[GDK_AXIS_XTILT]); - _gdk_device_translate_axis (tablet->stylus_device, ytilt_axis_index, - wl_fixed_to_double (ytilt), - &tablet->axes[GDK_AXIS_YTILT]); - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "tablet tool %d tilt %f/%f", - gdk_device_tool_get_tool_type (tool->tool), - wl_fixed_to_double (xtilt), wl_fixed_to_double (ytilt)); -} - -static void -tablet_tool_handle_button (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - uint32_t serial, - uint32_t button, - uint32_t state) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - GdkEventType evtype; - guint n_button; - - if (!tablet || !tablet->pointer_info.focus) - return; - - tablet->pointer_info.press_serial = serial; - - if (button == BTN_STYLUS) - n_button = GDK_BUTTON_SECONDARY; - else if (button == BTN_STYLUS2) - n_button = GDK_BUTTON_MIDDLE; - else if (button == BTN_STYLUS3) - n_button = 8; /* Back */ - else - return; - - if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED) - evtype = GDK_BUTTON_PRESS; - else if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED) - evtype = GDK_BUTTON_RELEASE; - else - return; - - tablet_create_button_event_frame (tablet, evtype, n_button); -} - -static void -tablet_tool_handle_rotation (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - wl_fixed_t degrees) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - int axis_index; - - if (!tablet) - return; - - axis_index = tablet->axis_indices[GDK_AXIS_ROTATION]; - - _gdk_device_translate_axis (tablet->stylus_device, axis_index, - wl_fixed_to_double (degrees), - &tablet->axes[GDK_AXIS_ROTATION]); - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "tablet tool %d rotation %f", - gdk_device_tool_get_tool_type (tool->tool), - wl_fixed_to_double (degrees)); -} - -static void -tablet_tool_handle_slider (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - int32_t position) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - int axis_index; - - if (!tablet) - return; - - axis_index = tablet->axis_indices[GDK_AXIS_SLIDER]; - - _gdk_device_translate_axis (tablet->stylus_device, axis_index, - position, &tablet->axes[GDK_AXIS_SLIDER]); - - GDK_SEAT_DEBUG (tool->seat, EVENTS, - "tablet tool %d slider %d", - gdk_device_tool_get_tool_type (tool->tool), position); -} - -static void -tablet_tool_handle_wheel (void *data, - struct zwp_tablet_tool_v2 *wp_tablet_tool, - int32_t degrees, - int32_t clicks) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - GdkWaylandSeat *seat; - GdkEvent *event; - - if (!tablet) - return; - - seat = GDK_WAYLAND_SEAT (tablet->seat); - - GDK_SEAT_DEBUG (seat, EVENTS, - "tablet tool %d wheel %d/%d", - gdk_device_tool_get_tool_type (tool->tool), degrees, clicks); - - if (clicks == 0) - return; - - /* Send smooth event */ - event = gdk_scroll_event_new (tablet->pointer_info.focus, - tablet->logical_device, - tablet->current_tool->tool, - tablet->pointer_info.time, - device_get_modifiers (tablet->logical_device), - 0, clicks, - FALSE, - GDK_SCROLL_UNIT_WHEEL); - - _gdk_wayland_display_deliver_event (seat->display, event); -} - -static void -tablet_tool_handle_frame (void *data, - struct zwp_tablet_tool_v2 *wl_tablet_tool, - uint32_t time) -{ - GdkWaylandTabletToolData *tool = data; - GdkWaylandTabletData *tablet = tool->current_tablet; - GdkEvent *frame_event; - - if (!tablet) - return; - - GDK_SEAT_DEBUG (tablet->seat, EVENTS, - "tablet frame, time %d", time); - - frame_event = tablet->pointer_info.frame.event; - - if (frame_event && gdk_event_get_event_type (frame_event) == GDK_PROXIMITY_OUT) - { - tool->current_tablet = NULL; - tablet->current_tool = NULL; - } - - tablet->pointer_info.time = time; - gdk_wayland_tablet_flush_frame_event (tablet, time); -} - -static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { - tablet_tool_handle_type, - tablet_tool_handle_hardware_serial, - tablet_tool_handle_hardware_id_wacom, - tablet_tool_handle_capability, - tablet_tool_handle_done, - tablet_tool_handle_removed, - tablet_tool_handle_proximity_in, - tablet_tool_handle_proximity_out, - tablet_tool_handle_down, - tablet_tool_handle_up, - tablet_tool_handle_motion, - tablet_tool_handle_pressure, - tablet_tool_handle_distance, - tablet_tool_handle_tilt, - tablet_tool_handle_rotation, - tablet_tool_handle_slider, - tablet_tool_handle_wheel, - tablet_tool_handle_button, - tablet_tool_handle_frame, -}; - -static void -tablet_pad_ring_handle_source (void *data, - struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring, - uint32_t source) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad ring handle source, ring = %p source = %d", - wp_tablet_pad_ring, source); - - group->axis_tmp_info.source = source; -} - -static void -tablet_pad_ring_handle_angle (void *data, - struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring, - wl_fixed_t angle) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad ring handle angle, ring = %p angle = %f", - wp_tablet_pad_ring, wl_fixed_to_double (angle)); - - group->axis_tmp_info.value = wl_fixed_to_double (angle); -} - -static void -tablet_pad_ring_handle_stop (void *data, - struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad ring handle stop, ring = %p", wp_tablet_pad_ring); - - group->axis_tmp_info.is_stop = TRUE; -} - -static void -tablet_pad_ring_handle_frame (void *data, - struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring, - uint32_t time) -{ - GdkWaylandTabletPadGroupData *group = data; - GdkWaylandTabletPadData *pad = group->pad; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); - GdkEvent *event; - - GDK_SEAT_DEBUG (seat, EVENTS, - "tablet pad ring handle frame, ring = %p", wp_tablet_pad_ring); - - event = gdk_pad_event_new_ring (seat->keyboard_focus, - pad->device, - time, - g_list_index (pad->mode_groups, group), - g_list_index (pad->rings, wp_tablet_pad_ring), - group->current_mode, - group->axis_tmp_info.value); - - _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), - event); -} - -static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = { - tablet_pad_ring_handle_source, - tablet_pad_ring_handle_angle, - tablet_pad_ring_handle_stop, - tablet_pad_ring_handle_frame, -}; - -static void -tablet_pad_strip_handle_source (void *data, - struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip, - uint32_t source) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad strip handle source, strip = %p source = %d", - wp_tablet_pad_strip, source); - - group->axis_tmp_info.source = source; -} - -static void -tablet_pad_strip_handle_position (void *data, - struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip, - uint32_t position) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad strip handle position, strip = %p position = %d", - wp_tablet_pad_strip, position); - - group->axis_tmp_info.value = (double) position / 65535; -} - -static void -tablet_pad_strip_handle_stop (void *data, - struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad strip handle stop, strip = %p", - wp_tablet_pad_strip); - - group->axis_tmp_info.is_stop = TRUE; -} - -static void -tablet_pad_strip_handle_frame (void *data, - struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip, - uint32_t time) -{ - GdkWaylandTabletPadGroupData *group = data; - GdkWaylandTabletPadData *pad = group->pad; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); - GdkEvent *event; - - GDK_SEAT_DEBUG (seat, EVENTS, - "tablet pad strip handle frame, strip = %p", - wp_tablet_pad_strip); - - event = gdk_pad_event_new_strip (seat->keyboard_focus, - pad->device, - time, - g_list_index (pad->mode_groups, group), - g_list_index (pad->strips, wp_tablet_pad_strip), - group->current_mode, - group->axis_tmp_info.value); - - _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), - event); -} - -static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener = { - tablet_pad_strip_handle_source, - tablet_pad_strip_handle_position, - tablet_pad_strip_handle_stop, - tablet_pad_strip_handle_frame, -}; - -static void -tablet_pad_group_handle_buttons (void *data, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, - struct wl_array *buttons) -{ - GdkWaylandTabletPadGroupData *group = data; - uint32_t *p; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad group handle buttons, pad group = %p, n_buttons = %" G_GSIZE_FORMAT, - wp_tablet_pad_group, buttons->size); - - wl_array_for_each (p, buttons) - { - group->buttons = g_list_prepend (group->buttons, GUINT_TO_POINTER (*p)); - } - - group->buttons = g_list_reverse (group->buttons); -} - -static void -tablet_pad_group_handle_ring (void *data, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, - struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad group handle ring, pad group = %p, ring = %p", - wp_tablet_pad_group, wp_tablet_pad_ring); - - zwp_tablet_pad_ring_v2_add_listener (wp_tablet_pad_ring, - &tablet_pad_ring_listener, group); - zwp_tablet_pad_ring_v2_set_user_data (wp_tablet_pad_ring, group); - - group->rings = g_list_append (group->rings, wp_tablet_pad_ring); - group->pad->rings = g_list_append (group->pad->rings, wp_tablet_pad_ring); -} - -static void -tablet_pad_group_handle_strip (void *data, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, - struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad group handle strip, pad group = %p, strip = %p", - wp_tablet_pad_group, wp_tablet_pad_strip); - - zwp_tablet_pad_strip_v2_add_listener (wp_tablet_pad_strip, - &tablet_pad_strip_listener, group); - zwp_tablet_pad_strip_v2_set_user_data (wp_tablet_pad_strip, group); - - group->strips = g_list_append (group->strips, wp_tablet_pad_strip); - group->pad->strips = g_list_append (group->pad->strips, wp_tablet_pad_strip); -} - -static void -tablet_pad_group_handle_modes (void *data, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, - uint32_t modes) -{ - GdkWaylandTabletPadGroupData *group = data; - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad group handle modes, pad group = %p, n_modes = %d", - wp_tablet_pad_group, modes); - - group->n_modes = modes; -} - -static void -tablet_pad_group_handle_done (void *data, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group) -{ -#ifdef G_ENABLE_DEBUG - GdkWaylandTabletPadGroupData *group = data; -#endif - - GDK_SEAT_DEBUG (group->pad->seat, EVENTS, - "tablet pad group handle done, pad group = %p", - wp_tablet_pad_group); -} - -static void -tablet_pad_group_handle_mode (void *data, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, - uint32_t time, - uint32_t serial, - uint32_t mode) -{ - GdkWaylandTabletPadGroupData *group = data; - GdkWaylandTabletPadData *pad = group->pad; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); - GdkEvent *event; - guint n_group; - - GDK_SEAT_DEBUG (seat, EVENTS, - "tablet pad group handle mode, pad group = %p, mode = %d", - wp_tablet_pad_group, mode); - - group->mode_switch_serial = serial; - group->current_mode = mode; - n_group = g_list_index (pad->mode_groups, group); - - event = gdk_pad_event_new_group_mode (seat->keyboard_focus, - pad->device, - time, - n_group, - mode); - - _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), - event); -} - -static const struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener = { - tablet_pad_group_handle_buttons, - tablet_pad_group_handle_ring, - tablet_pad_group_handle_strip, - tablet_pad_group_handle_modes, - tablet_pad_group_handle_done, - tablet_pad_group_handle_mode, -}; - -static void -tablet_pad_handle_group (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad, - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group) -{ - GdkWaylandTabletPadData *pad = data; - GdkWaylandTabletPadGroupData *group; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle group, pad group = %p, group = %p", - wp_tablet_pad_group, wp_tablet_pad_group); - - group = g_new0 (GdkWaylandTabletPadGroupData, 1); - group->wp_tablet_pad_group = wp_tablet_pad_group; - group->pad = pad; - - zwp_tablet_pad_group_v2_add_listener (wp_tablet_pad_group, - &tablet_pad_group_listener, group); - zwp_tablet_pad_group_v2_set_user_data (wp_tablet_pad_group, group); - pad->mode_groups = g_list_append (pad->mode_groups, group); -} - -static void -tablet_pad_handle_path (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad, - const char *path) -{ - GdkWaylandTabletPadData *pad = data; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle path, pad = %p, path = %s", - wp_tablet_pad, path); - - pad->path = g_strdup (path); -} - -static void -tablet_pad_handle_buttons (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad, - uint32_t buttons) -{ - GdkWaylandTabletPadData *pad = data; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle buttons, pad = %p, n_buttons = %d", - wp_tablet_pad, buttons); - - pad->n_buttons = buttons; -} - -static void -tablet_pad_handle_done (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad) -{ - GdkWaylandTabletPadData *pad = data; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle done, pad = %p", wp_tablet_pad); - - pad->device = - g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD, - "name", "Pad device", - "source", GDK_SOURCE_TABLET_PAD, - "display", gdk_seat_get_display (pad->seat), - "seat", pad->seat, - NULL); - - _gdk_device_set_associated_device (pad->device, GDK_WAYLAND_SEAT (pad->seat)->logical_keyboard); - gdk_seat_device_added (GDK_SEAT (pad->seat), pad->device); -} - -static void -tablet_pad_handle_button (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad, - uint32_t time, - uint32_t button, - uint32_t state) -{ - GdkWaylandTabletPadData *pad = data; - GdkWaylandTabletPadGroupData *group; - GdkEvent *event; - int n_group; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle button, pad = %p, button = %d, state = %d", - wp_tablet_pad, button, state); - - group = tablet_pad_lookup_button_group (pad, button); - -#ifdef G_DISABLE_ASSERT - if (group == NULL) - return; -#else - g_assert (group != NULL); -#endif - - n_group = g_list_index (pad->mode_groups, group); - - event = gdk_pad_event_new_button (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED - ? GDK_PAD_BUTTON_PRESS - : GDK_PAD_BUTTON_RELEASE, - GDK_WAYLAND_SEAT (pad->seat)->keyboard_focus, - pad->device, - time, - n_group, - button, - group->current_mode); - - _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), event); -} - -static void -tablet_pad_handle_enter (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad, - uint32_t serial, - struct zwp_tablet_v2 *wp_tablet, - struct wl_surface *surface) -{ - GdkWaylandTabletPadData *pad = data; - GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet); - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle enter, pad = %p, tablet = %p surface = %p", - wp_tablet_pad, wp_tablet, surface); - - /* Relate pad and tablet */ - tablet->pads = g_list_prepend (tablet->pads, pad); - pad->current_tablet = tablet; -} - -static void -tablet_pad_handle_leave (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad, - uint32_t serial, - struct wl_surface *surface) -{ - GdkWaylandTabletPadData *pad = data; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle leave, pad = %p, surface = %p", - wp_tablet_pad, surface); - - if (pad->current_tablet) - { - pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad); - pad->current_tablet = NULL; - } -} - -static void -tablet_pad_handle_removed (void *data, - struct zwp_tablet_pad_v2 *wp_tablet_pad) -{ - GdkWaylandTabletPadData *pad = data; - - GDK_SEAT_DEBUG (pad->seat, EVENTS, - "tablet pad handle removed, pad = %p", wp_tablet_pad); - - /* Remove from the current tablet */ - if (pad->current_tablet) - { - pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad); - pad->current_tablet = NULL; - } - - _gdk_wayland_seat_remove_tablet_pad (GDK_WAYLAND_SEAT (pad->seat), pad); -} - -static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { - tablet_pad_handle_group, - tablet_pad_handle_path, - tablet_pad_handle_buttons, - tablet_pad_handle_done, - tablet_pad_handle_button, - tablet_pad_handle_enter, - tablet_pad_handle_leave, - tablet_pad_handle_removed, -}; - -static void -tablet_seat_handle_tablet_added (void *data, - struct zwp_tablet_seat_v2 *wp_tablet_seat, - struct zwp_tablet_v2 *wp_tablet) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTabletData *tablet; - - tablet = g_new0 (GdkWaylandTabletData, 1); - tablet->seat = GDK_SEAT (seat); - - tablet->wp_tablet = wp_tablet; - - seat->tablets = g_list_prepend (seat->tablets, tablet); - - zwp_tablet_v2_add_listener (wp_tablet, &tablet_listener, tablet); - zwp_tablet_v2_set_user_data (wp_tablet, tablet); -} - -static void -tablet_seat_handle_tool_added (void *data, - struct zwp_tablet_seat_v2 *wp_tablet_seat, - struct zwp_tablet_tool_v2 *wp_tablet_tool) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTabletToolData *tool; - - tool = g_new0 (GdkWaylandTabletToolData, 1); - tool->wp_tablet_tool = wp_tablet_tool; - tool->seat = GDK_SEAT (seat); - - zwp_tablet_tool_v2_add_listener (wp_tablet_tool, &tablet_tool_listener, tool); - zwp_tablet_tool_v2_set_user_data (wp_tablet_tool, tool); - - seat->tablet_tools = g_list_prepend (seat->tablet_tools, tool); -} - -static void -tablet_seat_handle_pad_added (void *data, - struct zwp_tablet_seat_v2 *wp_tablet_seat, - struct zwp_tablet_pad_v2 *wp_tablet_pad) -{ - GdkWaylandSeat *seat = data; - GdkWaylandTabletPadData *pad; - - pad = g_new0 (GdkWaylandTabletPadData, 1); - pad->wp_tablet_pad = wp_tablet_pad; - pad->seat = GDK_SEAT (seat); - - zwp_tablet_pad_v2_add_listener (wp_tablet_pad, &tablet_pad_listener, pad); - zwp_tablet_pad_v2_set_user_data (wp_tablet_pad, pad); - - seat->tablet_pads = g_list_prepend (seat->tablet_pads, pad); -} - -static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { - tablet_seat_handle_tablet_added, - tablet_seat_handle_tool_added, - tablet_seat_handle_pad_added, -}; - -static void -init_devices (GdkWaylandSeat *seat) -{ - /* pointer */ - seat->logical_pointer = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Core Pointer", - "source", GDK_SOURCE_MOUSE, - "has-cursor", TRUE, - "display", seat->display, - "seat", seat, - NULL); - - GDK_WAYLAND_DEVICE (seat->logical_pointer)->pointer = &seat->pointer_info; - - /* keyboard */ - seat->logical_keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE, - "name", "Core Keyboard", - "source", GDK_SOURCE_KEYBOARD, - "has-cursor", FALSE, - "display", seat->display, - "seat", seat, - NULL); - _gdk_device_reset_axes (seat->logical_keyboard); - - /* link both */ - _gdk_device_set_associated_device (seat->logical_pointer, seat->logical_keyboard); - _gdk_device_set_associated_device (seat->logical_keyboard, seat->logical_pointer); - - gdk_seat_device_added (GDK_SEAT (seat), seat->logical_pointer); - gdk_seat_device_added (GDK_SEAT (seat), seat->logical_keyboard); -} - -static void -pointer_surface_update_scale (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; - GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); - guint32 scale; - GSList *l; - - if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE) - { - /* We can't set the scale on this surface */ - return; - } - - if (!pointer->pointer_surface_outputs) - return; - - scale = 1; - for (l = pointer->pointer_surface_outputs; l != NULL; l = l->next) - { - guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data); - scale = MAX (scale, output_scale); - } - - if (pointer->current_output_scale == scale) - return; - pointer->current_output_scale = scale; - - gdk_wayland_device_update_surface_cursor (device); -} - -void -gdk_wayland_seat_update_cursor_scale (GdkWaylandSeat *seat) -{ - GList *l; - - pointer_surface_update_scale (seat->logical_pointer); - - for (l = seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - pointer_surface_update_scale (tablet->logical_device); - } -} - -static void -pointer_surface_enter (void *data, - struct wl_surface *wl_surface, - struct wl_output *output) - -{ - GdkDevice *device = data; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandTabletData *tablet; - - GDK_SEAT_DEBUG (seat, EVENTS, - "pointer surface of seat %p entered output %p", - seat, output); - - tablet = gdk_wayland_seat_find_tablet (seat, device); - - if (tablet) - { - tablet->pointer_info.pointer_surface_outputs = - g_slist_append (tablet->pointer_info.pointer_surface_outputs, output); - } - else - { - seat->pointer_info.pointer_surface_outputs = - g_slist_append (seat->pointer_info.pointer_surface_outputs, output); - } - - pointer_surface_update_scale (device); -} - -static void -pointer_surface_leave (void *data, - struct wl_surface *wl_surface, - struct wl_output *output) -{ - GdkDevice *device = data; - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandTabletData *tablet; - - GDK_SEAT_DEBUG (seat, EVENTS, - "pointer surface of seat %p left output %p", - seat, output); - - tablet = gdk_wayland_seat_find_tablet (seat, device); - - if (tablet) - { - tablet->pointer_info.pointer_surface_outputs = - g_slist_remove (tablet->pointer_info.pointer_surface_outputs, output); - } - else - { - seat->pointer_info.pointer_surface_outputs = - g_slist_remove (seat->pointer_info.pointer_surface_outputs, output); - } - - pointer_surface_update_scale (device); -} - -static const struct wl_surface_listener pointer_surface_listener = { - pointer_surface_enter, - pointer_surface_leave -}; - -static void -gdk_wayland_pointer_data_finalize (GdkWaylandPointerData *pointer) -{ - g_clear_object (&pointer->focus); - g_clear_object (&pointer->cursor); - wl_surface_destroy (pointer->pointer_surface); - g_slist_free (pointer->pointer_surface_outputs); -} - -static void -gdk_wayland_seat_finalize (GObject *object) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (object); - GList *l; - - for (l = seat->tablet_tools; l != NULL; l = l->next) - _gdk_wayland_seat_remove_tool (seat, l->data); - - for (l = seat->tablet_pads; l != NULL; l = l->next) - _gdk_wayland_seat_remove_tablet_pad (seat, l->data); - - for (l = seat->tablets; l != NULL; l = l->next) - _gdk_wayland_seat_remove_tablet (seat, l->data); - - seat_handle_capabilities (seat, seat->wl_seat, 0); - g_object_unref (seat->keymap); - gdk_wayland_pointer_data_finalize (&seat->pointer_info); - /* FIXME: destroy data_device */ - g_clear_object (&seat->drag); - g_clear_object (&seat->drop); - g_clear_object (&seat->clipboard); - g_clear_object (&seat->primary_clipboard); - g_hash_table_destroy (seat->touches); - zwp_tablet_seat_v2_destroy (seat->wp_tablet_seat); - stop_key_repeat (seat); - - G_OBJECT_CLASS (gdk_wayland_seat_parent_class)->finalize (object); -} - -static GdkSeatCapabilities -gdk_wayland_seat_get_capabilities (GdkSeat *seat) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - GdkSeatCapabilities caps = 0; - - if (wayland_seat->logical_pointer) - caps |= GDK_SEAT_CAPABILITY_POINTER; - if (wayland_seat->logical_keyboard) - caps |= GDK_SEAT_CAPABILITY_KEYBOARD; - if (wayland_seat->logical_touch) - caps |= GDK_SEAT_CAPABILITY_TOUCH; - - return caps; -} - -static void -gdk_wayland_seat_set_grab_surface (GdkWaylandSeat *seat, - GdkSurface *surface) -{ - if (seat->grab_surface) - { - _gdk_wayland_surface_set_grab_seat (seat->grab_surface, NULL); - g_object_remove_weak_pointer (G_OBJECT (seat->grab_surface), - (gpointer *) &seat->grab_surface); - seat->grab_surface = NULL; - } - - if (surface) - { - seat->grab_surface = surface; - g_object_add_weak_pointer (G_OBJECT (surface), - (gpointer *) &seat->grab_surface); - _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (seat)); - } -} - -static GdkGrabStatus -gdk_wayland_seat_grab (GdkSeat *seat, - GdkSurface *surface, - GdkSeatCapabilities capabilities, - gboolean owner_events, - GdkCursor *cursor, - GdkEvent *event, - GdkSeatGrabPrepareFunc prepare_func, - gpointer prepare_func_data) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - guint32 evtime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME; - GdkDisplay *display = gdk_seat_get_display (seat); - GList *l; - - if (surface == NULL || GDK_SURFACE_DESTROYED (surface)) - return GDK_GRAB_NOT_VIEWABLE; - - gdk_wayland_seat_set_grab_surface (wayland_seat, surface); - wayland_seat->grab_time = evtime; - - if (prepare_func) - (prepare_func) (seat, surface, prepare_func_data); - - if (!gdk_wayland_surface_has_surface (surface)) - { - gdk_wayland_seat_set_grab_surface (wayland_seat, NULL); - return GDK_GRAB_NOT_VIEWABLE; - } - - if (wayland_seat->logical_pointer && - capabilities & GDK_SEAT_CAPABILITY_POINTER) - { - device_maybe_emit_grab_crossing (wayland_seat->logical_pointer, - surface, evtime); - - _gdk_display_add_device_grab (display, - wayland_seat->logical_pointer, - surface, - owner_events, - GDK_ALL_EVENTS_MASK, - _gdk_display_get_next_serial (display), - evtime, - FALSE); - - gdk_wayland_seat_set_global_cursor (seat, cursor); - g_set_object (&wayland_seat->cursor, cursor); - gdk_wayland_device_update_surface_cursor (wayland_seat->logical_pointer); - } - - if (wayland_seat->logical_touch && - capabilities & GDK_SEAT_CAPABILITY_TOUCH) - { - device_maybe_emit_grab_crossing (wayland_seat->logical_touch, - surface, evtime); - - _gdk_display_add_device_grab (display, - wayland_seat->logical_touch, - surface, - owner_events, - GDK_ALL_EVENTS_MASK, - _gdk_display_get_next_serial (display), - evtime, - FALSE); - } - - if (wayland_seat->logical_keyboard && - capabilities & GDK_SEAT_CAPABILITY_KEYBOARD) - { - device_maybe_emit_grab_crossing (wayland_seat->logical_keyboard, - surface, evtime); - - _gdk_display_add_device_grab (display, - wayland_seat->logical_keyboard, - surface, - owner_events, - GDK_ALL_EVENTS_MASK, - _gdk_display_get_next_serial (display), - evtime, - FALSE); - - /* Inhibit shortcuts if the seat grab is for the keyboard only */ - if (capabilities == GDK_SEAT_CAPABILITY_KEYBOARD) - gdk_wayland_surface_inhibit_shortcuts (surface, seat); - } - - if (wayland_seat->tablets && - capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS) - { - for (l = wayland_seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - - device_maybe_emit_grab_crossing (tablet->logical_device, - surface, - evtime); - - _gdk_display_add_device_grab (display, - tablet->logical_device, - surface, - owner_events, - GDK_ALL_EVENTS_MASK, - _gdk_display_get_next_serial (display), - evtime, - FALSE); - - gdk_wayland_device_update_surface_cursor (tablet->logical_device); - } - } - - return GDK_GRAB_SUCCESS; -} - -static void -gdk_wayland_seat_ungrab (GdkSeat *seat) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - GdkDisplay *display = gdk_seat_get_display (seat); - GdkDeviceGrabInfo *grab; - GList *l; - - g_clear_object (&wayland_seat->grab_cursor); - - gdk_wayland_seat_set_grab_surface (wayland_seat, NULL); - - if (wayland_seat->logical_pointer) - { - device_maybe_emit_ungrab_crossing (wayland_seat->logical_pointer, - GDK_CURRENT_TIME); - - gdk_wayland_device_update_surface_cursor (wayland_seat->logical_pointer); - } - - if (wayland_seat->logical_keyboard) - { - GdkSurface *prev_focus; - - prev_focus = device_maybe_emit_ungrab_crossing (wayland_seat->logical_keyboard, - GDK_CURRENT_TIME); - if (prev_focus) - gdk_wayland_surface_restore_shortcuts (prev_focus, seat); - } - - if (wayland_seat->logical_touch) - { - grab = _gdk_display_get_last_device_grab (display, wayland_seat->logical_touch); - - if (grab) - grab->serial_end = grab->serial_start; - } - - for (l = wayland_seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - - grab = _gdk_display_get_last_device_grab (display, tablet->logical_device); - - if (grab) - grab->serial_end = grab->serial_start; - } -} - -static GdkDevice * -gdk_wayland_seat_get_logical_device (GdkSeat *seat, - GdkSeatCapabilities capabilities) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - - if (capabilities == GDK_SEAT_CAPABILITY_POINTER) - return wayland_seat->logical_pointer; - else if (capabilities == GDK_SEAT_CAPABILITY_KEYBOARD) - return wayland_seat->logical_keyboard; - else if (capabilities == GDK_SEAT_CAPABILITY_TOUCH) - return wayland_seat->logical_touch; - - return NULL; -} - -static GList * -gdk_wayland_seat_get_devices (GdkSeat *seat, - GdkSeatCapabilities capabilities) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - GList *physical_devices = NULL; - - if (wayland_seat->finger_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) - physical_devices = g_list_prepend (physical_devices, wayland_seat->finger_scrolling); - if (wayland_seat->continuous_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) - physical_devices = g_list_prepend (physical_devices, wayland_seat->continuous_scrolling); - if (wayland_seat->wheel_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) - physical_devices = g_list_prepend (physical_devices, wayland_seat->wheel_scrolling); - if (wayland_seat->pointer && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) - physical_devices = g_list_prepend (physical_devices, wayland_seat->pointer); - if (wayland_seat->keyboard && (capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)) - physical_devices = g_list_prepend (physical_devices, wayland_seat->keyboard); - if (wayland_seat->touch && (capabilities & GDK_SEAT_CAPABILITY_TOUCH)) - physical_devices = g_list_prepend (physical_devices, wayland_seat->touch); - - if (wayland_seat->tablets && (capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS)) - { - GList *l; - - for (l = wayland_seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - - physical_devices = g_list_prepend (physical_devices, tablet->stylus_device); - } - } - - if (wayland_seat->tablet_pads && (capabilities & GDK_SEAT_CAPABILITY_TABLET_PAD)) - { - GList *l; - - for (l = wayland_seat->tablet_pads; l; l = l->next) - { - GdkWaylandTabletPadData *data = l->data; - physical_devices = g_list_prepend (physical_devices, data->device); - } - } - - return physical_devices; -} - -static GList * -gdk_wayland_seat_get_tools (GdkSeat *seat) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - GList *tools = NULL, *l; - - for (l = wayland_seat->tablet_tools; l; l = l->next) - { - GdkWaylandTabletToolData *tool = l->data; - - tools = g_list_prepend (tools, tool->tool); - } - - return tools; -} - -static void -gdk_wayland_seat_class_init (GdkWaylandSeatClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass); - - object_class->finalize = gdk_wayland_seat_finalize; - - seat_class->get_capabilities = gdk_wayland_seat_get_capabilities; - seat_class->grab = gdk_wayland_seat_grab; - seat_class->ungrab = gdk_wayland_seat_ungrab; - seat_class->get_logical_device = gdk_wayland_seat_get_logical_device; - seat_class->get_devices = gdk_wayland_seat_get_devices; - seat_class->get_tools = gdk_wayland_seat_get_tools; -} - -static void -gdk_wayland_seat_init (GdkWaylandSeat *seat) -{ -} - -static void -init_pointer_data (GdkWaylandPointerData *pointer_data, - GdkDisplay *display, - GdkDevice *logical_device) -{ - GdkWaylandDisplay *display_wayland; - - display_wayland = GDK_WAYLAND_DISPLAY (display); - - pointer_data->current_output_scale = 1; - pointer_data->pointer_surface = - wl_compositor_create_surface (display_wayland->compositor); - wl_surface_add_listener (pointer_data->pointer_surface, - &pointer_surface_listener, - logical_device); -} - -void -_gdk_wayland_display_create_seat (GdkWaylandDisplay *display_wayland, - guint32 id, - struct wl_seat *wl_seat) -{ - GdkDisplay *display = GDK_DISPLAY (display_wayland); - GdkWaylandSeat *seat; - - seat = g_object_new (GDK_TYPE_WAYLAND_SEAT, - "display", display_wayland, - NULL); - seat->id = id; - seat->keymap = _gdk_wayland_keymap_new (display); - seat->display = display; - seat->touches = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_free); - seat->wl_seat = wl_seat; - - wl_seat_add_listener (seat->wl_seat, &seat_listener, seat); - wl_seat_set_user_data (seat->wl_seat, seat); - - if (display_wayland->primary_selection_manager) - { - seat->primary_clipboard = gdk_wayland_primary_new (seat); - } - else - { - /* If the compositor doesn't support primary clipboard, - * just do it local-only */ - seat->primary_clipboard = gdk_clipboard_new (display); - } - - seat->data_device = - wl_data_device_manager_get_data_device (display_wayland->data_device_manager, - seat->wl_seat); - seat->clipboard = gdk_wayland_clipboard_new (display); - wl_data_device_add_listener (seat->data_device, - &data_device_listener, seat); - - init_devices (seat); - init_pointer_data (&seat->pointer_info, display, seat->logical_pointer); - - if (display_wayland->tablet_manager) - { - seat->wp_tablet_seat = - zwp_tablet_manager_v2_get_tablet_seat (display_wayland->tablet_manager, - wl_seat); - zwp_tablet_seat_v2_add_listener (seat->wp_tablet_seat, &tablet_seat_listener, - seat); - } - - if (display->clipboard == NULL) - display->clipboard = g_object_ref (seat->clipboard); - if (display->primary_clipboard == NULL) - display->primary_clipboard = g_object_ref (seat->primary_clipboard); - - gdk_display_add_seat (display, GDK_SEAT (seat)); -} - -void -_gdk_wayland_display_remove_seat (GdkWaylandDisplay *display_wayland, - guint32 id) -{ - GdkDisplay *display = GDK_DISPLAY (display_wayland); - GList *l, *seats; - - seats = gdk_display_list_seats (display); - - for (l = seats; l != NULL; l = l->next) - { - GdkWaylandSeat *seat = l->data; - - if (seat->id != id) - continue; - - gdk_display_remove_seat (display, GDK_SEAT (seat)); - break; - } - - g_list_free (seats); -} - -uint32_t -_gdk_wayland_seat_get_implicit_grab_serial (GdkSeat *seat, - GdkEvent *event) -{ - GdkEventSequence *sequence = NULL; - GdkWaylandTouchData *touch = NULL; - - if (event) - sequence = gdk_event_get_event_sequence (event); - - if (sequence) - touch = gdk_wayland_seat_get_touch (GDK_WAYLAND_SEAT (seat), - GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); - - if (touch) - return touch->touch_down_serial; - - if (event) - { - GdkDevice *source = gdk_event_get_device (event); - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - GList *l; - - for (l = wayland_seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - - if (tablet->stylus_device == source) - return tablet->pointer_info.press_serial; - } - } - - return GDK_WAYLAND_SEAT (seat)->pointer_info.press_serial; -} - -uint32_t -_gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat, - GdkEventSequence **sequence) -{ - GdkWaylandTouchData *touch; - GHashTableIter iter; - GList *l; - uint32_t serial; - - g_hash_table_iter_init (&iter, seat->touches); - - if (sequence) - *sequence = NULL; - - serial = seat->keyboard_key_serial; - - if (seat->pointer_info.press_serial > serial) - serial = seat->pointer_info.press_serial; - - for (l = seat->tablets; l; l = l->next) - { - GdkWaylandTabletData *tablet = l->data; - - if (tablet->pointer_info.press_serial > serial) - serial = tablet->pointer_info.press_serial; - } - - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) - { - if (touch->touch_down_serial > serial) - { - if (sequence) - *sequence = GDK_SLOT_TO_EVENT_SEQUENCE (touch->id); - serial = touch->touch_down_serial; - } - } - - return serial; -} - -void -gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device, - GdkEventSequence *sequence) -{ - GdkWaylandSeat *seat; - GdkWaylandTouchData *touch; - GdkEvent *event; - - g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); - touch = gdk_wayland_seat_get_touch (seat, - GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); - - if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch == touch) - { - GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL; - emulate_touch_crossing (touch->surface, NULL, - seat->logical_touch, seat->touch, - touch, GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, - GDK_CURRENT_TIME); - } - - event = gdk_touch_event_new (GDK_TOUCH_CANCEL, - GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), - touch->surface, - seat->logical_touch, - GDK_CURRENT_TIME, - device_get_modifiers (seat->logical_touch), - touch->x, touch->y, - NULL, - touch->initial_touch); - _gdk_wayland_display_deliver_event (seat->display, event); -} - -void -gdk_wayland_seat_set_global_cursor (GdkSeat *seat, - GdkCursor *cursor) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - GdkDevice *pointer; - - pointer = gdk_seat_get_pointer (seat); - - g_set_object (&wayland_seat->grab_cursor, cursor); - gdk_wayland_device_set_surface_cursor (pointer, - gdk_wayland_device_get_focus (pointer), - NULL); -} - -void -gdk_wayland_seat_set_drag (GdkSeat *seat, - GdkDrag *drag) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); - - g_set_object (&wayland_seat->drag, drag); -} - -/** - * gdk_wayland_device_get_data_device: (skip) - * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_data_device` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_data_device` - */ -struct wl_data_device * -gdk_wayland_device_get_data_device (GdkDevice *gdk_device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); - return seat->data_device; -} - -/** - * gdk_wayland_device_set_selection: (skip) - * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` - * @source: the data source for the selection - * - * Sets the selection of the `GdkDevice. - * - * This is calling wl_data_device_set_selection() on - * the `wl_data_device` of @gdk_device. - */ -void -gdk_wayland_device_set_selection (GdkDevice *gdk_device, - struct wl_data_source *source) -{ - GdkWaylandSeat *seat; - guint32 serial; - - g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); - serial = _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL); - wl_data_device_set_selection (seat->data_device, source, serial); -} - -/** - * gdk_wayland_seat_get_wl_seat: (skip) - * @seat: (type GdkWaylandSeat): a `GdkSeat` - * - * Returns the Wayland `wl_seat` of a `GdkSeat`. - * - * Returns: (transfer none): a Wayland `wl_seat` - */ -struct wl_seat * -gdk_wayland_seat_get_wl_seat (GdkSeat *seat) -{ - g_return_val_if_fail (GDK_IS_WAYLAND_SEAT (seat), NULL); - - return GDK_WAYLAND_SEAT (seat)->wl_seat; -} - -/** - * gdk_wayland_device_get_node_path: - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the `/dev/input/event*` path of this device. - * - * For `GdkDevice`s that possibly coalesce multiple hardware - * devices (eg. mouse, keyboard, touch,...), this function - * will return %NULL. - * - * This is most notably implemented for devices of type - * %GDK_SOURCE_PEN, %GDK_SOURCE_TABLET_PAD. - * - * Returns: (nullable) (transfer none): the `/dev/input/event*` - * path of this device - */ -const char * -gdk_wayland_device_get_node_path (GdkDevice *device) -{ - GdkWaylandTabletData *tablet; - GdkWaylandTabletPadData *pad; - - GdkSeat *seat; - - g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); - - seat = gdk_device_get_seat (device); - tablet = gdk_wayland_seat_find_tablet (GDK_WAYLAND_SEAT (seat), device); - if (tablet) - return tablet->path; - - pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); - if (pad) - return pad->path; - - return NULL; -} - -/* - * gdk_wayland_device_pad_set_feedback: - * @device: (type GdkWaylandDevice): a %GDK_SOURCE_TABLET_PAD device - * @feature: Feature to set the feedback label for - * @feature_idx: 0-indexed index of the feature to set the feedback label for - * @label: Feedback label - * - * Sets the feedback label for the given feature/index. - * - * This may be used by the compositor to provide user feedback - * of the actions available/performed. - */ -void -gdk_wayland_device_pad_set_feedback (GdkDevice *device, - GdkDevicePadFeature feature, - guint feature_idx, - const char *label) -{ - GdkWaylandTabletPadData *pad; - GdkWaylandTabletPadGroupData *group; - GdkSeat *seat; - - seat = gdk_device_get_seat (device); - pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); - if (!pad) - return; - - if (feature == GDK_DEVICE_PAD_FEATURE_BUTTON) - { - group = tablet_pad_lookup_button_group (pad, feature_idx); - if (!group) - return; - - zwp_tablet_pad_v2_set_feedback (pad->wp_tablet_pad, feature_idx, label, - group->mode_switch_serial); - } - else if (feature == GDK_DEVICE_PAD_FEATURE_RING) - { - struct zwp_tablet_pad_ring_v2 *wp_pad_ring; - - wp_pad_ring = g_list_nth_data (pad->rings, feature_idx); - if (!wp_pad_ring) - return; - - group = zwp_tablet_pad_ring_v2_get_user_data (wp_pad_ring); - zwp_tablet_pad_ring_v2_set_feedback (wp_pad_ring, label, - group->mode_switch_serial); - - } - else if (feature == GDK_DEVICE_PAD_FEATURE_STRIP) - { - struct zwp_tablet_pad_strip_v2 *wp_pad_strip; - - wp_pad_strip = g_list_nth_data (pad->strips, feature_idx); - if (!wp_pad_strip) - return; - - group = zwp_tablet_pad_strip_v2_get_user_data (wp_pad_strip); - zwp_tablet_pad_strip_v2_set_feedback (wp_pad_strip, label, - group->mode_switch_serial); - } -} diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c new file mode 100644 index 0000000000..90ecad458a --- /dev/null +++ b/gdk/wayland/gdkseat-wayland.c @@ -0,0 +1,5461 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2009 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkdevice-wayland-private.h" + +#include "gdkclipboard-wayland.h" +#include "gdkclipboardprivate.h" +#include "gdkcursorprivate.h" +#include "gdkdeviceprivate.h" +#include "gdkdevicepadprivate.h" +#include "gdkdevicetoolprivate.h" +#include "gdkdropprivate.h" +#include "gdkeventsprivate.h" +#include "gdkkeysprivate.h" +#include "gdkkeysyms.h" +#include "gdkprimary-wayland.h" +#include "gdkprivate-wayland.h" +#include "gdkseat-wayland.h" +#include "gdkseatprivate.h" +#include "gdksurfaceprivate.h" +#include "gdktypes.h" +#include "gdkwayland.h" +#include "gdkprivate.h" + +#include "pointer-gestures-unstable-v1-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" + +#include + +#include +#include +#include +#include +#include +#include +#if defined(HAVE_DEV_EVDEV_INPUT_H) +#include +#elif defined(HAVE_LINUX_INPUT_H) +#include +#endif + +/** + * GdkWaylandDevice: + * + * The Wayland implementation of `GdkDevice`. + * + * Beyond the regular [class@Gdk.Device] API, the Wayland implementation + * provides access to Wayland objects such as the `wl_seat` with + * [method@GdkWayland.WaylandDevice.get_wl_seat], the `wl_keyboard` with + * [method@GdkWayland.WaylandDevice.get_wl_keyboard] and the `wl_pointer` with + * [method@GdkWayland.WaylandDevice.get_wl_pointer]. + */ + +/** + * GdkWaylandSeat: + * + * The Wayland implementation of `GdkSeat`. + * + * Beyond the regular [class@Gdk.Seat] API, the Wayland implementation + * provides access to the Wayland `wl_seat` object with + * [method@GdkWayland.WaylandSeat.get_wl_seat]. + */ + +#define BUTTON_BASE (BTN_LEFT - 1) /* Used to translate to 1-indexed buttons */ + +#ifndef BTN_STYLUS3 +#define BTN_STYLUS3 0x149 /* Linux 4.15 */ +#endif + +#define ALL_BUTTONS_MASK (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | \ + GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | \ + GDK_BUTTON5_MASK) + +#define GDK_SEAT_DEBUG(seat,type,...) GDK_DISPLAY_DEBUG(gdk_seat_get_display (GDK_SEAT (seat)),type,__VA_ARGS__) + +typedef struct _GdkWaylandDevicePad GdkWaylandDevicePad; +typedef struct _GdkWaylandDevicePadClass GdkWaylandDevicePadClass; + +typedef struct _GdkWaylandTouchData GdkWaylandTouchData; +typedef struct _GdkWaylandPointerFrameData GdkWaylandPointerFrameData; +typedef struct _GdkWaylandPointerData GdkWaylandPointerData; +typedef struct _GdkWaylandTabletData GdkWaylandTabletData; +typedef struct _GdkWaylandTabletToolData GdkWaylandTabletToolData; +typedef struct _GdkWaylandTabletPadGroupData GdkWaylandTabletPadGroupData; +typedef struct _GdkWaylandTabletPadData GdkWaylandTabletPadData; + +struct _GdkWaylandTouchData +{ + uint32_t id; + double x; + double y; + GdkSurface *surface; + uint32_t touch_down_serial; + guint initial_touch : 1; +}; + +struct _GdkWaylandPointerFrameData +{ + GdkEvent *event; + + /* Specific to the scroll event */ + double delta_x, delta_y; + int32_t value120_x, value120_y; + gint8 is_scroll_stop; + enum wl_pointer_axis_source source; +}; + +struct _GdkWaylandPointerData { + GdkSurface *focus; + + double surface_x, surface_y; + + GdkModifierType button_modifiers; + + uint32_t time; + uint32_t enter_serial; + uint32_t press_serial; + + GdkSurface *grab_surface; + uint32_t grab_time; + + struct wl_surface *pointer_surface; + guint cursor_is_default: 1; + GdkCursor *cursor; + guint cursor_timeout_id; + guint cursor_image_index; + guint cursor_image_delay; + guint touchpad_event_sequence; + + guint current_output_scale; + GSList *pointer_surface_outputs; + + /* Accumulated event data for a pointer frame */ + GdkWaylandPointerFrameData frame; +}; + +struct _GdkWaylandTabletToolData +{ + GdkSeat *seat; + struct zwp_tablet_tool_v2 *wp_tablet_tool; + GdkAxisFlags axes; + GdkDeviceToolType type; + guint64 hardware_serial; + guint64 hardware_id_wacom; + + GdkDeviceTool *tool; + GdkWaylandTabletData *current_tablet; +}; + +struct _GdkWaylandTabletPadGroupData +{ + GdkWaylandTabletPadData *pad; + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group; + GList *rings; + GList *strips; + GList *buttons; + + guint mode_switch_serial; + guint n_modes; + guint current_mode; + + struct { + guint source; + gboolean is_stop; + double value; + } axis_tmp_info; +}; + +struct _GdkWaylandTabletPadData +{ + GdkSeat *seat; + struct zwp_tablet_pad_v2 *wp_tablet_pad; + GdkDevice *device; + + GdkWaylandTabletData *current_tablet; + + guint enter_serial; + uint32_t n_buttons; + char *path; + + GList *rings; + GList *strips; + GList *mode_groups; +}; + +struct _GdkWaylandTabletData +{ + struct zwp_tablet_v2 *wp_tablet; + char *name; + char *path; + uint32_t vid; + uint32_t pid; + + GdkDevice *logical_device; + GdkDevice *stylus_device; + GdkSeat *seat; + GdkWaylandPointerData pointer_info; + + GList *pads; + + GdkWaylandTabletToolData *current_tool; + + int axis_indices[GDK_AXIS_LAST]; + double axes[GDK_AXIS_LAST]; +}; + +struct _GdkWaylandSeat +{ + GdkSeat parent_instance; + + guint32 id; + struct wl_seat *wl_seat; + struct wl_pointer *wl_pointer; + struct wl_keyboard *wl_keyboard; + struct wl_touch *wl_touch; + struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe; + struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch; + struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold; + struct zwp_tablet_seat_v2 *wp_tablet_seat; + + GdkDisplay *display; + + GdkDevice *logical_pointer; + GdkDevice *logical_keyboard; + GdkDevice *pointer; + GdkDevice *wheel_scrolling; + GdkDevice *finger_scrolling; + GdkDevice *continuous_scrolling; + GdkDevice *keyboard; + GdkDevice *logical_touch; + GdkDevice *touch; + GdkCursor *cursor; + GdkKeymap *keymap; + + GHashTable *touches; + GList *tablets; + GList *tablet_tools; + GList *tablet_pads; + + GdkWaylandPointerData pointer_info; + GdkWaylandPointerData touch_info; + + GdkModifierType key_modifiers; + GdkSurface *keyboard_focus; + GdkSurface *grab_surface; + uint32_t grab_time; + gboolean have_server_repeat; + uint32_t server_repeat_rate; + uint32_t server_repeat_delay; + + struct wl_data_offer *pending_offer; + GdkContentFormatsBuilder *pending_builder; + GdkDragAction pending_source_actions; + GdkDragAction pending_action; + + struct wl_callback *repeat_callback; + guint32 repeat_timer; + guint32 repeat_key; + guint32 repeat_count; + gint64 repeat_deadline; + uint32_t keyboard_time; + uint32_t keyboard_key_serial; + + GdkClipboard *clipboard; + GdkClipboard *primary_clipboard; + struct wl_data_device *data_device; + GdkDrag *drag; + GdkDrop *drop; + + /* Some tracking on gesture events */ + guint gesture_n_fingers; + double gesture_scale; + + GdkCursor *grab_cursor; +}; + +G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT) + +struct _GdkWaylandDevice +{ + GdkDevice parent_instance; + GdkWaylandTouchData *emulating_touch; /* Only used on wd->logical_touch */ + GdkWaylandPointerData *pointer; +}; + +struct _GdkWaylandDeviceClass +{ + GdkDeviceClass parent_class; +}; + +G_DEFINE_TYPE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) + +struct _GdkWaylandDevicePad +{ + GdkWaylandDevice parent_instance; +}; + +struct _GdkWaylandDevicePadClass +{ + GdkWaylandDeviceClass parent_class; +}; + +static void gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface); +static void init_pointer_data (GdkWaylandPointerData *pointer_data, + GdkDisplay *display_wayland, + GdkDevice *logical_device); +static void pointer_surface_update_scale (GdkDevice *device); + +#define GDK_TYPE_WAYLAND_DEVICE_PAD (gdk_wayland_device_pad_get_type ()) +GType gdk_wayland_device_pad_get_type (void); + +G_DEFINE_TYPE_WITH_CODE (GdkWaylandDevicePad, gdk_wayland_device_pad, + GDK_TYPE_WAYLAND_DEVICE, + G_IMPLEMENT_INTERFACE (GDK_TYPE_DEVICE_PAD, + gdk_wayland_device_pad_iface_init)) + +#define GDK_SLOT_TO_EVENT_SEQUENCE(s) ((GdkEventSequence *) GUINT_TO_POINTER((s) + 1)) +#define GDK_EVENT_SEQUENCE_TO_SLOT(s) (GPOINTER_TO_UINT(s) - 1) + +static void deliver_key_event (GdkWaylandSeat *seat, + uint32_t time_, + uint32_t key, + uint32_t state, + gboolean from_key_repeat); + +static void +gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer) +{ + if (pointer->cursor_timeout_id > 0) + { + g_source_remove (pointer->cursor_timeout_id); + pointer->cursor_timeout_id = 0; + pointer->cursor_image_delay = 0; + } + + pointer->cursor_image_index = 0; +} + +static GdkWaylandTabletData * +gdk_wayland_seat_find_tablet (GdkWaylandSeat *seat, + GdkDevice *device) +{ + GList *l; + + for (l = seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + + if (tablet->logical_device == device || + tablet->stylus_device == device) + return tablet; + } + + return NULL; +} + +static GdkWaylandTabletPadData * +gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, + GdkDevice *device) +{ + GList *l; + + for (l = seat->tablet_pads; l; l = l->next) + { + GdkWaylandTabletPadData *pad = l->data; + + if (pad->device == device) + return pad; + } + + return NULL; +} + + +static gboolean +gdk_wayland_device_update_surface_cursor (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + struct wl_buffer *buffer; + int x, y, w, h, scale; + guint next_image_index, next_image_delay; + gboolean retval = G_SOURCE_REMOVE; + GdkWaylandTabletData *tablet; + + tablet = gdk_wayland_seat_find_tablet (seat, device); + + if (pointer->cursor) + { + buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display), + pointer->cursor, + pointer->current_output_scale, + pointer->cursor_image_index, + &x, &y, &w, &h, &scale); + } + else + { + pointer->cursor_timeout_id = 0; + return G_SOURCE_REMOVE; + } + + if (tablet) + { + if (!tablet->current_tool) + { + pointer->cursor_timeout_id = 0; + return G_SOURCE_REMOVE; + } + + zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool, + pointer->enter_serial, + pointer->pointer_surface, + x, y); + } + else if (seat->wl_pointer) + { + wl_pointer_set_cursor (seat->wl_pointer, + pointer->enter_serial, + pointer->pointer_surface, + x, y); + } + else + { + pointer->cursor_timeout_id = 0; + return G_SOURCE_REMOVE; + } + + if (buffer) + { + wl_surface_attach (pointer->pointer_surface, buffer, 0, 0); + wl_surface_set_buffer_scale (pointer->pointer_surface, scale); + wl_surface_damage (pointer->pointer_surface, 0, 0, w, h); + wl_surface_commit (pointer->pointer_surface); + } + else + { + wl_surface_attach (pointer->pointer_surface, NULL, 0, 0); + wl_surface_commit (pointer->pointer_surface); + } + + next_image_index = + _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display), + pointer->cursor, + pointer->current_output_scale, + pointer->cursor_image_index, + &next_image_delay); + + if (next_image_index != pointer->cursor_image_index) + { + if (next_image_delay != pointer->cursor_image_delay || + pointer->cursor_timeout_id == 0) + { + guint id; + GSource *source; + + gdk_wayland_pointer_stop_cursor_animation (pointer); + + /* Queue timeout for next frame */ + id = g_timeout_add (next_image_delay, + (GSourceFunc) gdk_wayland_device_update_surface_cursor, + device); + source = g_main_context_find_source_by_id (NULL, id); + g_source_set_static_name (source, "[gtk] gdk_wayland_device_update_surface_cursor"); + pointer->cursor_timeout_id = id; + } + else + retval = G_SOURCE_CONTINUE; + + pointer->cursor_image_index = next_image_index; + pointer->cursor_image_delay = next_image_delay; + } + else + gdk_wayland_pointer_stop_cursor_animation (pointer); + + return retval; +} + +static void +gdk_wayland_device_set_surface_cursor (GdkDevice *device, + GdkSurface *surface, + GdkCursor *cursor) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + + if (device == seat->logical_touch) + return; + + if (seat->grab_cursor) + cursor = seat->grab_cursor; + + if (pointer->cursor != NULL && + cursor != NULL && + gdk_cursor_equal (cursor, pointer->cursor)) + return; + + if (cursor == NULL) + { + if (!pointer->cursor_is_default) + { + g_clear_object (&pointer->cursor); + pointer->cursor = gdk_cursor_new_from_name ("default", NULL); + pointer->cursor_is_default = TRUE; + + gdk_wayland_pointer_stop_cursor_animation (pointer); + gdk_wayland_device_update_surface_cursor (device); + } + else + { + /* Nothing to do, we'already using the default cursor */ + } + } + else + { + g_set_object (&pointer->cursor, cursor); + pointer->cursor_is_default = FALSE; + + gdk_wayland_pointer_stop_cursor_animation (pointer); + gdk_wayland_device_update_surface_cursor (device); + } +} + +static GdkModifierType +device_get_modifiers (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkModifierType mask; + + mask = seat->key_modifiers; + + if (pointer) + mask |= pointer->button_modifiers; + + return mask; +} + +void +gdk_wayland_device_query_state (GdkDevice *device, + GdkSurface *surface, + double *win_x, + double *win_y, + GdkModifierType *mask) +{ + GdkWaylandPointerData *pointer; + double x, y; + + if (mask) + *mask = device_get_modifiers (device); + + pointer = GDK_WAYLAND_DEVICE (device)->pointer; + + if (pointer->focus == surface) + { + x = pointer->surface_x; + y = pointer->surface_y; + } + else + { + x = y = -1; + } + + if (win_x) + *win_x = x; + if (win_y) + *win_y = y; +} + +static void +emulate_crossing (GdkSurface *surface, + GdkSurface *child_surface, + GdkDevice *device, + GdkEventType type, + GdkCrossingMode mode, + guint32 time_) +{ + GdkEvent *event; + GdkModifierType state; + double x, y; + + gdk_surface_get_device_position (surface, device, &x, &y, &state); + event = gdk_crossing_event_new (type, + surface, + device, + time_, + state, + x, y, + mode, + GDK_NOTIFY_NONLINEAR); + + _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); +} + +static void +emulate_touch_crossing (GdkSurface *surface, + GdkSurface *child_surface, + GdkDevice *device, + GdkDevice *source, + GdkWaylandTouchData *touch, + GdkEventType type, + GdkCrossingMode mode, + guint32 time_) +{ + GdkEvent *event; + + event = gdk_crossing_event_new (type, + surface, + device, + time_, + 0, + touch->x, touch->y, + mode, + GDK_NOTIFY_NONLINEAR); + + _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); +} + +static void +emulate_focus (GdkSurface *surface, + GdkDevice *device, + gboolean focus_in, + guint32 time_) +{ + GdkEvent *event = gdk_focus_event_new (surface, device, focus_in); + + _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); +} + +static void +device_emit_grab_crossing (GdkDevice *device, + GdkSurface *from, + GdkSurface *to, + GdkCrossingMode mode, + guint32 time_) +{ + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + { + if (from) + emulate_focus (from, device, FALSE, time_); + if (to) + emulate_focus (to, device, TRUE, time_); + } + else + { + if (from) + emulate_crossing (from, to, device, GDK_LEAVE_NOTIFY, mode, time_); + if (to) + emulate_crossing (to, from, device, GDK_ENTER_NOTIFY, mode, time_); + } +} + +GdkSurface * +gdk_wayland_device_get_focus (GdkDevice *device) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandPointerData *pointer; + + if (device == wayland_seat->logical_keyboard) + return wayland_seat->keyboard_focus; + else + { + pointer = GDK_WAYLAND_DEVICE (device)->pointer; + + if (pointer) + return pointer->focus; + } + + return NULL; +} + +static void +device_maybe_emit_grab_crossing (GdkDevice *device, + GdkSurface *window, + guint32 time) +{ + GdkSurface *surface = gdk_wayland_device_get_focus (device); + GdkSurface *focus = window; + + if (focus != surface) + device_emit_grab_crossing (device, focus, window, GDK_CROSSING_GRAB, time); +} + +static GdkSurface* +device_maybe_emit_ungrab_crossing (GdkDevice *device, + guint32 time_) +{ + GdkDeviceGrabInfo *grab; + GdkSurface *focus = NULL; + GdkSurface *surface = NULL; + GdkSurface *prev_focus = NULL; + + focus = gdk_wayland_device_get_focus (device); + grab = _gdk_display_get_last_device_grab (gdk_device_get_display (device), device); + + if (grab) + { + prev_focus = grab->surface; + surface = grab->surface; + } + + if (focus != surface) + device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time_); + + return prev_focus; +} + +static GdkGrabStatus +gdk_wayland_device_grab (GdkDevice *device, + GdkSurface *surface, + gboolean owner_events, + GdkEventMask event_mask, + GdkSurface *confine_to, + GdkCursor *cursor, + guint32 time_) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + + if (GDK_IS_DRAG_SURFACE (surface) && + gdk_surface_get_mapped (surface)) + { + g_warning ("Surface %p is already mapped at the time of grabbing. " + "gdk_seat_grab() should be used to simultaneously grab input " + "and show this popup. You may find oddities ahead.", + surface); + } + + device_maybe_emit_grab_crossing (device, surface, time_); + + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + { + /* Device is a keyboard */ + gdk_wayland_surface_inhibit_shortcuts (surface, + gdk_device_get_seat (device)); + return GDK_GRAB_SUCCESS; + } + else + { + /* Device is a pointer */ + if (pointer->grab_surface != NULL && + time_ != 0 && pointer->grab_time > time_) + { + return GDK_GRAB_ALREADY_GRABBED; + } + + if (time_ == 0) + time_ = pointer->time; + + pointer->grab_surface = surface; + pointer->grab_time = time_; + _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (wayland_seat)); + + g_clear_object (&wayland_seat->cursor); + + if (cursor) + wayland_seat->cursor = g_object_ref (cursor); + + gdk_wayland_device_update_surface_cursor (device); + } + + return GDK_GRAB_SUCCESS; +} + +static void +gdk_wayland_device_ungrab (GdkDevice *device, + guint32 time_) +{ + GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkSurface *prev_focus; + + prev_focus = device_maybe_emit_ungrab_crossing (device, time_); + + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + { + /* Device is a keyboard */ + if (prev_focus) + gdk_wayland_surface_restore_shortcuts (prev_focus, + gdk_device_get_seat (device)); + } + else + { + /* Device is a pointer */ + gdk_wayland_device_update_surface_cursor (device); + + if (pointer->grab_surface) + _gdk_wayland_surface_set_grab_seat (pointer->grab_surface, + NULL); + } +} + +static GdkSurface * +gdk_wayland_device_surface_at_position (GdkDevice *device, + double *win_x, + double *win_y, + GdkModifierType *mask) +{ + GdkWaylandPointerData *pointer; + + pointer = GDK_WAYLAND_DEVICE(device)->pointer; + + if (!pointer) + return NULL; + + if (win_x) + *win_x = pointer->surface_x; + if (win_y) + *win_y = pointer->surface_y; + if (mask) + *mask = device_get_modifiers (device); + + return pointer->focus; +} + +static void +gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass) +{ + GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass); + + device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor; + device_class->grab = gdk_wayland_device_grab; + device_class->ungrab = gdk_wayland_device_ungrab; + device_class->surface_at_position = gdk_wayland_device_surface_at_position; +} + +static void +gdk_wayland_device_init (GdkWaylandDevice *device_core) +{ + GdkDevice *device; + + device = GDK_DEVICE (device_core); + + _gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1); + _gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1); +} + +static int +gdk_wayland_device_pad_get_n_groups (GdkDevicePad *pad) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadData *data; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); +#ifdef G_DISABLE_ASSERT + if (data == NULL) + return 0; +#else + g_assert (data != NULL); +#endif + + return g_list_length (data->mode_groups); +} + +static int +gdk_wayland_device_pad_get_group_n_modes (GdkDevicePad *pad, + int n_group) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadGroupData *group; + GdkWaylandTabletPadData *data; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); +#ifdef G_DISABLE_ASSERT + if (data == NULL) + return 0; +#else + g_assert (data != NULL); +#endif + + group = g_list_nth_data (data->mode_groups, n_group); + if (!group) + return -1; + + return group->n_modes; +} + +static int +gdk_wayland_device_pad_get_n_features (GdkDevicePad *pad, + GdkDevicePadFeature feature) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadData *data; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); + g_assert (data != NULL); + + switch (feature) + { + case GDK_DEVICE_PAD_FEATURE_BUTTON: + return data->n_buttons; + case GDK_DEVICE_PAD_FEATURE_RING: + return g_list_length (data->rings); + case GDK_DEVICE_PAD_FEATURE_STRIP: + return g_list_length (data->strips); + default: + return -1; + } +} + +static int +gdk_wayland_device_pad_get_feature_group (GdkDevicePad *pad, + GdkDevicePadFeature feature, + int idx) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadGroupData *group; + GdkWaylandTabletPadData *data; + GList *l; + int i; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); +#ifdef G_DISABLE_ASSERT + if (data == NULL) + return -1; +#else + g_assert (data != NULL); +#endif + + for (l = data->mode_groups, i = 0; l; l = l->next, i++) + { + group = l->data; + + switch (feature) + { + case GDK_DEVICE_PAD_FEATURE_BUTTON: + if (g_list_find (group->buttons, GINT_TO_POINTER (idx))) + return i; + break; + case GDK_DEVICE_PAD_FEATURE_RING: + { + gpointer ring; + + ring = g_list_nth_data (data->rings, idx); + if (ring && g_list_find (group->rings, ring)) + return i; + break; + } + case GDK_DEVICE_PAD_FEATURE_STRIP: + { + gpointer strip; + strip = g_list_nth_data (data->strips, idx); + if (strip && g_list_find (group->strips, strip)) + return i; + break; + } + default: + break; + } + } + + return -1; +} + +static void +gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface) +{ + iface->get_n_groups = gdk_wayland_device_pad_get_n_groups; + iface->get_group_n_modes = gdk_wayland_device_pad_get_group_n_modes; + iface->get_n_features = gdk_wayland_device_pad_get_n_features; + iface->get_feature_group = gdk_wayland_device_pad_get_feature_group; +} + +static void +gdk_wayland_device_pad_class_init (GdkWaylandDevicePadClass *klass) +{ +} + +static void +gdk_wayland_device_pad_init (GdkWaylandDevicePad *pad) +{ +} + +/** + * gdk_wayland_device_get_wl_seat: (skip) + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_seat` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_seat` + */ +struct wl_seat * +gdk_wayland_device_get_wl_seat (GdkDevice *device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->wl_seat; +} + +/** + * gdk_wayland_device_get_wl_pointer: (skip) + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_pointer` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_pointer` + */ +struct wl_pointer * +gdk_wayland_device_get_wl_pointer (GdkDevice *device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->wl_pointer; +} + +/** + * gdk_wayland_device_get_wl_keyboard: (skip) + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_keyboard` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_keyboard` + */ +struct wl_keyboard * +gdk_wayland_device_get_wl_keyboard (GdkDevice *device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->wl_keyboard; +} + +/** + * gdk_wayland_device_get_xkb_keymap: + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the `xkb_keymap` of a `GdkDevice`. + * + * Returns: (transfer none): a `struct xkb_keymap` + * + * Since: 4.4 + */ +struct xkb_keymap * +gdk_wayland_device_get_xkb_keymap (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return _gdk_wayland_keymap_get_xkb_keymap (seat->keymap); +} + +GdkKeymap * +_gdk_wayland_device_get_keymap (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->keymap; +} + +static void +gdk_wayland_seat_discard_pending_offer (GdkWaylandSeat *seat) +{ + if (seat->pending_builder) + { + GdkContentFormats *ignore = gdk_content_formats_builder_free_to_formats (seat->pending_builder); + gdk_content_formats_unref (ignore); + seat->pending_builder = NULL; + } + g_clear_pointer (&seat->pending_offer, wl_data_offer_destroy); + seat->pending_source_actions = 0; + seat->pending_action = 0; +} + +static inline GdkDragAction +gdk_wayland_actions_to_gdk_actions (uint32_t dnd_actions) +{ + GdkDragAction actions = 0; + + if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) + actions |= GDK_ACTION_COPY; + if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) + actions |= GDK_ACTION_MOVE; + if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) + actions |= GDK_ACTION_ASK; + + return actions; +} + +static void +data_offer_offer (void *data, + struct wl_data_offer *offer, + const char *type) +{ + GdkWaylandSeat *seat = data; + + if (seat->pending_offer != offer) + { + GDK_SEAT_DEBUG (seat, EVENTS, + "%p: offer for unknown offer %p of %s", + seat, offer, type); + return; + } + + /* skip magic mime types */ + if (g_str_equal (type, GDK_WAYLAND_LOCAL_DND_MIME_TYPE)) + return; + + gdk_content_formats_builder_add_mime_type (seat->pending_builder, type); +} + +static void +data_offer_source_actions (void *data, + struct wl_data_offer *offer, + uint32_t source_actions) +{ + GdkWaylandSeat *seat = data; + + if (offer == seat->pending_offer) + { + seat->pending_source_actions = gdk_wayland_actions_to_gdk_actions (source_actions); + return; + } + + if (seat->drop == NULL) + return; + + gdk_wayland_drop_set_source_actions (seat->drop, source_actions); + + gdk_drop_emit_motion_event (seat->drop, + FALSE, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + GDK_CURRENT_TIME); +} + +static void +data_offer_action (void *data, + struct wl_data_offer *offer, + uint32_t action) +{ + GdkWaylandSeat *seat = data; + + if (offer == seat->pending_offer) + { + seat->pending_action = gdk_wayland_actions_to_gdk_actions (action); + return; + } + + if (seat->drop == NULL) + return; + + gdk_wayland_drop_set_action (seat->drop, action); + + gdk_drop_emit_motion_event (seat->drop, + FALSE, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + GDK_CURRENT_TIME); +} + +static const struct wl_data_offer_listener data_offer_listener = { + data_offer_offer, + data_offer_source_actions, + data_offer_action +}; + +static void +data_device_data_offer (void *data, + struct wl_data_device *data_device, + struct wl_data_offer *offer) +{ + GdkWaylandSeat *seat = data; + + GDK_SEAT_DEBUG (seat, EVENTS, + "data device data offer, data device %p, offer %p", + data_device, offer); + + gdk_wayland_seat_discard_pending_offer (seat); + + seat->pending_offer = offer; + wl_data_offer_add_listener (offer, + &data_offer_listener, + seat); + + seat->pending_builder = gdk_content_formats_builder_new (); + seat->pending_source_actions = 0; + seat->pending_action = 0; +} + +static void +data_device_enter (void *data, + struct wl_data_device *data_device, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer *offer) +{ + GdkWaylandSeat *seat = data; + GdkSurface *dest_surface; + GdkContentFormats *formats; + int origin_x, origin_y; + GdkDevice *device; + + dest_surface = wl_surface_get_user_data (surface); + + if (!GDK_IS_SURFACE (dest_surface)) + return; + + if (offer != seat->pending_offer) + { + GDK_SEAT_DEBUG (seat, EVENTS, + "%p: enter event for unknown offer %p, expected %p", + seat, offer, seat->pending_offer); + return; + } + + GDK_SEAT_DEBUG (seat, EVENTS, + "data device enter, data device %p serial %u, surface %p, x %f y %f, offer %p", + data_device, serial, surface, wl_fixed_to_double (x), wl_fixed_to_double (y), offer); + + /* Update pointer state, so device state queries work during DnD */ + seat->pointer_info.focus = g_object_ref (dest_surface); + seat->pointer_info.surface_x = wl_fixed_to_double (x); + seat->pointer_info.surface_y = wl_fixed_to_double (y); + + if (seat->logical_pointer) + device = seat->logical_pointer; + else if (seat->logical_touch) + device = seat->logical_touch; + else + { + g_warning ("No device for DND enter, ignoring."); + return; + } + + formats = gdk_content_formats_builder_free_to_formats (seat->pending_builder); + seat->pending_builder = NULL; + seat->pending_offer = NULL; + + seat->drop = gdk_wayland_drop_new (device, seat->drag, formats, dest_surface, offer, serial); + gdk_wayland_drop_set_source_actions (seat->drop, seat->pending_source_actions); + gdk_wayland_drop_set_action (seat->drop, seat->pending_action); + + gdk_content_formats_unref (formats); + + gdk_wayland_seat_discard_pending_offer (seat); + + gdk_surface_get_origin (gdk_drop_get_surface (seat->drop), &origin_x, &origin_y); + + gdk_drop_emit_enter_event (seat->drop, + FALSE, + origin_x + seat->pointer_info.surface_x, + origin_y + seat->pointer_info.surface_y, + GDK_CURRENT_TIME); +} + +static void +data_device_leave (void *data, + struct wl_data_device *data_device) +{ + GdkWaylandSeat *seat = data; + + GDK_SEAT_DEBUG (seat, EVENTS, + "data device leave, data device %p", data_device); + + if (seat->drop == NULL) + return; + + g_object_unref (seat->pointer_info.focus); + seat->pointer_info.focus = NULL; + + gdk_drop_emit_leave_event (seat->drop, + FALSE, + GDK_CURRENT_TIME); + + g_clear_object (&seat->drop); +} + +static void +data_device_motion (void *data, + struct wl_data_device *data_device, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) +{ + GdkWaylandSeat *seat = data; + int origin_x, origin_y; + + GDK_SEAT_DEBUG (seat, EVENTS, + "data device motion, data_device = %p, time = %d, x = %f, y = %f", + data_device, time, wl_fixed_to_double (x), wl_fixed_to_double (y)); + + if (seat->drop == NULL) + return; + + /* Update pointer state, so device state queries work during DnD */ + seat->pointer_info.surface_x = wl_fixed_to_double (x); + seat->pointer_info.surface_y = wl_fixed_to_double (y); + + gdk_surface_get_origin (gdk_drop_get_surface (seat->drop), &origin_x, &origin_y); + + gdk_drop_emit_motion_event (seat->drop, + FALSE, + origin_x + seat->pointer_info.surface_x, + origin_y + seat->pointer_info.surface_y, + time); +} + +static void +data_device_drop (void *data, + struct wl_data_device *data_device) +{ + GdkWaylandSeat *seat = data; + int origin_x, origin_y; + + GDK_SEAT_DEBUG (seat, EVENTS, + "data device drop, data device %p", data_device); + + gdk_surface_get_origin (gdk_drop_get_surface (seat->drop), &origin_x, &origin_y); + + gdk_drop_emit_drop_event (seat->drop, + FALSE, + origin_x + seat->pointer_info.surface_x, + origin_y + seat->pointer_info.surface_y, + GDK_CURRENT_TIME); +} + +static void +data_device_selection (void *data, + struct wl_data_device *wl_data_device, + struct wl_data_offer *offer) +{ + GdkWaylandSeat *seat = data; + GdkContentFormats *formats; + + if (offer) + { + if (offer == seat->pending_offer) + { + formats = gdk_content_formats_builder_free_to_formats (seat->pending_builder); + seat->pending_builder = NULL; + seat->pending_offer = NULL; + } + else + { + formats = gdk_content_formats_new (NULL, 0); + offer = NULL; + } + + gdk_wayland_seat_discard_pending_offer (seat); + } + else + { + formats = gdk_content_formats_new (NULL, 0); + } + + gdk_wayland_clipboard_claim_remote (GDK_WAYLAND_CLIPBOARD (seat->clipboard), + offer, + formats); +} + +static const struct wl_data_device_listener data_device_listener = { + data_device_data_offer, + data_device_enter, + data_device_leave, + data_device_motion, + data_device_drop, + data_device_selection +}; + +static GdkDevice * get_scroll_device (GdkWaylandSeat *seat, + enum wl_pointer_axis_source source); + +static void +flush_discrete_scroll_event (GdkWaylandSeat *seat, + gint value120_x, + gint value120_y) +{ + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); + GdkEvent *event = NULL; + GdkDevice *source; + GdkScrollDirection direction; + + if (value120_x > 0) + direction = GDK_SCROLL_LEFT; + else if (value120_x < 0) + direction = GDK_SCROLL_RIGHT; + else if (value120_y > 0) + direction = GDK_SCROLL_DOWN; + else + direction = GDK_SCROLL_UP; + + source = get_scroll_device (seat, seat->pointer_info.frame.source); + + if (display_wayland->seat_version >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION) + { + event = gdk_scroll_event_new_value120 (seat->pointer_info.focus, + source, + NULL, + seat->pointer_info.time, + device_get_modifiers (seat->logical_pointer), + direction, + value120_x, + value120_y); + } + else + { + gint discrete_x = value120_x / 120; + gint discrete_y = value120_y / 120; + + if (discrete_x != 0 || discrete_y != 0) + { + event = gdk_scroll_event_new_discrete (seat->pointer_info.focus, + source, + NULL, + seat->pointer_info.time, + device_get_modifiers (seat->logical_pointer), + direction); + } + } + + if (event) + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +flush_smooth_scroll_event (GdkWaylandSeat *seat, + double delta_x, + double delta_y, + gboolean is_stop) +{ + GdkEvent *event; + GdkDevice *source; + + source = get_scroll_device (seat, seat->pointer_info.frame.source); + event = gdk_scroll_event_new (seat->pointer_info.focus, + source, + NULL, + seat->pointer_info.time, + device_get_modifiers (seat->logical_pointer), + delta_x, delta_y, + is_stop, + GDK_SCROLL_UNIT_SURFACE); + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +flush_scroll_event (GdkWaylandSeat *seat, + GdkWaylandPointerFrameData *pointer_frame) +{ + gboolean is_stop = FALSE; + + if (pointer_frame->value120_x || pointer_frame->value120_y) + { + flush_discrete_scroll_event (seat, + pointer_frame->value120_x, + pointer_frame->value120_y); + pointer_frame->value120_x = 0; + pointer_frame->value120_y = 0; + } + else if (pointer_frame->is_scroll_stop || + pointer_frame->delta_x != 0 || + pointer_frame->delta_y != 0) + { + /* Axes can stop independently, if we stop on one axis but have a + * delta on the other, we don't count it as a stop event. + */ + if (pointer_frame->is_scroll_stop && + pointer_frame->delta_x == 0 && + pointer_frame->delta_y == 0) + is_stop = TRUE; + + flush_smooth_scroll_event (seat, + pointer_frame->delta_x, + pointer_frame->delta_y, + is_stop); + } + + pointer_frame->value120_x = 0; + pointer_frame->value120_y = 0; + pointer_frame->delta_x = 0; + pointer_frame->delta_y = 0; + pointer_frame->is_scroll_stop = FALSE; +} + +static void +gdk_wayland_seat_flush_frame_event (GdkWaylandSeat *seat) +{ + if (seat->pointer_info.frame.event) + { + _gdk_wayland_display_deliver_event (gdk_seat_get_display (GDK_SEAT (seat)), + seat->pointer_info.frame.event); + seat->pointer_info.frame.event = NULL; + } + else + { + flush_scroll_event (seat, &seat->pointer_info.frame); + seat->pointer_info.frame.source = 0; + } +} + +static void +gdk_wayland_seat_set_frame_event (GdkWaylandSeat *seat, + GdkEvent *event) +{ + if (seat->pointer_info.frame.event && + gdk_event_get_event_type (seat->pointer_info.frame.event) != gdk_event_get_event_type (event)) + gdk_wayland_seat_flush_frame_event (seat); + + seat->pointer_info.frame.event = event; +} + +static void +pointer_handle_enter (void *data, + struct wl_pointer *pointer, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t sx, + wl_fixed_t sy) +{ + GdkWaylandSeat *seat = data; + GdkEvent *event; + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); + + if (!surface) + return; + + if (!GDK_IS_SURFACE (wl_surface_get_user_data (surface))) + return; + + seat->pointer_info.focus = wl_surface_get_user_data (surface); + g_object_ref (seat->pointer_info.focus); + + seat->pointer_info.button_modifiers = 0; + + seat->pointer_info.surface_x = wl_fixed_to_double (sx); + seat->pointer_info.surface_y = wl_fixed_to_double (sy); + seat->pointer_info.enter_serial = serial; + + event = gdk_crossing_event_new (GDK_ENTER_NOTIFY, + seat->pointer_info.focus, + seat->logical_pointer, + 0, + 0, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + GDK_CROSSING_NORMAL, + GDK_NOTIFY_NONLINEAR); + gdk_wayland_seat_set_frame_event (seat, event); + + gdk_wayland_device_update_surface_cursor (seat->logical_pointer); + + GDK_SEAT_DEBUG (seat, EVENTS, + "enter, seat %p surface %p", + seat, seat->pointer_info.focus); + + if (display_wayland->seat_version < WL_POINTER_HAS_FRAME) + gdk_wayland_seat_flush_frame_event (seat); +} + +static void +pointer_handle_leave (void *data, + struct wl_pointer *pointer, + uint32_t serial, + struct wl_surface *surface) +{ + GdkWaylandSeat *seat = data; + GdkEvent *event; + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); + GdkDeviceGrabInfo *grab; + + if (!seat->pointer_info.focus) + return; + + grab = _gdk_display_get_last_device_grab (seat->display, + seat->logical_pointer); + + if (seat->pointer_info.button_modifiers != 0 && + grab && grab->implicit) + { + gulong display_serial; + + display_serial = _gdk_display_get_next_serial (seat->display); + _gdk_display_end_device_grab (seat->display, seat->logical_pointer, + display_serial, NULL, TRUE); + _gdk_display_device_grab_update (seat->display, + seat->logical_pointer, + display_serial); + } + + event = gdk_crossing_event_new (GDK_LEAVE_NOTIFY, + seat->pointer_info.focus, + seat->logical_pointer, + 0, + 0, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + GDK_CROSSING_NORMAL, + GDK_NOTIFY_NONLINEAR); + gdk_wayland_seat_set_frame_event (seat, event); + + gdk_wayland_device_update_surface_cursor (seat->logical_pointer); + + GDK_SEAT_DEBUG (seat, EVENTS, + "leave, seat %p surface %p", + seat, seat->pointer_info.focus); + + g_object_unref (seat->pointer_info.focus); + seat->pointer_info.focus = NULL; + if (seat->cursor) + gdk_wayland_pointer_stop_cursor_animation (&seat->pointer_info); + + if (display_wayland->seat_version < WL_POINTER_HAS_FRAME) + gdk_wayland_seat_flush_frame_event (seat); +} + +static void +pointer_handle_motion (void *data, + struct wl_pointer *pointer, + uint32_t time, + wl_fixed_t sx, + wl_fixed_t sy) +{ + GdkWaylandSeat *seat = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); + GdkEvent *event; + + if (!seat->pointer_info.focus) + return; + + seat->pointer_info.time = time; + seat->pointer_info.surface_x = wl_fixed_to_double (sx); + seat->pointer_info.surface_y = wl_fixed_to_double (sy); + + event = gdk_motion_event_new (seat->pointer_info.focus, + seat->logical_pointer, + NULL, + time, + device_get_modifiers (seat->logical_pointer), + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + NULL); + gdk_wayland_seat_set_frame_event (seat, event); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double x, y; + gdk_event_get_position (event, &x, &y); + g_message ("motion %f %f, seat %p state %d", + x, y, seat, gdk_event_get_modifier_state (event)); + } + + if (display->seat_version < WL_POINTER_HAS_FRAME) + gdk_wayland_seat_flush_frame_event (seat); +} + +static void +pointer_handle_button (void *data, + struct wl_pointer *pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + GdkWaylandSeat *seat = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); + GdkEvent *event; + uint32_t modifier; + int gdk_button; + + if (!seat->pointer_info.focus) + return; + + switch (button) + { + case BTN_LEFT: + gdk_button = GDK_BUTTON_PRIMARY; + break; + case BTN_MIDDLE: + gdk_button = GDK_BUTTON_MIDDLE; + break; + case BTN_RIGHT: + gdk_button = GDK_BUTTON_SECONDARY; + break; + default: + /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */ + gdk_button = button - BUTTON_BASE + 4; + break; + } + + seat->pointer_info.time = time; + if (state) + seat->pointer_info.press_serial = serial; + + event = gdk_button_event_new (state ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE, + seat->pointer_info.focus, + seat->logical_pointer, + NULL, + time, + device_get_modifiers (seat->logical_pointer), + gdk_button, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + NULL); + + gdk_wayland_seat_set_frame_event (seat, event); + + switch (button) + { + case BTN_RIGHT: + modifier = GDK_BUTTON3_MASK; + break; + case BTN_MIDDLE: + modifier = GDK_BUTTON2_MASK; + break; + default: + modifier = (GDK_BUTTON1_MASK << (button - BUTTON_BASE - 1)) & ALL_BUTTONS_MASK; + break; + } + + if (state) + seat->pointer_info.button_modifiers |= modifier; + else + seat->pointer_info.button_modifiers &= ~modifier; + + GDK_SEAT_DEBUG (seat, EVENTS, + "button %d %s, seat %p state %d", + gdk_button_event_get_button (event), + state ? "press" : "release", + seat, + gdk_event_get_modifier_state (event)); + + if (display->seat_version < WL_POINTER_HAS_FRAME) + gdk_wayland_seat_flush_frame_event (seat); +} + +#ifdef G_ENABLE_DEBUG + +static const char * +get_axis_name (uint32_t axis) +{ + switch (axis) + { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + return "horizontal"; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + return "vertical"; + default: + return "unknown"; + } +} + +#endif + +static void +pointer_handle_axis (void *data, + struct wl_pointer *pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + GdkWaylandSeat *seat = data; + GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); + + if (!seat->pointer_info.focus) + return; + + /* get the delta and convert it into the expected range */ + switch (axis) + { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + pointer_frame->delta_y = wl_fixed_to_double (value); + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + pointer_frame->delta_x = wl_fixed_to_double (value); + break; + default: + g_return_if_reached (); + } + + seat->pointer_info.time = time; + + GDK_SEAT_DEBUG (seat, EVENTS, + "scroll, axis %s, value %f, seat %p", + get_axis_name (axis), wl_fixed_to_double (value), + seat); + + if (display->seat_version < WL_POINTER_HAS_FRAME) + gdk_wayland_seat_flush_frame_event (seat); +} + +static void +pointer_handle_frame (void *data, + struct wl_pointer *pointer) +{ + GdkWaylandSeat *seat = data; + + GDK_SEAT_DEBUG (seat, EVENTS, "frame, seat %p", seat); + + gdk_wayland_seat_flush_frame_event (seat); +} + +#ifdef G_ENABLE_DEBUG + +static const char * +get_axis_source_name (enum wl_pointer_axis_source source) +{ + switch (source) + { + case WL_POINTER_AXIS_SOURCE_WHEEL: + return "wheel"; + case WL_POINTER_AXIS_SOURCE_FINGER: + return "finger"; + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: + return "continuous"; + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: + return "wheel-tilt"; + default: + return "unknown"; + } +} + +#endif + +static void +pointer_handle_axis_source (void *data, + struct wl_pointer *pointer, + enum wl_pointer_axis_source source) +{ + GdkWaylandSeat *seat = data; + GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; + + if (!seat->pointer_info.focus) + return; + + pointer_frame->source = source; + + GDK_SEAT_DEBUG (seat, EVENTS, + "axis source %s, seat %p", get_axis_source_name (source), seat); +} + +static void +pointer_handle_axis_stop (void *data, + struct wl_pointer *pointer, + uint32_t time, + uint32_t axis) +{ + GdkWaylandSeat *seat = data; + GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; + + if (!seat->pointer_info.focus) + return; + + seat->pointer_info.time = time; + + switch (axis) + { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + pointer_frame->delta_y = 0; + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + pointer_frame->delta_x = 0; + break; + default: + g_return_if_reached (); + } + + pointer_frame->is_scroll_stop = TRUE; + + GDK_SEAT_DEBUG (seat, EVENTS, + "axis %s stop, seat %p", get_axis_name (axis), seat); +} + +static void +pointer_handle_axis_discrete (void *data, + struct wl_pointer *pointer, + uint32_t axis, + int32_t value) +{ + GdkWaylandSeat *seat = data; + GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; + + if (!seat->pointer_info.focus) + return; + + switch (axis) + { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + pointer_frame->value120_y = value * 120; + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + pointer_frame->value120_x = value * 120; + break; + default: + g_return_if_reached (); + } + + GDK_SEAT_DEBUG (seat, EVENTS, + "discrete scroll, axis %s, value %d, seat %p", + get_axis_name (axis), value, seat); +} + +static void +pointer_handle_axis_value120 (void *data, + struct wl_pointer *pointer, + uint32_t axis, + int32_t value) +{ + GdkWaylandSeat *seat = data; + GdkWaylandPointerFrameData *pointer_frame = &seat->pointer_info.frame; + + if (!seat->pointer_info.focus) + return; + + switch (axis) + { + case WL_POINTER_AXIS_VERTICAL_SCROLL: + pointer_frame->value120_y = value; + break; + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + pointer_frame->value120_x = value; + break; + default: + g_return_if_reached (); + } + + GDK_SEAT_DEBUG (seat, EVENTS, + "value120 scroll, axis %s, value %d, seat %p", + get_axis_name (axis), value, seat); +} + +static int +get_active_layout (GdkKeymap *keymap) +{ + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + + xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap); + xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); + + for (int i = 0; i < xkb_keymap_num_layouts (xkb_keymap); i++) + { + if (xkb_state_layout_index_is_active (xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) + return i; + } + + return -1; +} + +#ifdef G_ENABLE_DEBUG +static const char * +get_active_layout_name (GdkKeymap *keymap) +{ + struct xkb_keymap *xkb_keymap; + + xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap); + + return xkb_keymap_layout_get_name (xkb_keymap, get_active_layout (keymap)); +} +#endif + +static void +keyboard_handle_keymap (void *data, + struct wl_keyboard *keyboard, + uint32_t format, + int fd, + uint32_t size) +{ + GdkWaylandSeat *seat = data; + PangoDirection direction; + gboolean bidi; + gboolean caps_lock; + gboolean num_lock; + gboolean scroll_lock; + GdkModifierType modifiers; + + direction = gdk_keymap_get_direction (seat->keymap); + bidi = gdk_keymap_have_bidi_layouts (seat->keymap); + caps_lock = gdk_keymap_get_caps_lock_state (seat->keymap); + num_lock = gdk_keymap_get_num_lock_state (seat->keymap); + scroll_lock = gdk_keymap_get_scroll_lock_state (seat->keymap); + modifiers = gdk_keymap_get_modifier_state (seat->keymap); + + _gdk_wayland_keymap_update_from_fd (seat->keymap, format, fd, size); + +#ifdef G_ENABLE_DEBUG + if (GDK_DISPLAY_DEBUG_CHECK (seat->keymap->display, INPUT)) + { + GString *s = g_string_new (""); + struct xkb_keymap *xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (seat->keymap); + struct xkb_state *xkb_state = _gdk_wayland_keymap_get_xkb_state (seat->keymap); + for (int i = 0; i < xkb_keymap_num_layouts (xkb_keymap); i++) + { + if (s->len > 0) + g_string_append (s, ", "); + if (xkb_state_layout_index_is_active (xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) + g_string_append (s, "*"); + g_string_append (s, xkb_keymap_layout_get_name (xkb_keymap, i)); + } + gdk_debug_message ("layouts: %s", s->str); + g_string_free (s, TRUE); + } +#endif + + g_signal_emit_by_name (seat->keymap, "keys-changed"); + g_signal_emit_by_name (seat->keymap, "state-changed"); + if (direction != gdk_keymap_get_direction (seat->keymap)) + g_signal_emit_by_name (seat->keymap, "direction-changed"); + + if (direction != gdk_keymap_get_direction (seat->keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "direction"); + if (bidi != gdk_keymap_have_bidi_layouts (seat->keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "has-bidi-layouts"); + if (caps_lock != gdk_keymap_get_caps_lock_state (seat->keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "caps-lock-state"); + if (num_lock != gdk_keymap_get_num_lock_state (seat->keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "num-lock-state"); + if (scroll_lock != gdk_keymap_get_scroll_lock_state (seat->keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "scroll-lock-state"); + if (modifiers != gdk_keymap_get_modifier_state (seat->keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "modifier-state"); +} + +static void +keyboard_handle_enter (void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + struct wl_surface *surface, + struct wl_array *keys) +{ + GdkWaylandSeat *seat = data; + GdkEvent *event; + + if (!surface) + return; + + if (!GDK_IS_SURFACE (wl_surface_get_user_data (surface))) + return; + + seat->keyboard_focus = wl_surface_get_user_data (surface); + g_object_ref (seat->keyboard_focus); + seat->repeat_key = 0; + + event = gdk_focus_event_new (seat->keyboard_focus, + seat->logical_keyboard, + TRUE); + + GDK_SEAT_DEBUG (seat, EVENTS, + "focus in, seat %p surface %p", + seat, seat->keyboard_focus); + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void stop_key_repeat (GdkWaylandSeat *seat); + +static void +keyboard_handle_leave (void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + struct wl_surface *surface) +{ + GdkWaylandSeat *seat = data; + GdkEvent *event; + + if (!seat->keyboard_focus) + return; + + /* gdk_surface_is_destroyed() might already return TRUE for + * seat->keyboard_focus here, which would happen if we destroyed the + * surface before losing keyboard focus. + */ + stop_key_repeat (seat); + + event = gdk_focus_event_new (seat->keyboard_focus, + seat->logical_keyboard, + FALSE); + + g_object_unref (seat->keyboard_focus); + seat->keyboard_focus = NULL; + seat->repeat_key = 0; + seat->key_modifiers = 0; + + GDK_SEAT_DEBUG (seat, EVENTS, + "focus out, seat %p surface %p", + seat, gdk_event_get_surface (event)); + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static gboolean keyboard_repeat (gpointer data); + +static gboolean +get_key_repeat (GdkWaylandSeat *seat, + guint *delay, + guint *interval) +{ + gboolean repeat; + + if (seat->have_server_repeat) + { + if (seat->server_repeat_rate > 0) + { + repeat = TRUE; + *delay = seat->server_repeat_delay; + *interval = (1000 / seat->server_repeat_rate); + } + else + { + repeat = FALSE; + } + } + else + { + repeat = TRUE; + *delay = 400; + *interval = 80; + } + + return repeat; +} + +static void +stop_key_repeat (GdkWaylandSeat *seat) +{ + if (seat->repeat_timer) + { + g_source_remove (seat->repeat_timer); + seat->repeat_timer = 0; + } + + g_clear_pointer (&seat->repeat_callback, wl_callback_destroy); +} + +static void +deliver_key_event (GdkWaylandSeat *seat, + uint32_t time_, + uint32_t key, + uint32_t state, + gboolean from_key_repeat) +{ + GdkEvent *event; + struct xkb_state *xkb_state; + struct xkb_keymap *xkb_keymap; + GdkKeymap *keymap; + guint delay, interval, timeout; + gint64 begin_time, now; + xkb_mod_mask_t consumed; + GdkTranslatedKey translated; + GdkTranslatedKey no_lock; + xkb_mod_mask_t modifiers; + xkb_mod_index_t caps_lock; + + begin_time = g_get_monotonic_time (); + + stop_key_repeat (seat); + + keymap = seat->keymap; + xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); + xkb_keymap = _gdk_wayland_keymap_get_xkb_keymap (keymap); + + translated.keyval = xkb_state_key_get_one_sym (xkb_state, key); + modifiers = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); + consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (xkb_state, key, modifiers); + translated.consumed = gdk_wayland_keymap_get_gdk_modifiers (keymap, consumed); + translated.layout = xkb_state_key_get_layout (xkb_state, key); + translated.level = xkb_state_key_get_level (xkb_state, key, translated.layout); + + if (translated.keyval == XKB_KEY_NoSymbol) + return; + + seat->pointer_info.time = time_; + seat->key_modifiers = gdk_keymap_get_modifier_state (keymap); + + + modifiers = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); + caps_lock = xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS); + if (modifiers & (1 << caps_lock)) + { + struct xkb_state *tmp_state = xkb_state_new (xkb_keymap); + xkb_layout_index_t layout; + + modifiers &= ~(1 << caps_lock); + layout = xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); + xkb_state_update_mask (tmp_state, modifiers, 0, 0, layout, 0, 0); + + no_lock.keyval = xkb_state_key_get_one_sym (tmp_state, key); + consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (tmp_state, key, modifiers); + no_lock.consumed = gdk_wayland_keymap_get_gdk_modifiers (keymap, consumed); + no_lock.layout = xkb_state_key_get_layout (tmp_state, key); + no_lock.level = xkb_state_key_get_level (tmp_state, key, no_lock.layout); + + xkb_state_unref (tmp_state); + } + else + { + no_lock = translated; + } + + event = gdk_key_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE, + seat->keyboard_focus, + seat->logical_keyboard, + time_, + key, + device_get_modifiers (seat->logical_pointer), + _gdk_wayland_keymap_key_is_modifier (keymap, key), + &translated, + &no_lock, + NULL); + + _gdk_wayland_display_deliver_event (seat->display, event); + + GDK_SEAT_DEBUG (seat, EVENTS, + "keyboard %s event%s, surface %p, code %d, sym %d, " + "mods 0x%x, consumed 0x%x, layout %d level %d", + (state ? "press" : "release"), + (from_key_repeat ? " (repeat)" : ""), + gdk_event_get_surface (event), + gdk_key_event_get_keycode (event), + gdk_key_event_get_keyval (event), + gdk_event_get_modifier_state (event), + gdk_key_event_get_consumed_modifiers (event), + gdk_key_event_get_layout (event), + gdk_key_event_get_level (event)); + + if (!xkb_keymap_key_repeats (xkb_keymap, key)) + return; + + if (!get_key_repeat (seat, &delay, &interval)) + return; + + if (!from_key_repeat) + { + if (state) /* Another key is pressed */ + { + seat->repeat_key = key; + } + else if (seat->repeat_key == key) /* Repeated key is released */ + { + seat->repeat_key = 0; + } + } + + if (!seat->repeat_key) + return; + + seat->repeat_count++; + + interval *= 1000L; + delay *= 1000L; + + now = g_get_monotonic_time (); + + if (seat->repeat_count == 1) + seat->repeat_deadline = begin_time + delay; + else if (seat->repeat_deadline + interval > now) + seat->repeat_deadline += interval; + else + /* frame delay caused us to miss repeat deadline */ + seat->repeat_deadline = now; + + timeout = (seat->repeat_deadline - now) / 1000L; + + seat->repeat_timer = g_timeout_add (timeout, keyboard_repeat, seat); + gdk_source_set_static_name_by_id (seat->repeat_timer, "[gtk] keyboard_repeat"); +} + +static void +sync_after_repeat_callback (void *data, + struct wl_callback *callback, + uint32_t time) +{ + GdkWaylandSeat *seat = data; + + g_clear_pointer (&seat->repeat_callback, wl_callback_destroy); + deliver_key_event (seat, seat->keyboard_time, seat->repeat_key, 1, TRUE); +} + +static const struct wl_callback_listener sync_after_repeat_callback_listener = { + sync_after_repeat_callback +}; + +static gboolean +keyboard_repeat (gpointer data) +{ + GdkWaylandSeat *seat = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (seat->display); + + /* Ping the server and wait for the timeout. We won't process + * key repeat until it responds, since a hung server could lead + * to a delayed key release event. We don't want to generate + * repeat events long after the user released the key, just because + * the server is tardy in telling us the user released the key. + */ + seat->repeat_callback = wl_display_sync (display->wl_display); + + wl_callback_add_listener (seat->repeat_callback, + &sync_after_repeat_callback_listener, + seat); + + seat->repeat_timer = 0; + return G_SOURCE_REMOVE; +} + +static void +keyboard_handle_key (void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state_w) +{ + GdkWaylandSeat *seat = data; + + if (!seat->keyboard_focus) + return; + + seat->keyboard_time = time; + seat->keyboard_key_serial = serial; + seat->repeat_count = 0; + deliver_key_event (data, time, key + 8, state_w, FALSE); + +} + +static void +keyboard_handle_modifiers (void *data, + struct wl_keyboard *keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ + GdkWaylandSeat *seat = data; + GdkKeymap *keymap; + struct xkb_state *xkb_state; + PangoDirection direction; + gboolean bidi; + gboolean caps_lock; + gboolean num_lock; + gboolean scroll_lock; + GdkModifierType modifiers; + int layout; + + keymap = seat->keymap; + xkb_state = _gdk_wayland_keymap_get_xkb_state (keymap); + + direction = gdk_keymap_get_direction (keymap); + bidi = gdk_keymap_have_bidi_layouts (keymap); + caps_lock = gdk_keymap_get_caps_lock_state (keymap); + num_lock = gdk_keymap_get_num_lock_state (keymap); + scroll_lock = gdk_keymap_get_scroll_lock_state (keymap); + modifiers = gdk_keymap_get_modifier_state (keymap); + layout = get_active_layout (keymap); + + /* Note: the docs for xkb_state_update mask state that all parameters + * must be passed, or we may end up with an 'incoherent' state. But the + * Wayland modifiers event only includes a single group field, so we + * can't pass depressed/latched/locked groups. + * + * We assume that the compositor is sending us the 'effective' group + * (the protocol is not clear on that point), and pass it as the depressed + * group - we are basically pretending that the user holds down a key for + * this group at all times. + * + * This means that our xkb_state would answer a few questions differently + * from the compositors xkb_state - e.g. if you asked it about the latched + * group. But nobody is asking it those questions, so it does not really + * matter. We hope. + */ + xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0); + + seat->key_modifiers = gdk_keymap_get_modifier_state (keymap); + + g_signal_emit_by_name (keymap, "state-changed"); + if (layout != get_active_layout (keymap)) + { + GDK_DISPLAY_DEBUG (keymap->display, INPUT, "active layout now: %s", get_active_layout_name (keymap)); + + g_signal_emit_by_name (keymap, "keys-changed"); + } + if (direction != gdk_keymap_get_direction (keymap)) + { + g_signal_emit_by_name (keymap, "direction-changed"); + g_object_notify (G_OBJECT (seat->logical_keyboard), "direction"); + } + if (bidi != gdk_keymap_have_bidi_layouts (keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "has-bidi-layouts"); + if (caps_lock != gdk_keymap_get_caps_lock_state (keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "caps-lock-state"); + if (num_lock != gdk_keymap_get_num_lock_state (keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "num-lock-state"); + if (scroll_lock != gdk_keymap_get_scroll_lock_state (keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "scroll-lock-state"); + if (modifiers != gdk_keymap_get_modifier_state (keymap)) + g_object_notify (G_OBJECT (seat->logical_keyboard), "modifier-state"); +} + +static void +keyboard_handle_repeat_info (void *data, + struct wl_keyboard *keyboard, + int32_t rate, + int32_t delay) +{ + GdkWaylandSeat *seat = data; + + seat->have_server_repeat = TRUE; + seat->server_repeat_rate = rate; + seat->server_repeat_delay = delay; +} + +static GdkWaylandTouchData * +gdk_wayland_seat_add_touch (GdkWaylandSeat *seat, + uint32_t id, + struct wl_surface *surface) +{ + GdkWaylandTouchData *touch; + + touch = g_new0 (GdkWaylandTouchData, 1); + touch->id = id; + touch->surface = wl_surface_get_user_data (surface); + touch->initial_touch = (g_hash_table_size (seat->touches) == 0); + + g_hash_table_insert (seat->touches, GUINT_TO_POINTER (id), touch); + + return touch; +} + +static GdkWaylandTouchData * +gdk_wayland_seat_get_touch (GdkWaylandSeat *seat, + uint32_t id) +{ + return g_hash_table_lookup (seat->touches, GUINT_TO_POINTER (id)); +} + +static void +gdk_wayland_seat_remove_touch (GdkWaylandSeat *seat, + uint32_t id) +{ + g_hash_table_remove (seat->touches, GUINT_TO_POINTER (id)); +} + +void +gdk_wayland_seat_clear_touchpoints (GdkWaylandSeat *seat, + GdkSurface *surface) +{ + GHashTableIter iter; + GdkWaylandTouchData *touch; + + g_hash_table_iter_init (&iter, seat->touches); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) + { + if (touch->surface == surface) + g_hash_table_iter_remove (&iter); + } +} + +static void +mimic_pointer_emulating_touch_info (GdkDevice *device, + GdkWaylandTouchData *touch) +{ + GdkWaylandPointerData *pointer; + + pointer = GDK_WAYLAND_DEVICE (device)->pointer; + g_set_object (&pointer->focus, touch->surface); + pointer->press_serial = pointer->enter_serial = touch->touch_down_serial; + pointer->surface_x = touch->x; + pointer->surface_y = touch->y; +} + +static void +touch_handle_logical_pointer_crossing (GdkWaylandSeat *seat, + GdkWaylandTouchData *touch, + uint32_t time) +{ + GdkWaylandPointerData *pointer; + + pointer = GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer; + + if (pointer->focus == touch->surface) + return; + + if (pointer->focus) + { + emulate_touch_crossing (pointer->focus, NULL, + seat->logical_touch, seat->touch, touch, + GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, time); + } + + if (touch->surface) + { + emulate_touch_crossing (touch->surface, NULL, + seat->logical_touch, seat->touch, touch, + GDK_ENTER_NOTIFY, GDK_CROSSING_NORMAL, time); + } +} + +static void +touch_handle_down (void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + struct wl_surface *wl_surface, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTouchData *touch; + GdkEvent *event; + + if (!wl_surface) + return; + + touch = gdk_wayland_seat_add_touch (seat, id, wl_surface); + touch->x = wl_fixed_to_double (x); + touch->y = wl_fixed_to_double (y); + touch->touch_down_serial = serial; + + event = gdk_touch_event_new (GDK_TOUCH_BEGIN, + GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), + touch->surface, + seat->logical_touch, + time, + device_get_modifiers (seat->logical_touch), + touch->x, touch->y, + NULL, + touch->initial_touch); + + if (touch->initial_touch) + { + touch_handle_logical_pointer_crossing (seat, touch, time); + GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = touch; + mimic_pointer_emulating_touch_info (seat->logical_touch, touch); + } + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double xx, yy; + gdk_event_get_position (event, &xx, &yy); + g_message ("touch begin %f %f", xx, yy); + } + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +touch_handle_up (void *data, + struct wl_touch *wl_touch, + uint32_t serial, + uint32_t time, + int32_t id) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTouchData *touch; + GdkEvent *event; + + touch = gdk_wayland_seat_get_touch (seat, id); + if (!touch) + return; + + event = gdk_touch_event_new (GDK_TOUCH_END, + GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), + touch->surface, + seat->logical_touch, + time, + device_get_modifiers (seat->logical_touch), + touch->x, touch->y, + NULL, + touch->initial_touch); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double x, y; + gdk_event_get_position (event, &x, &y); + g_message ("touch end %f %f", x, y); + } + + _gdk_wayland_display_deliver_event (seat->display, event); + + if (touch->initial_touch) + GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = NULL; + + gdk_wayland_seat_remove_touch (seat, id); +} + +static void +touch_handle_motion (void *data, + struct wl_touch *wl_touch, + uint32_t time, + int32_t id, + wl_fixed_t x, + wl_fixed_t y) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTouchData *touch; + GdkEvent *event; + + touch = gdk_wayland_seat_get_touch (seat, id); + if (!touch) + return; + + touch->x = wl_fixed_to_double (x); + touch->y = wl_fixed_to_double (y); + + if (touch->initial_touch) + mimic_pointer_emulating_touch_info (seat->logical_touch, touch); + + event = gdk_touch_event_new (GDK_TOUCH_UPDATE, + GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), + touch->surface, + seat->logical_touch, + time, + device_get_modifiers (seat->logical_touch), + touch->x, touch->y, + NULL, + touch->initial_touch); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double xx, yy; + gdk_event_get_position (event, &xx, &yy); + g_message ("touch update %f %f", xx, yy); + } + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +touch_handle_frame (void *data, + struct wl_touch *wl_touch) +{ +} + +static void +touch_handle_cancel (void *data, + struct wl_touch *wl_touch) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTouchData *touch; + GHashTableIter iter; + GdkEvent *event; + + if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch) + { + touch = GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch; + GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL; + } + + g_hash_table_iter_init (&iter, seat->touches); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) + { + event = gdk_touch_event_new (GDK_TOUCH_CANCEL, + GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), + touch->surface, + seat->logical_touch, + GDK_CURRENT_TIME, + device_get_modifiers (seat->logical_touch), + touch->x, touch->y, + NULL, + touch->initial_touch); + _gdk_wayland_display_deliver_event (seat->display, event); + g_hash_table_iter_remove (&iter); + } + + GDK_SEAT_DEBUG (seat, EVENTS, "touch cancel"); +} + +static void +touch_handle_shape (void *data, + struct wl_touch *touch, + int32_t id, + wl_fixed_t major, + wl_fixed_t minor) +{ +} + +static void +touch_handle_orientation (void *data, + struct wl_touch *touch, + int32_t id, + wl_fixed_t orientation) +{ +} + +static void +emit_gesture_swipe_event (GdkWaylandSeat *seat, + GdkTouchpadGesturePhase phase, + guint32 _time, + guint32 n_fingers, + double dx, + double dy) +{ + GdkEvent *event; + + if (!seat->pointer_info.focus) + return; + + seat->pointer_info.time = _time; + + if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) + seat->pointer_info.touchpad_event_sequence++; + + event = gdk_touchpad_event_new_swipe (seat->pointer_info.focus, + GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), + seat->logical_pointer, + _time, + device_get_modifiers (seat->logical_pointer), + phase, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + n_fingers, + dx, dy); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double x, y; + gdk_event_get_position (event, &x, &y); + g_message ("swipe event %d, coords: %f %f, seat %p state %d", + gdk_event_get_event_type (event), x, y, seat, + gdk_event_get_modifier_state (event)); + } + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +gesture_swipe_begin (void *data, + struct zwp_pointer_gesture_swipe_v1 *swipe, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + GdkWaylandSeat *seat = data; + + emit_gesture_swipe_event (seat, + GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, + time, fingers, 0, 0); + seat->gesture_n_fingers = fingers; +} + +static void +gesture_swipe_update (void *data, + struct zwp_pointer_gesture_swipe_v1 *swipe, + uint32_t time, + wl_fixed_t dx, + wl_fixed_t dy) +{ + GdkWaylandSeat *seat = data; + + emit_gesture_swipe_event (seat, + GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, + time, + seat->gesture_n_fingers, + wl_fixed_to_double (dx), + wl_fixed_to_double (dy)); +} + +static void +gesture_swipe_end (void *data, + struct zwp_pointer_gesture_swipe_v1 *swipe, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + GdkWaylandSeat *seat = data; + GdkTouchpadGesturePhase phase; + + phase = (cancelled) ? + GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : + GDK_TOUCHPAD_GESTURE_PHASE_END; + + emit_gesture_swipe_event (seat, phase, time, + seat->gesture_n_fingers, 0, 0); +} + +static void +emit_gesture_pinch_event (GdkWaylandSeat *seat, + GdkTouchpadGesturePhase phase, + guint32 _time, + guint n_fingers, + double dx, + double dy, + double scale, + double angle_delta) +{ + GdkEvent *event; + + if (!seat->pointer_info.focus) + return; + + seat->pointer_info.time = _time; + + if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) + seat->pointer_info.touchpad_event_sequence++; + + event = gdk_touchpad_event_new_pinch (seat->pointer_info.focus, + GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), + seat->logical_pointer, + _time, + device_get_modifiers (seat->logical_pointer), + phase, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + n_fingers, + dx, dy, + scale, angle_delta * G_PI / 180); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double x, y; + gdk_event_get_position (event, &x, &y); + g_message ("pinch event %d, coords: %f %f, seat %p state %d", + gdk_event_get_event_type (event), + x, y, seat, + gdk_event_get_modifier_state (event)); + } + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +gesture_pinch_begin (void *data, + struct zwp_pointer_gesture_pinch_v1 *pinch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + GdkWaylandSeat *seat = data; + + emit_gesture_pinch_event (seat, + GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, + time, fingers, 0, 0, 1, 0); + seat->gesture_n_fingers = fingers; +} + +static void +gesture_pinch_update (void *data, + struct zwp_pointer_gesture_pinch_v1 *pinch, + uint32_t time, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t scale, + wl_fixed_t rotation) +{ + GdkWaylandSeat *seat = data; + + emit_gesture_pinch_event (seat, + GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, time, + seat->gesture_n_fingers, + wl_fixed_to_double (dx), + wl_fixed_to_double (dy), + wl_fixed_to_double (scale), + wl_fixed_to_double (rotation)); +} + +static void +gesture_pinch_end (void *data, + struct zwp_pointer_gesture_pinch_v1 *pinch, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + GdkWaylandSeat *seat = data; + GdkTouchpadGesturePhase phase; + + phase = (cancelled) ? + GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : + GDK_TOUCHPAD_GESTURE_PHASE_END; + + emit_gesture_pinch_event (seat, phase, + time, seat->gesture_n_fingers, + 0, 0, 1, 0); +} + +static void +emit_gesture_hold_event (GdkWaylandSeat *seat, + GdkTouchpadGesturePhase phase, + guint32 _time, + guint32 n_fingers) +{ + GdkEvent *event; + + if (!seat->pointer_info.focus) + return; + + seat->pointer_info.time = _time; + + if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) + seat->pointer_info.touchpad_event_sequence++; + + event = gdk_touchpad_event_new_hold (seat->pointer_info.focus, + GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), + seat->logical_pointer, + _time, + device_get_modifiers (seat->logical_pointer), + phase, + seat->pointer_info.surface_x, + seat->pointer_info.surface_y, + n_fingers); + + if (GDK_DISPLAY_DEBUG_CHECK (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS)) + { + double x, y; + gdk_event_get_position (event, &x, &y); + g_message ("hold event %d, coords: %f %f, seat %p state %d", + gdk_event_get_event_type (event), + x, y, seat, + gdk_event_get_modifier_state (event)); + } + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +gesture_hold_begin (void *data, + struct zwp_pointer_gesture_hold_v1 *hold, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + GdkWaylandSeat *seat = data; + + emit_gesture_hold_event (seat, + GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, + time, fingers); + seat->gesture_n_fingers = fingers; +} + +static void +gesture_hold_end (void *data, + struct zwp_pointer_gesture_hold_v1 *hold, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + GdkWaylandSeat *seat = data; + GdkTouchpadGesturePhase phase; + + phase = (cancelled) ? + GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : + GDK_TOUCHPAD_GESTURE_PHASE_END; + + emit_gesture_hold_event (seat, phase, time, + seat->gesture_n_fingers); +} + +static void +_gdk_wayland_seat_remove_tool (GdkWaylandSeat *seat, + GdkWaylandTabletToolData *tool) +{ + seat->tablet_tools = g_list_remove (seat->tablet_tools, tool); + + gdk_seat_tool_removed (GDK_SEAT (seat), tool->tool); + + zwp_tablet_tool_v2_destroy (tool->wp_tablet_tool); + g_object_unref (tool->tool); + g_free (tool); +} + +static void +_gdk_wayland_seat_remove_tablet (GdkWaylandSeat *seat, + GdkWaylandTabletData *tablet) +{ + seat->tablets = g_list_remove (seat->tablets, tablet); + + gdk_seat_device_removed (GDK_SEAT (seat), tablet->stylus_device); + gdk_seat_device_removed (GDK_SEAT (seat), tablet->logical_device); + + while (tablet->pads) + { + GdkWaylandTabletPadData *pad = tablet->pads->data; + + pad->current_tablet = NULL; + tablet->pads = g_list_remove (tablet->pads, pad); + } + + zwp_tablet_v2_destroy (tablet->wp_tablet); + + _gdk_device_set_associated_device (tablet->logical_device, NULL); + _gdk_device_set_associated_device (tablet->stylus_device, NULL); + + if (tablet->pointer_info.focus) + g_object_unref (tablet->pointer_info.focus); + + wl_surface_destroy (tablet->pointer_info.pointer_surface); + g_object_unref (tablet->logical_device); + g_object_unref (tablet->stylus_device); + g_free (tablet); +} + +static void +_gdk_wayland_seat_remove_tablet_pad (GdkWaylandSeat *seat, + GdkWaylandTabletPadData *pad) +{ + seat->tablet_pads = g_list_remove (seat->tablet_pads, pad); + + gdk_seat_device_removed (GDK_SEAT (seat), pad->device); + _gdk_device_set_associated_device (pad->device, NULL); + + g_object_unref (pad->device); + g_free (pad); +} + +static GdkWaylandTabletPadGroupData * +tablet_pad_lookup_button_group (GdkWaylandTabletPadData *pad, + uint32_t button) +{ + GdkWaylandTabletPadGroupData *group; + GList *l; + + for (l = pad->mode_groups; l; l = l->next) + { + group = l->data; + + if (g_list_find (group->buttons, GUINT_TO_POINTER (button))) + return group; + } + + return NULL; +} + +static void +tablet_handle_name (void *data, + struct zwp_tablet_v2 *wp_tablet, + const char *name) +{ + GdkWaylandTabletData *tablet = data; + + tablet->name = g_strdup (name); +} + +static void +tablet_handle_id (void *data, + struct zwp_tablet_v2 *wp_tablet, + uint32_t vid, + uint32_t pid) +{ + GdkWaylandTabletData *tablet = data; + + tablet->vid = vid; + tablet->pid = pid; +} + +static void +tablet_handle_path (void *data, + struct zwp_tablet_v2 *wp_tablet, + const char *path) +{ + GdkWaylandTabletData *tablet = data; + + tablet->path = g_strdup (path); +} + +static void +tablet_handle_done (void *data, + struct zwp_tablet_v2 *wp_tablet) +{ + GdkWaylandTabletData *tablet = data; + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (tablet->seat); + GdkDisplay *display = gdk_seat_get_display (GDK_SEAT (seat)); + GdkDevice *logical_device, *stylus_device; + char *logical_name; + char *vid, *pid; + + vid = g_strdup_printf ("%.4x", tablet->vid); + pid = g_strdup_printf ("%.4x", tablet->pid); + + logical_name = g_strdup_printf ("Logical pointer for %s", tablet->name); + logical_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", logical_name, + "source", GDK_SOURCE_MOUSE, + "has-cursor", TRUE, + "display", display, + "seat", seat, + NULL); + GDK_WAYLAND_DEVICE (logical_device)->pointer = &tablet->pointer_info; + + stylus_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", tablet->name, + "source", GDK_SOURCE_PEN, + "has-cursor", FALSE, + "display", display, + "seat", seat, + "vendor-id", vid, + "product-id", pid, + NULL); + + tablet->logical_device = logical_device; + init_pointer_data (&tablet->pointer_info, display, tablet->logical_device); + + tablet->stylus_device = stylus_device; + + _gdk_device_set_associated_device (logical_device, seat->logical_keyboard); + _gdk_device_set_associated_device (stylus_device, logical_device); + + gdk_seat_device_added (GDK_SEAT (seat), logical_device); + gdk_seat_device_added (GDK_SEAT (seat), stylus_device); + + g_free (logical_name); + g_free (vid); + g_free (pid); +} + +static void +tablet_handle_removed (void *data, + struct zwp_tablet_v2 *wp_tablet) +{ + GdkWaylandTabletData *tablet = data; + + _gdk_wayland_seat_remove_tablet (GDK_WAYLAND_SEAT (tablet->seat), tablet); +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, + pointer_handle_frame, + pointer_handle_axis_source, + pointer_handle_axis_stop, + pointer_handle_axis_discrete, + pointer_handle_axis_value120, +}; + +static const struct wl_keyboard_listener keyboard_listener = { + keyboard_handle_keymap, + keyboard_handle_enter, + keyboard_handle_leave, + keyboard_handle_key, + keyboard_handle_modifiers, + keyboard_handle_repeat_info, +}; + +static const struct wl_touch_listener touch_listener = { + touch_handle_down, + touch_handle_up, + touch_handle_motion, + touch_handle_frame, + touch_handle_cancel, + touch_handle_shape, + touch_handle_orientation, +}; + +static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener = { + gesture_swipe_begin, + gesture_swipe_update, + gesture_swipe_end +}; + +static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = { + gesture_pinch_begin, + gesture_pinch_update, + gesture_pinch_end +}; + +static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_listener = { + gesture_hold_begin, + gesture_hold_end +}; + +static const struct zwp_tablet_v2_listener tablet_listener = { + tablet_handle_name, + tablet_handle_id, + tablet_handle_path, + tablet_handle_done, + tablet_handle_removed, +}; + +static void +seat_handle_capabilities (void *data, + struct wl_seat *wl_seat, + enum wl_seat_capability caps) +{ + GdkWaylandSeat *seat = data; + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); + + GDK_SEAT_DEBUG (seat, MISC, + "seat %p with %s%s%s", wl_seat, + (caps & WL_SEAT_CAPABILITY_POINTER) ? " pointer, " : "", + (caps & WL_SEAT_CAPABILITY_KEYBOARD) ? " keyboard, " : "", + (caps & WL_SEAT_CAPABILITY_TOUCH) ? " touch" : ""); + + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) + { + seat->wl_pointer = wl_seat_get_pointer (wl_seat); + wl_pointer_set_user_data (seat->wl_pointer, seat); + wl_pointer_add_listener (seat->wl_pointer, &pointer_listener, seat); + + seat->pointer = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Pointer", + "source", GDK_SOURCE_MOUSE, + "has-cursor", TRUE, + "display", seat->display, + "seat", seat, + NULL); + _gdk_device_set_associated_device (seat->pointer, seat->logical_pointer); + gdk_seat_device_added (GDK_SEAT (seat), seat->pointer); + + if (display_wayland->pointer_gestures) + { + seat->wp_pointer_gesture_swipe = + zwp_pointer_gestures_v1_get_swipe_gesture (display_wayland->pointer_gestures, + seat->wl_pointer); + zwp_pointer_gesture_swipe_v1_set_user_data (seat->wp_pointer_gesture_swipe, + seat); + zwp_pointer_gesture_swipe_v1_add_listener (seat->wp_pointer_gesture_swipe, + &gesture_swipe_listener, seat); + + seat->wp_pointer_gesture_pinch = + zwp_pointer_gestures_v1_get_pinch_gesture (display_wayland->pointer_gestures, + seat->wl_pointer); + zwp_pointer_gesture_pinch_v1_set_user_data (seat->wp_pointer_gesture_pinch, + seat); + zwp_pointer_gesture_pinch_v1_add_listener (seat->wp_pointer_gesture_pinch, + &gesture_pinch_listener, seat); + + if (display_wayland->pointer_gestures_version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE_SINCE_VERSION) + { + seat->wp_pointer_gesture_hold = + zwp_pointer_gestures_v1_get_hold_gesture (display_wayland->pointer_gestures, + seat->wl_pointer); + zwp_pointer_gesture_hold_v1_set_user_data (seat->wp_pointer_gesture_hold, + seat); + zwp_pointer_gesture_hold_v1_add_listener (seat->wp_pointer_gesture_hold, + &gesture_hold_listener, seat); + } + } + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) + { + g_clear_pointer (&seat->wp_pointer_gesture_swipe, + zwp_pointer_gesture_swipe_v1_destroy); + g_clear_pointer (&seat->wp_pointer_gesture_pinch, + zwp_pointer_gesture_pinch_v1_destroy); + + wl_pointer_release (seat->wl_pointer); + seat->wl_pointer = NULL; + gdk_seat_device_removed (GDK_SEAT (seat), seat->pointer); + _gdk_device_set_associated_device (seat->pointer, NULL); + + g_clear_object (&seat->pointer); + + if (seat->wheel_scrolling) + { + gdk_seat_device_removed (GDK_SEAT (seat), seat->wheel_scrolling); + _gdk_device_set_associated_device (seat->wheel_scrolling, NULL); + + g_clear_object (&seat->wheel_scrolling); + } + + if (seat->finger_scrolling) + { + gdk_seat_device_removed (GDK_SEAT (seat), seat->finger_scrolling); + _gdk_device_set_associated_device (seat->finger_scrolling, NULL); + + g_clear_object (&seat->finger_scrolling); + } + + if (seat->continuous_scrolling) + { + gdk_seat_device_removed (GDK_SEAT (seat), seat->continuous_scrolling); + _gdk_device_set_associated_device (seat->continuous_scrolling, NULL); + + g_clear_object (&seat->continuous_scrolling); + } + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !seat->wl_keyboard) + { + seat->wl_keyboard = wl_seat_get_keyboard (wl_seat); + wl_keyboard_set_user_data (seat->wl_keyboard, seat); + wl_keyboard_add_listener (seat->wl_keyboard, &keyboard_listener, seat); + + seat->keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Keyboard", + "source", GDK_SOURCE_KEYBOARD, + "has-cursor", FALSE, + "display", seat->display, + "seat", seat, + NULL); + _gdk_device_reset_axes (seat->keyboard); + _gdk_device_set_associated_device (seat->keyboard, seat->logical_keyboard); + gdk_seat_device_added (GDK_SEAT (seat), seat->keyboard); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->wl_keyboard) + { + wl_keyboard_release (seat->wl_keyboard); + seat->wl_keyboard = NULL; + gdk_seat_device_removed (GDK_SEAT (seat), seat->keyboard); + _gdk_device_set_associated_device (seat->keyboard, NULL); + + g_clear_object (&seat->keyboard); + } + + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !seat->wl_touch) + { + seat->wl_touch = wl_seat_get_touch (wl_seat); + wl_touch_set_user_data (seat->wl_touch, seat); + wl_touch_add_listener (seat->wl_touch, &touch_listener, seat); + + seat->logical_touch = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Touch Logical Pointer", + "source", GDK_SOURCE_TOUCHSCREEN, + "has-cursor", TRUE, + "display", seat->display, + "seat", seat, + NULL); + GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer = &seat->touch_info; + _gdk_device_set_associated_device (seat->logical_touch, seat->logical_keyboard); + gdk_seat_device_added (GDK_SEAT (seat), seat->logical_touch); + + seat->touch = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Touch", + "source", GDK_SOURCE_TOUCHSCREEN, + "has-cursor", FALSE, + "display", seat->display, + "seat", seat, + NULL); + _gdk_device_set_associated_device (seat->touch, seat->logical_touch); + gdk_seat_device_added (GDK_SEAT (seat), seat->touch); + } + else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->wl_touch) + { + wl_touch_release (seat->wl_touch); + seat->wl_touch = NULL; + gdk_seat_device_removed (GDK_SEAT (seat), seat->touch); + gdk_seat_device_removed (GDK_SEAT (seat), seat->logical_touch); + _gdk_device_set_associated_device (seat->logical_touch, NULL); + _gdk_device_set_associated_device (seat->touch, NULL); + + g_clear_object (&seat->logical_touch); + g_clear_object (&seat->touch); + } +} + +static GdkDevice * +get_scroll_device (GdkWaylandSeat *seat, + enum wl_pointer_axis_source source) +{ + if (!seat->pointer) + return NULL; + + switch (source) + { + case WL_POINTER_AXIS_SOURCE_WHEEL: + if (seat->wheel_scrolling == NULL) + { + seat->wheel_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Wheel Scrolling", + "source", GDK_SOURCE_MOUSE, + "has-cursor", TRUE, + "display", seat->display, + "seat", seat, + NULL); + gdk_seat_device_added (GDK_SEAT (seat), seat->wheel_scrolling); + } + return seat->wheel_scrolling; + + case WL_POINTER_AXIS_SOURCE_FINGER: + if (seat->finger_scrolling == NULL) + { + seat->finger_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Finger Scrolling", + "source", GDK_SOURCE_TOUCHPAD, + "has-cursor", TRUE, + "display", seat->display, + "seat", seat, + NULL); + gdk_seat_device_added (GDK_SEAT (seat), seat->finger_scrolling); + } + return seat->finger_scrolling; + + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: + if (seat->continuous_scrolling == NULL) + { + seat->continuous_scrolling = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Wayland Continuous Scrolling", + "source", GDK_SOURCE_TRACKPOINT, + "has-cursor", TRUE, + "display", seat->display, + "seat", seat, + NULL); + gdk_seat_device_added (GDK_SEAT (seat), seat->continuous_scrolling); + } + return seat->continuous_scrolling; + + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: + default: + return seat->pointer; + } +} + +static void +seat_handle_name (void *data, + struct wl_seat *seat, + const char *name) +{ + /* We don't care about the name. */ + GDK_SEAT_DEBUG (GDK_WAYLAND_SEAT (data), MISC, + "seat %p name %s", seat, name); +} + +static const struct wl_seat_listener seat_listener = { + seat_handle_capabilities, + seat_handle_name, +}; + +static void +tablet_tool_handle_type (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t tool_type) +{ + GdkWaylandTabletToolData *tool = data; + + switch (tool_type) + { + case ZWP_TABLET_TOOL_V2_TYPE_PEN: + tool->type = GDK_DEVICE_TOOL_TYPE_PEN; + break; + case ZWP_TABLET_TOOL_V2_TYPE_BRUSH: + tool->type = GDK_DEVICE_TOOL_TYPE_BRUSH; + break; + case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH: + tool->type = GDK_DEVICE_TOOL_TYPE_AIRBRUSH; + break; + case ZWP_TABLET_TOOL_V2_TYPE_PENCIL: + tool->type = GDK_DEVICE_TOOL_TYPE_PENCIL; + break; + case ZWP_TABLET_TOOL_V2_TYPE_ERASER: + tool->type = GDK_DEVICE_TOOL_TYPE_ERASER; + break; + case ZWP_TABLET_TOOL_V2_TYPE_MOUSE: + tool->type = GDK_DEVICE_TOOL_TYPE_MOUSE; + break; + case ZWP_TABLET_TOOL_V2_TYPE_LENS: + tool->type = GDK_DEVICE_TOOL_TYPE_LENS; + break; + default: + tool->type = GDK_DEVICE_TOOL_TYPE_UNKNOWN; + break; + }; +} + +static void +tablet_tool_handle_hardware_serial (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t serial_hi, + uint32_t serial_lo) +{ + GdkWaylandTabletToolData *tool = data; + + tool->hardware_serial = ((guint64) serial_hi) << 32 | serial_lo; +} + +static void +tablet_tool_handle_hardware_id_wacom (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t id_hi, + uint32_t id_lo) +{ + GdkWaylandTabletToolData *tool = data; + + tool->hardware_id_wacom = ((guint64) id_hi) << 32 | id_lo; +} + +static void +tablet_tool_handle_capability (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t capability) +{ + GdkWaylandTabletToolData *tool = data; + + switch (capability) + { + case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: + tool->axes |= GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT; + break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: + tool->axes |= GDK_AXIS_FLAG_PRESSURE; + break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: + tool->axes |= GDK_AXIS_FLAG_DISTANCE; + break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: + tool->axes |= GDK_AXIS_FLAG_ROTATION; + break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: + tool->axes |= GDK_AXIS_FLAG_SLIDER; + break; + default: + break; + } +} + +static void +tablet_tool_handle_done (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool) +{ + GdkWaylandTabletToolData *tool = data; + + tool->tool = gdk_device_tool_new (tool->hardware_serial, + tool->hardware_id_wacom, + tool->type, tool->axes); + gdk_seat_tool_added (tool->seat, tool->tool); +} + +static void +tablet_tool_handle_removed (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool) +{ + GdkWaylandTabletToolData *tool = data; + + _gdk_wayland_seat_remove_tool (GDK_WAYLAND_SEAT (tool->seat), tool); +} + +static void +gdk_wayland_tablet_flush_frame_event (GdkWaylandTabletData *tablet, + guint32 time) +{ + GdkEvent *event; + GdkEventType type; + + event = tablet->pointer_info.frame.event; + tablet->pointer_info.frame.event = NULL; + + if (!event) + return; + + gdk_event_ref (event); + + type = gdk_event_get_event_type (event); + + if (type == GDK_PROXIMITY_OUT) + emulate_crossing (gdk_event_get_surface (event), NULL, + tablet->logical_device, GDK_LEAVE_NOTIFY, + GDK_CROSSING_NORMAL, time); + + _gdk_wayland_display_deliver_event (gdk_seat_get_display (tablet->seat), + event); + + if (type == GDK_PROXIMITY_IN) + emulate_crossing (gdk_event_get_surface (event), NULL, + tablet->logical_device, GDK_ENTER_NOTIFY, + GDK_CROSSING_NORMAL, time); + + gdk_event_unref (event); +} + +static void +gdk_wayland_tablet_set_frame_event (GdkWaylandTabletData *tablet, + GdkEvent *event) +{ + if (tablet->pointer_info.frame.event && + gdk_event_get_event_type (tablet->pointer_info.frame.event) != gdk_event_get_event_type (event)) + gdk_wayland_tablet_flush_frame_event (tablet, GDK_CURRENT_TIME); + + tablet->pointer_info.frame.event = event; +} + +static void +gdk_wayland_device_tablet_clone_tool_axes (GdkWaylandTabletData *tablet, + GdkDeviceTool *tool) +{ + int axis_pos; + + g_object_freeze_notify (G_OBJECT (tablet->stylus_device)); + _gdk_device_reset_axes (tablet->stylus_device); + + _gdk_device_add_axis (tablet->stylus_device, GDK_AXIS_X, 0, 0, 0); + _gdk_device_add_axis (tablet->stylus_device, GDK_AXIS_Y, 0, 0, 0); + + if (tool->tool_axes & (GDK_AXIS_FLAG_XTILT | GDK_AXIS_FLAG_YTILT)) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_XTILT, -90, 90, 0); + tablet->axis_indices[GDK_AXIS_XTILT] = axis_pos; + + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_YTILT, -90, 90, 0); + tablet->axis_indices[GDK_AXIS_YTILT] = axis_pos; + } + if (tool->tool_axes & GDK_AXIS_FLAG_DISTANCE) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_DISTANCE, 0, 65535, 0); + tablet->axis_indices[GDK_AXIS_DISTANCE] = axis_pos; + } + if (tool->tool_axes & GDK_AXIS_FLAG_PRESSURE) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_PRESSURE, 0, 65535, 0); + tablet->axis_indices[GDK_AXIS_PRESSURE] = axis_pos; + } + + if (tool->tool_axes & GDK_AXIS_FLAG_ROTATION) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_ROTATION, 0, 360, 0); + tablet->axis_indices[GDK_AXIS_ROTATION] = axis_pos; + } + + if (tool->tool_axes & GDK_AXIS_FLAG_SLIDER) + { + axis_pos = _gdk_device_add_axis (tablet->stylus_device, + GDK_AXIS_SLIDER, -65535, 65535, 0); + tablet->axis_indices[GDK_AXIS_SLIDER] = axis_pos; + } + + g_object_thaw_notify (G_OBJECT (tablet->stylus_device)); +} + +static void +gdk_wayland_mimic_device_axes (GdkDevice *logical, + GdkDevice *physical) +{ + double axis_min, axis_max, axis_resolution; + GdkAxisUse axis_use; + int axis_count; + int i; + + g_object_freeze_notify (G_OBJECT (logical)); + _gdk_device_reset_axes (logical); + axis_count = gdk_device_get_n_axes (physical); + + for (i = 0; i < axis_count; i++) + { + _gdk_device_get_axis_info (physical, i, &axis_use, &axis_min, + &axis_max, &axis_resolution); + _gdk_device_add_axis (logical, axis_use, axis_min, + axis_max, axis_resolution); + } + + g_object_thaw_notify (G_OBJECT (logical)); +} + +static void +tablet_tool_handle_proximity_in (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t serial, + struct zwp_tablet_v2 *wp_tablet, + struct wl_surface *wsurface) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet); + GdkSurface *surface; + GdkEvent *event; + + if (!wsurface) + return; + + surface = wl_surface_get_user_data (wsurface); + + if (!surface) + return; + if (!GDK_IS_SURFACE (surface)) + return; + + tool->current_tablet = tablet; + tablet->current_tool = tool; + + tablet->pointer_info.enter_serial = serial; + + tablet->pointer_info.focus = g_object_ref (surface); + + gdk_device_update_tool (tablet->stylus_device, tool->tool); + gdk_wayland_device_tablet_clone_tool_axes (tablet, tool->tool); + gdk_wayland_mimic_device_axes (tablet->logical_device, tablet->stylus_device); + + event = gdk_proximity_event_new (GDK_PROXIMITY_IN, + tablet->pointer_info.focus, + tablet->logical_device, + tool->tool, + tablet->pointer_info.time); + gdk_wayland_tablet_set_frame_event (tablet, event); + + tablet->pointer_info.pointer_surface_outputs = + g_slist_append (tablet->pointer_info.pointer_surface_outputs, + gdk_wayland_surface_get_wl_output (surface)); + pointer_surface_update_scale (tablet->logical_device); + + GDK_SEAT_DEBUG (tablet->seat, EVENTS, + "proximity in, seat %p surface %p tool %d", + tablet->seat, tablet->pointer_info.focus, + gdk_device_tool_get_tool_type (tool->tool)); +} + +static void +tablet_tool_handle_proximity_out (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + GdkEvent *event; + + if (!tablet) + return; + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "proximity out, seat %p, tool %d", tool->seat, + gdk_device_tool_get_tool_type (tool->tool)); + + event = gdk_proximity_event_new (GDK_PROXIMITY_OUT, + tablet->pointer_info.focus, + tablet->logical_device, + tool->tool, + tablet->pointer_info.time); + gdk_wayland_tablet_set_frame_event (tablet, event); + + gdk_wayland_pointer_stop_cursor_animation (&tablet->pointer_info); + + tablet->pointer_info.pointer_surface_outputs = + g_slist_remove (tablet->pointer_info.pointer_surface_outputs, + gdk_wayland_surface_get_wl_output (tablet->pointer_info.focus)); + pointer_surface_update_scale (tablet->logical_device); + + g_object_unref (tablet->pointer_info.focus); + tablet->pointer_info.focus = NULL; + + tablet->pointer_info.button_modifiers &= + ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | + GDK_BUTTON4_MASK | GDK_BUTTON5_MASK); + + gdk_device_update_tool (tablet->stylus_device, NULL); + g_clear_object (&tablet->pointer_info.cursor); +} + +static double * +tablet_copy_axes (GdkWaylandTabletData *tablet) +{ + return g_memdup2 (tablet->axes, sizeof (double) * GDK_AXIS_LAST); +} + +static void +tablet_create_button_event_frame (GdkWaylandTabletData *tablet, + GdkEventType evtype, + guint button) +{ + GdkEvent *event; + + event = gdk_button_event_new (evtype, + tablet->pointer_info.focus, + tablet->logical_device, + tablet->current_tool->tool, + tablet->pointer_info.time, + device_get_modifiers (tablet->logical_device), + button, + tablet->pointer_info.surface_x, + tablet->pointer_info.surface_y, + tablet_copy_axes (tablet)); + gdk_wayland_tablet_set_frame_event (tablet, event); +} + +static void +tablet_tool_handle_down (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t serial) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + + if (!tablet || !tablet->pointer_info.focus) + return; + + tablet->pointer_info.press_serial = serial; + + tablet_create_button_event_frame (tablet, GDK_BUTTON_PRESS, GDK_BUTTON_PRIMARY); + tablet->pointer_info.button_modifiers |= GDK_BUTTON1_MASK; +} + +static void +tablet_tool_handle_up (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + + if (!tablet || !tablet->pointer_info.focus) + return; + + tablet_create_button_event_frame (tablet, GDK_BUTTON_RELEASE, GDK_BUTTON_PRIMARY); + tablet->pointer_info.button_modifiers &= ~GDK_BUTTON1_MASK; +} + +static void +tablet_tool_handle_motion (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + wl_fixed_t sx, + wl_fixed_t sy) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + GdkEvent *event; + + if (!tablet) + return; + + tablet->pointer_info.surface_x = wl_fixed_to_double (sx); + tablet->pointer_info.surface_y = wl_fixed_to_double (sy); + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "tablet motion %f %f", + tablet->pointer_info.surface_x, + tablet->pointer_info.surface_y); + + event = gdk_motion_event_new (tablet->pointer_info.focus, + tablet->logical_device, + tool->tool, + tablet->pointer_info.time, + device_get_modifiers (tablet->logical_device), + tablet->pointer_info.surface_x, + tablet->pointer_info.surface_y, + tablet_copy_axes (tablet)); + + gdk_wayland_tablet_set_frame_event (tablet, event); +} + +static void +tablet_tool_handle_pressure (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t pressure) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + int axis_index; + + if (!tablet) + return; + + axis_index = tablet->axis_indices[GDK_AXIS_PRESSURE]; + + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + pressure, &tablet->axes[GDK_AXIS_PRESSURE]); + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "tablet tool %d pressure %d", + gdk_device_tool_get_tool_type (tool->tool), pressure); +} + +static void +tablet_tool_handle_distance (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t distance) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + int axis_index; + + if (!tablet) + return; + + axis_index = tablet->axis_indices[GDK_AXIS_DISTANCE]; + + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + distance, &tablet->axes[GDK_AXIS_DISTANCE]); + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "tablet tool %d distance %d", + gdk_device_tool_get_tool_type (tool->tool), distance); +} + +static void +tablet_tool_handle_tilt (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + wl_fixed_t xtilt, + wl_fixed_t ytilt) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + int xtilt_axis_index; + int ytilt_axis_index; + + if (!tablet) + return; + + xtilt_axis_index = tablet->axis_indices[GDK_AXIS_XTILT]; + ytilt_axis_index = tablet->axis_indices[GDK_AXIS_YTILT]; + + _gdk_device_translate_axis (tablet->stylus_device, xtilt_axis_index, + wl_fixed_to_double (xtilt), + &tablet->axes[GDK_AXIS_XTILT]); + _gdk_device_translate_axis (tablet->stylus_device, ytilt_axis_index, + wl_fixed_to_double (ytilt), + &tablet->axes[GDK_AXIS_YTILT]); + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "tablet tool %d tilt %f/%f", + gdk_device_tool_get_tool_type (tool->tool), + wl_fixed_to_double (xtilt), wl_fixed_to_double (ytilt)); +} + +static void +tablet_tool_handle_button (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + uint32_t serial, + uint32_t button, + uint32_t state) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + GdkEventType evtype; + guint n_button; + + if (!tablet || !tablet->pointer_info.focus) + return; + + tablet->pointer_info.press_serial = serial; + + if (button == BTN_STYLUS) + n_button = GDK_BUTTON_SECONDARY; + else if (button == BTN_STYLUS2) + n_button = GDK_BUTTON_MIDDLE; + else if (button == BTN_STYLUS3) + n_button = 8; /* Back */ + else + return; + + if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED) + evtype = GDK_BUTTON_PRESS; + else if (state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED) + evtype = GDK_BUTTON_RELEASE; + else + return; + + tablet_create_button_event_frame (tablet, evtype, n_button); +} + +static void +tablet_tool_handle_rotation (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + wl_fixed_t degrees) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + int axis_index; + + if (!tablet) + return; + + axis_index = tablet->axis_indices[GDK_AXIS_ROTATION]; + + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + wl_fixed_to_double (degrees), + &tablet->axes[GDK_AXIS_ROTATION]); + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "tablet tool %d rotation %f", + gdk_device_tool_get_tool_type (tool->tool), + wl_fixed_to_double (degrees)); +} + +static void +tablet_tool_handle_slider (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + int32_t position) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + int axis_index; + + if (!tablet) + return; + + axis_index = tablet->axis_indices[GDK_AXIS_SLIDER]; + + _gdk_device_translate_axis (tablet->stylus_device, axis_index, + position, &tablet->axes[GDK_AXIS_SLIDER]); + + GDK_SEAT_DEBUG (tool->seat, EVENTS, + "tablet tool %d slider %d", + gdk_device_tool_get_tool_type (tool->tool), position); +} + +static void +tablet_tool_handle_wheel (void *data, + struct zwp_tablet_tool_v2 *wp_tablet_tool, + int32_t degrees, + int32_t clicks) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + GdkWaylandSeat *seat; + GdkEvent *event; + + if (!tablet) + return; + + seat = GDK_WAYLAND_SEAT (tablet->seat); + + GDK_SEAT_DEBUG (seat, EVENTS, + "tablet tool %d wheel %d/%d", + gdk_device_tool_get_tool_type (tool->tool), degrees, clicks); + + if (clicks == 0) + return; + + /* Send smooth event */ + event = gdk_scroll_event_new (tablet->pointer_info.focus, + tablet->logical_device, + tablet->current_tool->tool, + tablet->pointer_info.time, + device_get_modifiers (tablet->logical_device), + 0, clicks, + FALSE, + GDK_SCROLL_UNIT_WHEEL); + + _gdk_wayland_display_deliver_event (seat->display, event); +} + +static void +tablet_tool_handle_frame (void *data, + struct zwp_tablet_tool_v2 *wl_tablet_tool, + uint32_t time) +{ + GdkWaylandTabletToolData *tool = data; + GdkWaylandTabletData *tablet = tool->current_tablet; + GdkEvent *frame_event; + + if (!tablet) + return; + + GDK_SEAT_DEBUG (tablet->seat, EVENTS, + "tablet frame, time %d", time); + + frame_event = tablet->pointer_info.frame.event; + + if (frame_event && gdk_event_get_event_type (frame_event) == GDK_PROXIMITY_OUT) + { + tool->current_tablet = NULL; + tablet->current_tool = NULL; + } + + tablet->pointer_info.time = time; + gdk_wayland_tablet_flush_frame_event (tablet, time); +} + +static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { + tablet_tool_handle_type, + tablet_tool_handle_hardware_serial, + tablet_tool_handle_hardware_id_wacom, + tablet_tool_handle_capability, + tablet_tool_handle_done, + tablet_tool_handle_removed, + tablet_tool_handle_proximity_in, + tablet_tool_handle_proximity_out, + tablet_tool_handle_down, + tablet_tool_handle_up, + tablet_tool_handle_motion, + tablet_tool_handle_pressure, + tablet_tool_handle_distance, + tablet_tool_handle_tilt, + tablet_tool_handle_rotation, + tablet_tool_handle_slider, + tablet_tool_handle_wheel, + tablet_tool_handle_button, + tablet_tool_handle_frame, +}; + +static void +tablet_pad_ring_handle_source (void *data, + struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring, + uint32_t source) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad ring handle source, ring = %p source = %d", + wp_tablet_pad_ring, source); + + group->axis_tmp_info.source = source; +} + +static void +tablet_pad_ring_handle_angle (void *data, + struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring, + wl_fixed_t angle) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad ring handle angle, ring = %p angle = %f", + wp_tablet_pad_ring, wl_fixed_to_double (angle)); + + group->axis_tmp_info.value = wl_fixed_to_double (angle); +} + +static void +tablet_pad_ring_handle_stop (void *data, + struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad ring handle stop, ring = %p", wp_tablet_pad_ring); + + group->axis_tmp_info.is_stop = TRUE; +} + +static void +tablet_pad_ring_handle_frame (void *data, + struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring, + uint32_t time) +{ + GdkWaylandTabletPadGroupData *group = data; + GdkWaylandTabletPadData *pad = group->pad; + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); + GdkEvent *event; + + GDK_SEAT_DEBUG (seat, EVENTS, + "tablet pad ring handle frame, ring = %p", wp_tablet_pad_ring); + + event = gdk_pad_event_new_ring (seat->keyboard_focus, + pad->device, + time, + g_list_index (pad->mode_groups, group), + g_list_index (pad->rings, wp_tablet_pad_ring), + group->current_mode, + group->axis_tmp_info.value); + + _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), + event); +} + +static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = { + tablet_pad_ring_handle_source, + tablet_pad_ring_handle_angle, + tablet_pad_ring_handle_stop, + tablet_pad_ring_handle_frame, +}; + +static void +tablet_pad_strip_handle_source (void *data, + struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip, + uint32_t source) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad strip handle source, strip = %p source = %d", + wp_tablet_pad_strip, source); + + group->axis_tmp_info.source = source; +} + +static void +tablet_pad_strip_handle_position (void *data, + struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip, + uint32_t position) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad strip handle position, strip = %p position = %d", + wp_tablet_pad_strip, position); + + group->axis_tmp_info.value = (double) position / 65535; +} + +static void +tablet_pad_strip_handle_stop (void *data, + struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad strip handle stop, strip = %p", + wp_tablet_pad_strip); + + group->axis_tmp_info.is_stop = TRUE; +} + +static void +tablet_pad_strip_handle_frame (void *data, + struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip, + uint32_t time) +{ + GdkWaylandTabletPadGroupData *group = data; + GdkWaylandTabletPadData *pad = group->pad; + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); + GdkEvent *event; + + GDK_SEAT_DEBUG (seat, EVENTS, + "tablet pad strip handle frame, strip = %p", + wp_tablet_pad_strip); + + event = gdk_pad_event_new_strip (seat->keyboard_focus, + pad->device, + time, + g_list_index (pad->mode_groups, group), + g_list_index (pad->strips, wp_tablet_pad_strip), + group->current_mode, + group->axis_tmp_info.value); + + _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), + event); +} + +static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener = { + tablet_pad_strip_handle_source, + tablet_pad_strip_handle_position, + tablet_pad_strip_handle_stop, + tablet_pad_strip_handle_frame, +}; + +static void +tablet_pad_group_handle_buttons (void *data, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, + struct wl_array *buttons) +{ + GdkWaylandTabletPadGroupData *group = data; + uint32_t *p; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad group handle buttons, pad group = %p, n_buttons = %" G_GSIZE_FORMAT, + wp_tablet_pad_group, buttons->size); + + wl_array_for_each (p, buttons) + { + group->buttons = g_list_prepend (group->buttons, GUINT_TO_POINTER (*p)); + } + + group->buttons = g_list_reverse (group->buttons); +} + +static void +tablet_pad_group_handle_ring (void *data, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, + struct zwp_tablet_pad_ring_v2 *wp_tablet_pad_ring) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad group handle ring, pad group = %p, ring = %p", + wp_tablet_pad_group, wp_tablet_pad_ring); + + zwp_tablet_pad_ring_v2_add_listener (wp_tablet_pad_ring, + &tablet_pad_ring_listener, group); + zwp_tablet_pad_ring_v2_set_user_data (wp_tablet_pad_ring, group); + + group->rings = g_list_append (group->rings, wp_tablet_pad_ring); + group->pad->rings = g_list_append (group->pad->rings, wp_tablet_pad_ring); +} + +static void +tablet_pad_group_handle_strip (void *data, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, + struct zwp_tablet_pad_strip_v2 *wp_tablet_pad_strip) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad group handle strip, pad group = %p, strip = %p", + wp_tablet_pad_group, wp_tablet_pad_strip); + + zwp_tablet_pad_strip_v2_add_listener (wp_tablet_pad_strip, + &tablet_pad_strip_listener, group); + zwp_tablet_pad_strip_v2_set_user_data (wp_tablet_pad_strip, group); + + group->strips = g_list_append (group->strips, wp_tablet_pad_strip); + group->pad->strips = g_list_append (group->pad->strips, wp_tablet_pad_strip); +} + +static void +tablet_pad_group_handle_modes (void *data, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, + uint32_t modes) +{ + GdkWaylandTabletPadGroupData *group = data; + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad group handle modes, pad group = %p, n_modes = %d", + wp_tablet_pad_group, modes); + + group->n_modes = modes; +} + +static void +tablet_pad_group_handle_done (void *data, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group) +{ +#ifdef G_ENABLE_DEBUG + GdkWaylandTabletPadGroupData *group = data; +#endif + + GDK_SEAT_DEBUG (group->pad->seat, EVENTS, + "tablet pad group handle done, pad group = %p", + wp_tablet_pad_group); +} + +static void +tablet_pad_group_handle_mode (void *data, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group, + uint32_t time, + uint32_t serial, + uint32_t mode) +{ + GdkWaylandTabletPadGroupData *group = data; + GdkWaylandTabletPadData *pad = group->pad; + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (pad->seat); + GdkEvent *event; + guint n_group; + + GDK_SEAT_DEBUG (seat, EVENTS, + "tablet pad group handle mode, pad group = %p, mode = %d", + wp_tablet_pad_group, mode); + + group->mode_switch_serial = serial; + group->current_mode = mode; + n_group = g_list_index (pad->mode_groups, group); + + event = gdk_pad_event_new_group_mode (seat->keyboard_focus, + pad->device, + time, + n_group, + mode); + + _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), + event); +} + +static const struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener = { + tablet_pad_group_handle_buttons, + tablet_pad_group_handle_ring, + tablet_pad_group_handle_strip, + tablet_pad_group_handle_modes, + tablet_pad_group_handle_done, + tablet_pad_group_handle_mode, +}; + +static void +tablet_pad_handle_group (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad, + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group) +{ + GdkWaylandTabletPadData *pad = data; + GdkWaylandTabletPadGroupData *group; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle group, pad group = %p, group = %p", + wp_tablet_pad_group, wp_tablet_pad_group); + + group = g_new0 (GdkWaylandTabletPadGroupData, 1); + group->wp_tablet_pad_group = wp_tablet_pad_group; + group->pad = pad; + + zwp_tablet_pad_group_v2_add_listener (wp_tablet_pad_group, + &tablet_pad_group_listener, group); + zwp_tablet_pad_group_v2_set_user_data (wp_tablet_pad_group, group); + pad->mode_groups = g_list_append (pad->mode_groups, group); +} + +static void +tablet_pad_handle_path (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad, + const char *path) +{ + GdkWaylandTabletPadData *pad = data; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle path, pad = %p, path = %s", + wp_tablet_pad, path); + + pad->path = g_strdup (path); +} + +static void +tablet_pad_handle_buttons (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad, + uint32_t buttons) +{ + GdkWaylandTabletPadData *pad = data; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle buttons, pad = %p, n_buttons = %d", + wp_tablet_pad, buttons); + + pad->n_buttons = buttons; +} + +static void +tablet_pad_handle_done (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad) +{ + GdkWaylandTabletPadData *pad = data; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle done, pad = %p", wp_tablet_pad); + + pad->device = + g_object_new (GDK_TYPE_WAYLAND_DEVICE_PAD, + "name", "Pad device", + "source", GDK_SOURCE_TABLET_PAD, + "display", gdk_seat_get_display (pad->seat), + "seat", pad->seat, + NULL); + + _gdk_device_set_associated_device (pad->device, GDK_WAYLAND_SEAT (pad->seat)->logical_keyboard); + gdk_seat_device_added (GDK_SEAT (pad->seat), pad->device); +} + +static void +tablet_pad_handle_button (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad, + uint32_t time, + uint32_t button, + uint32_t state) +{ + GdkWaylandTabletPadData *pad = data; + GdkWaylandTabletPadGroupData *group; + GdkEvent *event; + int n_group; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle button, pad = %p, button = %d, state = %d", + wp_tablet_pad, button, state); + + group = tablet_pad_lookup_button_group (pad, button); + +#ifdef G_DISABLE_ASSERT + if (group == NULL) + return; +#else + g_assert (group != NULL); +#endif + + n_group = g_list_index (pad->mode_groups, group); + + event = gdk_pad_event_new_button (state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED + ? GDK_PAD_BUTTON_PRESS + : GDK_PAD_BUTTON_RELEASE, + GDK_WAYLAND_SEAT (pad->seat)->keyboard_focus, + pad->device, + time, + n_group, + button, + group->current_mode); + + _gdk_wayland_display_deliver_event (gdk_seat_get_display (pad->seat), event); +} + +static void +tablet_pad_handle_enter (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad, + uint32_t serial, + struct zwp_tablet_v2 *wp_tablet, + struct wl_surface *surface) +{ + GdkWaylandTabletPadData *pad = data; + GdkWaylandTabletData *tablet = zwp_tablet_v2_get_user_data (wp_tablet); + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle enter, pad = %p, tablet = %p surface = %p", + wp_tablet_pad, wp_tablet, surface); + + /* Relate pad and tablet */ + tablet->pads = g_list_prepend (tablet->pads, pad); + pad->current_tablet = tablet; +} + +static void +tablet_pad_handle_leave (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad, + uint32_t serial, + struct wl_surface *surface) +{ + GdkWaylandTabletPadData *pad = data; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle leave, pad = %p, surface = %p", + wp_tablet_pad, surface); + + if (pad->current_tablet) + { + pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad); + pad->current_tablet = NULL; + } +} + +static void +tablet_pad_handle_removed (void *data, + struct zwp_tablet_pad_v2 *wp_tablet_pad) +{ + GdkWaylandTabletPadData *pad = data; + + GDK_SEAT_DEBUG (pad->seat, EVENTS, + "tablet pad handle removed, pad = %p", wp_tablet_pad); + + /* Remove from the current tablet */ + if (pad->current_tablet) + { + pad->current_tablet->pads = g_list_remove (pad->current_tablet->pads, pad); + pad->current_tablet = NULL; + } + + _gdk_wayland_seat_remove_tablet_pad (GDK_WAYLAND_SEAT (pad->seat), pad); +} + +static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { + tablet_pad_handle_group, + tablet_pad_handle_path, + tablet_pad_handle_buttons, + tablet_pad_handle_done, + tablet_pad_handle_button, + tablet_pad_handle_enter, + tablet_pad_handle_leave, + tablet_pad_handle_removed, +}; + +static void +tablet_seat_handle_tablet_added (void *data, + struct zwp_tablet_seat_v2 *wp_tablet_seat, + struct zwp_tablet_v2 *wp_tablet) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTabletData *tablet; + + tablet = g_new0 (GdkWaylandTabletData, 1); + tablet->seat = GDK_SEAT (seat); + + tablet->wp_tablet = wp_tablet; + + seat->tablets = g_list_prepend (seat->tablets, tablet); + + zwp_tablet_v2_add_listener (wp_tablet, &tablet_listener, tablet); + zwp_tablet_v2_set_user_data (wp_tablet, tablet); +} + +static void +tablet_seat_handle_tool_added (void *data, + struct zwp_tablet_seat_v2 *wp_tablet_seat, + struct zwp_tablet_tool_v2 *wp_tablet_tool) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTabletToolData *tool; + + tool = g_new0 (GdkWaylandTabletToolData, 1); + tool->wp_tablet_tool = wp_tablet_tool; + tool->seat = GDK_SEAT (seat); + + zwp_tablet_tool_v2_add_listener (wp_tablet_tool, &tablet_tool_listener, tool); + zwp_tablet_tool_v2_set_user_data (wp_tablet_tool, tool); + + seat->tablet_tools = g_list_prepend (seat->tablet_tools, tool); +} + +static void +tablet_seat_handle_pad_added (void *data, + struct zwp_tablet_seat_v2 *wp_tablet_seat, + struct zwp_tablet_pad_v2 *wp_tablet_pad) +{ + GdkWaylandSeat *seat = data; + GdkWaylandTabletPadData *pad; + + pad = g_new0 (GdkWaylandTabletPadData, 1); + pad->wp_tablet_pad = wp_tablet_pad; + pad->seat = GDK_SEAT (seat); + + zwp_tablet_pad_v2_add_listener (wp_tablet_pad, &tablet_pad_listener, pad); + zwp_tablet_pad_v2_set_user_data (wp_tablet_pad, pad); + + seat->tablet_pads = g_list_prepend (seat->tablet_pads, pad); +} + +static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { + tablet_seat_handle_tablet_added, + tablet_seat_handle_tool_added, + tablet_seat_handle_pad_added, +}; + +static void +init_devices (GdkWaylandSeat *seat) +{ + /* pointer */ + seat->logical_pointer = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Core Pointer", + "source", GDK_SOURCE_MOUSE, + "has-cursor", TRUE, + "display", seat->display, + "seat", seat, + NULL); + + GDK_WAYLAND_DEVICE (seat->logical_pointer)->pointer = &seat->pointer_info; + + /* keyboard */ + seat->logical_keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE, + "name", "Core Keyboard", + "source", GDK_SOURCE_KEYBOARD, + "has-cursor", FALSE, + "display", seat->display, + "seat", seat, + NULL); + _gdk_device_reset_axes (seat->logical_keyboard); + + /* link both */ + _gdk_device_set_associated_device (seat->logical_pointer, seat->logical_keyboard); + _gdk_device_set_associated_device (seat->logical_keyboard, seat->logical_pointer); + + gdk_seat_device_added (GDK_SEAT (seat), seat->logical_pointer); + gdk_seat_device_added (GDK_SEAT (seat), seat->logical_keyboard); +} + +static void +pointer_surface_update_scale (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); + guint32 scale; + GSList *l; + + if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE) + { + /* We can't set the scale on this surface */ + return; + } + + if (!pointer->pointer_surface_outputs) + return; + + scale = 1; + for (l = pointer->pointer_surface_outputs; l != NULL; l = l->next) + { + guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data); + scale = MAX (scale, output_scale); + } + + if (pointer->current_output_scale == scale) + return; + pointer->current_output_scale = scale; + + gdk_wayland_device_update_surface_cursor (device); +} + +void +gdk_wayland_seat_update_cursor_scale (GdkWaylandSeat *seat) +{ + GList *l; + + pointer_surface_update_scale (seat->logical_pointer); + + for (l = seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + pointer_surface_update_scale (tablet->logical_device); + } +} + +static void +pointer_surface_enter (void *data, + struct wl_surface *wl_surface, + struct wl_output *output) + +{ + GdkDevice *device = data; + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandTabletData *tablet; + + GDK_SEAT_DEBUG (seat, EVENTS, + "pointer surface of seat %p entered output %p", + seat, output); + + tablet = gdk_wayland_seat_find_tablet (seat, device); + + if (tablet) + { + tablet->pointer_info.pointer_surface_outputs = + g_slist_append (tablet->pointer_info.pointer_surface_outputs, output); + } + else + { + seat->pointer_info.pointer_surface_outputs = + g_slist_append (seat->pointer_info.pointer_surface_outputs, output); + } + + pointer_surface_update_scale (device); +} + +static void +pointer_surface_leave (void *data, + struct wl_surface *wl_surface, + struct wl_output *output) +{ + GdkDevice *device = data; + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandTabletData *tablet; + + GDK_SEAT_DEBUG (seat, EVENTS, + "pointer surface of seat %p left output %p", + seat, output); + + tablet = gdk_wayland_seat_find_tablet (seat, device); + + if (tablet) + { + tablet->pointer_info.pointer_surface_outputs = + g_slist_remove (tablet->pointer_info.pointer_surface_outputs, output); + } + else + { + seat->pointer_info.pointer_surface_outputs = + g_slist_remove (seat->pointer_info.pointer_surface_outputs, output); + } + + pointer_surface_update_scale (device); +} + +static const struct wl_surface_listener pointer_surface_listener = { + pointer_surface_enter, + pointer_surface_leave +}; + +static void +gdk_wayland_pointer_data_finalize (GdkWaylandPointerData *pointer) +{ + g_clear_object (&pointer->focus); + g_clear_object (&pointer->cursor); + wl_surface_destroy (pointer->pointer_surface); + g_slist_free (pointer->pointer_surface_outputs); +} + +static void +gdk_wayland_seat_finalize (GObject *object) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (object); + GList *l; + + for (l = seat->tablet_tools; l != NULL; l = l->next) + _gdk_wayland_seat_remove_tool (seat, l->data); + + for (l = seat->tablet_pads; l != NULL; l = l->next) + _gdk_wayland_seat_remove_tablet_pad (seat, l->data); + + for (l = seat->tablets; l != NULL; l = l->next) + _gdk_wayland_seat_remove_tablet (seat, l->data); + + seat_handle_capabilities (seat, seat->wl_seat, 0); + g_object_unref (seat->keymap); + gdk_wayland_pointer_data_finalize (&seat->pointer_info); + /* FIXME: destroy data_device */ + g_clear_object (&seat->drag); + g_clear_object (&seat->drop); + g_clear_object (&seat->clipboard); + g_clear_object (&seat->primary_clipboard); + g_hash_table_destroy (seat->touches); + zwp_tablet_seat_v2_destroy (seat->wp_tablet_seat); + stop_key_repeat (seat); + + G_OBJECT_CLASS (gdk_wayland_seat_parent_class)->finalize (object); +} + +static GdkSeatCapabilities +gdk_wayland_seat_get_capabilities (GdkSeat *seat) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + GdkSeatCapabilities caps = 0; + + if (wayland_seat->logical_pointer) + caps |= GDK_SEAT_CAPABILITY_POINTER; + if (wayland_seat->logical_keyboard) + caps |= GDK_SEAT_CAPABILITY_KEYBOARD; + if (wayland_seat->logical_touch) + caps |= GDK_SEAT_CAPABILITY_TOUCH; + + return caps; +} + +static void +gdk_wayland_seat_set_grab_surface (GdkWaylandSeat *seat, + GdkSurface *surface) +{ + if (seat->grab_surface) + { + _gdk_wayland_surface_set_grab_seat (seat->grab_surface, NULL); + g_object_remove_weak_pointer (G_OBJECT (seat->grab_surface), + (gpointer *) &seat->grab_surface); + seat->grab_surface = NULL; + } + + if (surface) + { + seat->grab_surface = surface; + g_object_add_weak_pointer (G_OBJECT (surface), + (gpointer *) &seat->grab_surface); + _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (seat)); + } +} + +static GdkGrabStatus +gdk_wayland_seat_grab (GdkSeat *seat, + GdkSurface *surface, + GdkSeatCapabilities capabilities, + gboolean owner_events, + GdkCursor *cursor, + GdkEvent *event, + GdkSeatGrabPrepareFunc prepare_func, + gpointer prepare_func_data) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + guint32 evtime = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME; + GdkDisplay *display = gdk_seat_get_display (seat); + GList *l; + + if (surface == NULL || GDK_SURFACE_DESTROYED (surface)) + return GDK_GRAB_NOT_VIEWABLE; + + gdk_wayland_seat_set_grab_surface (wayland_seat, surface); + wayland_seat->grab_time = evtime; + + if (prepare_func) + (prepare_func) (seat, surface, prepare_func_data); + + if (!gdk_wayland_surface_has_surface (surface)) + { + gdk_wayland_seat_set_grab_surface (wayland_seat, NULL); + return GDK_GRAB_NOT_VIEWABLE; + } + + if (wayland_seat->logical_pointer && + capabilities & GDK_SEAT_CAPABILITY_POINTER) + { + device_maybe_emit_grab_crossing (wayland_seat->logical_pointer, + surface, evtime); + + _gdk_display_add_device_grab (display, + wayland_seat->logical_pointer, + surface, + owner_events, + GDK_ALL_EVENTS_MASK, + _gdk_display_get_next_serial (display), + evtime, + FALSE); + + gdk_wayland_seat_set_global_cursor (seat, cursor); + g_set_object (&wayland_seat->cursor, cursor); + gdk_wayland_device_update_surface_cursor (wayland_seat->logical_pointer); + } + + if (wayland_seat->logical_touch && + capabilities & GDK_SEAT_CAPABILITY_TOUCH) + { + device_maybe_emit_grab_crossing (wayland_seat->logical_touch, + surface, evtime); + + _gdk_display_add_device_grab (display, + wayland_seat->logical_touch, + surface, + owner_events, + GDK_ALL_EVENTS_MASK, + _gdk_display_get_next_serial (display), + evtime, + FALSE); + } + + if (wayland_seat->logical_keyboard && + capabilities & GDK_SEAT_CAPABILITY_KEYBOARD) + { + device_maybe_emit_grab_crossing (wayland_seat->logical_keyboard, + surface, evtime); + + _gdk_display_add_device_grab (display, + wayland_seat->logical_keyboard, + surface, + owner_events, + GDK_ALL_EVENTS_MASK, + _gdk_display_get_next_serial (display), + evtime, + FALSE); + + /* Inhibit shortcuts if the seat grab is for the keyboard only */ + if (capabilities == GDK_SEAT_CAPABILITY_KEYBOARD) + gdk_wayland_surface_inhibit_shortcuts (surface, seat); + } + + if (wayland_seat->tablets && + capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS) + { + for (l = wayland_seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + + device_maybe_emit_grab_crossing (tablet->logical_device, + surface, + evtime); + + _gdk_display_add_device_grab (display, + tablet->logical_device, + surface, + owner_events, + GDK_ALL_EVENTS_MASK, + _gdk_display_get_next_serial (display), + evtime, + FALSE); + + gdk_wayland_device_update_surface_cursor (tablet->logical_device); + } + } + + return GDK_GRAB_SUCCESS; +} + +static void +gdk_wayland_seat_ungrab (GdkSeat *seat) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + GdkDisplay *display = gdk_seat_get_display (seat); + GdkDeviceGrabInfo *grab; + GList *l; + + g_clear_object (&wayland_seat->grab_cursor); + + gdk_wayland_seat_set_grab_surface (wayland_seat, NULL); + + if (wayland_seat->logical_pointer) + { + device_maybe_emit_ungrab_crossing (wayland_seat->logical_pointer, + GDK_CURRENT_TIME); + + gdk_wayland_device_update_surface_cursor (wayland_seat->logical_pointer); + } + + if (wayland_seat->logical_keyboard) + { + GdkSurface *prev_focus; + + prev_focus = device_maybe_emit_ungrab_crossing (wayland_seat->logical_keyboard, + GDK_CURRENT_TIME); + if (prev_focus) + gdk_wayland_surface_restore_shortcuts (prev_focus, seat); + } + + if (wayland_seat->logical_touch) + { + grab = _gdk_display_get_last_device_grab (display, wayland_seat->logical_touch); + + if (grab) + grab->serial_end = grab->serial_start; + } + + for (l = wayland_seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + + grab = _gdk_display_get_last_device_grab (display, tablet->logical_device); + + if (grab) + grab->serial_end = grab->serial_start; + } +} + +static GdkDevice * +gdk_wayland_seat_get_logical_device (GdkSeat *seat, + GdkSeatCapabilities capabilities) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + + if (capabilities == GDK_SEAT_CAPABILITY_POINTER) + return wayland_seat->logical_pointer; + else if (capabilities == GDK_SEAT_CAPABILITY_KEYBOARD) + return wayland_seat->logical_keyboard; + else if (capabilities == GDK_SEAT_CAPABILITY_TOUCH) + return wayland_seat->logical_touch; + + return NULL; +} + +static GList * +gdk_wayland_seat_get_devices (GdkSeat *seat, + GdkSeatCapabilities capabilities) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + GList *physical_devices = NULL; + + if (wayland_seat->finger_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) + physical_devices = g_list_prepend (physical_devices, wayland_seat->finger_scrolling); + if (wayland_seat->continuous_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) + physical_devices = g_list_prepend (physical_devices, wayland_seat->continuous_scrolling); + if (wayland_seat->wheel_scrolling && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) + physical_devices = g_list_prepend (physical_devices, wayland_seat->wheel_scrolling); + if (wayland_seat->pointer && (capabilities & GDK_SEAT_CAPABILITY_POINTER)) + physical_devices = g_list_prepend (physical_devices, wayland_seat->pointer); + if (wayland_seat->keyboard && (capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)) + physical_devices = g_list_prepend (physical_devices, wayland_seat->keyboard); + if (wayland_seat->touch && (capabilities & GDK_SEAT_CAPABILITY_TOUCH)) + physical_devices = g_list_prepend (physical_devices, wayland_seat->touch); + + if (wayland_seat->tablets && (capabilities & GDK_SEAT_CAPABILITY_TABLET_STYLUS)) + { + GList *l; + + for (l = wayland_seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + + physical_devices = g_list_prepend (physical_devices, tablet->stylus_device); + } + } + + if (wayland_seat->tablet_pads && (capabilities & GDK_SEAT_CAPABILITY_TABLET_PAD)) + { + GList *l; + + for (l = wayland_seat->tablet_pads; l; l = l->next) + { + GdkWaylandTabletPadData *data = l->data; + physical_devices = g_list_prepend (physical_devices, data->device); + } + } + + return physical_devices; +} + +static GList * +gdk_wayland_seat_get_tools (GdkSeat *seat) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + GList *tools = NULL, *l; + + for (l = wayland_seat->tablet_tools; l; l = l->next) + { + GdkWaylandTabletToolData *tool = l->data; + + tools = g_list_prepend (tools, tool->tool); + } + + return tools; +} + +static void +gdk_wayland_seat_class_init (GdkWaylandSeatClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkSeatClass *seat_class = GDK_SEAT_CLASS (klass); + + object_class->finalize = gdk_wayland_seat_finalize; + + seat_class->get_capabilities = gdk_wayland_seat_get_capabilities; + seat_class->grab = gdk_wayland_seat_grab; + seat_class->ungrab = gdk_wayland_seat_ungrab; + seat_class->get_logical_device = gdk_wayland_seat_get_logical_device; + seat_class->get_devices = gdk_wayland_seat_get_devices; + seat_class->get_tools = gdk_wayland_seat_get_tools; +} + +static void +gdk_wayland_seat_init (GdkWaylandSeat *seat) +{ +} + +static void +init_pointer_data (GdkWaylandPointerData *pointer_data, + GdkDisplay *display, + GdkDevice *logical_device) +{ + GdkWaylandDisplay *display_wayland; + + display_wayland = GDK_WAYLAND_DISPLAY (display); + + pointer_data->current_output_scale = 1; + pointer_data->pointer_surface = + wl_compositor_create_surface (display_wayland->compositor); + wl_surface_add_listener (pointer_data->pointer_surface, + &pointer_surface_listener, + logical_device); +} + +void +_gdk_wayland_display_create_seat (GdkWaylandDisplay *display_wayland, + guint32 id, + struct wl_seat *wl_seat) +{ + GdkDisplay *display = GDK_DISPLAY (display_wayland); + GdkWaylandSeat *seat; + + seat = g_object_new (GDK_TYPE_WAYLAND_SEAT, + "display", display_wayland, + NULL); + seat->id = id; + seat->keymap = _gdk_wayland_keymap_new (display); + seat->display = display; + seat->touches = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_free); + seat->wl_seat = wl_seat; + + wl_seat_add_listener (seat->wl_seat, &seat_listener, seat); + wl_seat_set_user_data (seat->wl_seat, seat); + + if (display_wayland->primary_selection_manager) + { + seat->primary_clipboard = gdk_wayland_primary_new (seat); + } + else + { + /* If the compositor doesn't support primary clipboard, + * just do it local-only */ + seat->primary_clipboard = gdk_clipboard_new (display); + } + + seat->data_device = + wl_data_device_manager_get_data_device (display_wayland->data_device_manager, + seat->wl_seat); + seat->clipboard = gdk_wayland_clipboard_new (display); + wl_data_device_add_listener (seat->data_device, + &data_device_listener, seat); + + init_devices (seat); + init_pointer_data (&seat->pointer_info, display, seat->logical_pointer); + + if (display_wayland->tablet_manager) + { + seat->wp_tablet_seat = + zwp_tablet_manager_v2_get_tablet_seat (display_wayland->tablet_manager, + wl_seat); + zwp_tablet_seat_v2_add_listener (seat->wp_tablet_seat, &tablet_seat_listener, + seat); + } + + if (display->clipboard == NULL) + display->clipboard = g_object_ref (seat->clipboard); + if (display->primary_clipboard == NULL) + display->primary_clipboard = g_object_ref (seat->primary_clipboard); + + gdk_display_add_seat (display, GDK_SEAT (seat)); +} + +void +_gdk_wayland_display_remove_seat (GdkWaylandDisplay *display_wayland, + guint32 id) +{ + GdkDisplay *display = GDK_DISPLAY (display_wayland); + GList *l, *seats; + + seats = gdk_display_list_seats (display); + + for (l = seats; l != NULL; l = l->next) + { + GdkWaylandSeat *seat = l->data; + + if (seat->id != id) + continue; + + gdk_display_remove_seat (display, GDK_SEAT (seat)); + break; + } + + g_list_free (seats); +} + +uint32_t +_gdk_wayland_seat_get_implicit_grab_serial (GdkSeat *seat, + GdkEvent *event) +{ + GdkEventSequence *sequence = NULL; + GdkWaylandTouchData *touch = NULL; + + if (event) + sequence = gdk_event_get_event_sequence (event); + + if (sequence) + touch = gdk_wayland_seat_get_touch (GDK_WAYLAND_SEAT (seat), + GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); + + if (touch) + return touch->touch_down_serial; + + if (event) + { + GdkDevice *source = gdk_event_get_device (event); + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + GList *l; + + for (l = wayland_seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + + if (tablet->stylus_device == source) + return tablet->pointer_info.press_serial; + } + } + + return GDK_WAYLAND_SEAT (seat)->pointer_info.press_serial; +} + +uint32_t +_gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat, + GdkEventSequence **sequence) +{ + GdkWaylandTouchData *touch; + GHashTableIter iter; + GList *l; + uint32_t serial; + + g_hash_table_iter_init (&iter, seat->touches); + + if (sequence) + *sequence = NULL; + + serial = seat->keyboard_key_serial; + + if (seat->pointer_info.press_serial > serial) + serial = seat->pointer_info.press_serial; + + for (l = seat->tablets; l; l = l->next) + { + GdkWaylandTabletData *tablet = l->data; + + if (tablet->pointer_info.press_serial > serial) + serial = tablet->pointer_info.press_serial; + } + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch)) + { + if (touch->touch_down_serial > serial) + { + if (sequence) + *sequence = GDK_SLOT_TO_EVENT_SEQUENCE (touch->id); + serial = touch->touch_down_serial; + } + } + + return serial; +} + +void +gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device, + GdkEventSequence *sequence) +{ + GdkWaylandSeat *seat; + GdkWaylandTouchData *touch; + GdkEvent *event; + + g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); + touch = gdk_wayland_seat_get_touch (seat, + GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); + + if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch == touch) + { + GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL; + emulate_touch_crossing (touch->surface, NULL, + seat->logical_touch, seat->touch, + touch, GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, + GDK_CURRENT_TIME); + } + + event = gdk_touch_event_new (GDK_TOUCH_CANCEL, + GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), + touch->surface, + seat->logical_touch, + GDK_CURRENT_TIME, + device_get_modifiers (seat->logical_touch), + touch->x, touch->y, + NULL, + touch->initial_touch); + _gdk_wayland_display_deliver_event (seat->display, event); +} + +void +gdk_wayland_seat_set_global_cursor (GdkSeat *seat, + GdkCursor *cursor) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + GdkDevice *pointer; + + pointer = gdk_seat_get_pointer (seat); + + g_set_object (&wayland_seat->grab_cursor, cursor); + gdk_wayland_device_set_surface_cursor (pointer, + gdk_wayland_device_get_focus (pointer), + NULL); +} + +void +gdk_wayland_seat_set_drag (GdkSeat *seat, + GdkDrag *drag) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (seat); + + g_set_object (&wayland_seat->drag, drag); +} + +/** + * gdk_wayland_device_get_data_device: (skip) + * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_data_device` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_data_device` + */ +struct wl_data_device * +gdk_wayland_device_get_data_device (GdkDevice *gdk_device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); + return seat->data_device; +} + +/** + * gdk_wayland_device_set_selection: (skip) + * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` + * @source: the data source for the selection + * + * Sets the selection of the `GdkDevice. + * + * This is calling wl_data_device_set_selection() on + * the `wl_data_device` of @gdk_device. + */ +void +gdk_wayland_device_set_selection (GdkDevice *gdk_device, + struct wl_data_source *source) +{ + GdkWaylandSeat *seat; + guint32 serial; + + g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); + serial = _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL); + wl_data_device_set_selection (seat->data_device, source, serial); +} + +/** + * gdk_wayland_seat_get_wl_seat: (skip) + * @seat: (type GdkWaylandSeat): a `GdkSeat` + * + * Returns the Wayland `wl_seat` of a `GdkSeat`. + * + * Returns: (transfer none): a Wayland `wl_seat` + */ +struct wl_seat * +gdk_wayland_seat_get_wl_seat (GdkSeat *seat) +{ + g_return_val_if_fail (GDK_IS_WAYLAND_SEAT (seat), NULL); + + return GDK_WAYLAND_SEAT (seat)->wl_seat; +} + +/** + * gdk_wayland_device_get_node_path: + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the `/dev/input/event*` path of this device. + * + * For `GdkDevice`s that possibly coalesce multiple hardware + * devices (eg. mouse, keyboard, touch,...), this function + * will return %NULL. + * + * This is most notably implemented for devices of type + * %GDK_SOURCE_PEN, %GDK_SOURCE_TABLET_PAD. + * + * Returns: (nullable) (transfer none): the `/dev/input/event*` + * path of this device + */ +const char * +gdk_wayland_device_get_node_path (GdkDevice *device) +{ + GdkWaylandTabletData *tablet; + GdkWaylandTabletPadData *pad; + + GdkSeat *seat; + + g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); + + seat = gdk_device_get_seat (device); + tablet = gdk_wayland_seat_find_tablet (GDK_WAYLAND_SEAT (seat), device); + if (tablet) + return tablet->path; + + pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); + if (pad) + return pad->path; + + return NULL; +} + +/* + * gdk_wayland_device_pad_set_feedback: + * @device: (type GdkWaylandDevice): a %GDK_SOURCE_TABLET_PAD device + * @feature: Feature to set the feedback label for + * @feature_idx: 0-indexed index of the feature to set the feedback label for + * @label: Feedback label + * + * Sets the feedback label for the given feature/index. + * + * This may be used by the compositor to provide user feedback + * of the actions available/performed. + */ +void +gdk_wayland_device_pad_set_feedback (GdkDevice *device, + GdkDevicePadFeature feature, + guint feature_idx, + const char *label) +{ + GdkWaylandTabletPadData *pad; + GdkWaylandTabletPadGroupData *group; + GdkSeat *seat; + + seat = gdk_device_get_seat (device); + pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); + if (!pad) + return; + + if (feature == GDK_DEVICE_PAD_FEATURE_BUTTON) + { + group = tablet_pad_lookup_button_group (pad, feature_idx); + if (!group) + return; + + zwp_tablet_pad_v2_set_feedback (pad->wp_tablet_pad, feature_idx, label, + group->mode_switch_serial); + } + else if (feature == GDK_DEVICE_PAD_FEATURE_RING) + { + struct zwp_tablet_pad_ring_v2 *wp_pad_ring; + + wp_pad_ring = g_list_nth_data (pad->rings, feature_idx); + if (!wp_pad_ring) + return; + + group = zwp_tablet_pad_ring_v2_get_user_data (wp_pad_ring); + zwp_tablet_pad_ring_v2_set_feedback (wp_pad_ring, label, + group->mode_switch_serial); + + } + else if (feature == GDK_DEVICE_PAD_FEATURE_STRIP) + { + struct zwp_tablet_pad_strip_v2 *wp_pad_strip; + + wp_pad_strip = g_list_nth_data (pad->strips, feature_idx); + if (!wp_pad_strip) + return; + + group = zwp_tablet_pad_strip_v2_get_user_data (wp_pad_strip); + zwp_tablet_pad_strip_v2_set_feedback (wp_pad_strip, label, + group->mode_switch_serial); + } +} diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 7e7672af9f..76a069975f 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -5,7 +5,6 @@ gdk_wayland_sources = files([ 'gdkcairocontext-wayland.c', 'gdkclipboard-wayland.c', 'gdkcursor-wayland.c', - 'gdkdevice-wayland.c', 'gdkdisplay-wayland.c', 'gdkdrag-wayland.c', 'gdkdragsurface-wayland.c', @@ -15,6 +14,7 @@ gdk_wayland_sources = files([ 'gdkkeys-wayland.c', 'gdkmonitor-wayland.c', 'gdkprimary-wayland.c', + 'gdkseat-wayland.c', 'gdksurface-wayland.c', 'gdktoplevel-wayland.c', 'gdkpopup-wayland.c', -- cgit v1.2.1 From e5cd9354d5337c545b0a20955772c89954e45ba1 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 2 Feb 2023 17:14:22 +0100 Subject: gdk/wayland: Move GdkWaylandDevice data to private struct Before splitting this object, avoid leaking details in its struct. --- gdk/wayland/gdkdevice-wayland-private.h | 12 ++++ gdk/wayland/gdkseat-wayland.c | 117 +++++++++++++++++++++++--------- 2 files changed, 97 insertions(+), 32 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland-private.h b/gdk/wayland/gdkdevice-wayland-private.h index b22a4f3814..c159462d86 100644 --- a/gdk/wayland/gdkdevice-wayland-private.h +++ b/gdk/wayland/gdkdevice-wayland-private.h @@ -3,6 +3,18 @@ #include "gdkwaylanddevice.h" +#include + +struct _GdkWaylandDevice +{ + GdkDevice parent_instance; +}; + +struct _GdkWaylandDeviceClass +{ + GdkDeviceClass parent_class; +}; + void gdk_wayland_device_query_state (GdkDevice *device, GdkSurface *surface, double *win_x, diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c index 90ecad458a..ee6532ff50 100644 --- a/gdk/wayland/gdkseat-wayland.c +++ b/gdk/wayland/gdkseat-wayland.c @@ -292,19 +292,13 @@ struct _GdkWaylandSeat G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT) -struct _GdkWaylandDevice +typedef struct { - GdkDevice parent_instance; GdkWaylandTouchData *emulating_touch; /* Only used on wd->logical_touch */ GdkWaylandPointerData *pointer; -}; - -struct _GdkWaylandDeviceClass -{ - GdkDeviceClass parent_class; -}; +} GdkWaylandDevicePrivate; -G_DEFINE_TYPE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) +G_DEFINE_TYPE_WITH_PRIVATE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) struct _GdkWaylandDevicePad { @@ -387,12 +381,51 @@ gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, return NULL; } +static GdkWaylandPointerData * +gdk_wayland_device_get_pointer (GdkWaylandDevice *wayland_device) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + return priv->pointer; +} + +static void +gdk_wayland_device_set_pointer (GdkWaylandDevice *wayland_device, + GdkWaylandPointerData *pointer) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + priv->pointer = pointer; +} + +static GdkWaylandTouchData * +gdk_wayland_device_get_emulating_touch (GdkWaylandDevice *wayland_device) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + return priv->emulating_touch; +} + +static void +gdk_wayland_device_set_emulating_touch (GdkWaylandDevice *wayland_device, + GdkWaylandTouchData *touch) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + priv->emulating_touch = touch; +} static gboolean gdk_wayland_device_update_surface_cursor (GdkDevice *device) { GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); struct wl_buffer *buffer; int x, y, w, h, scale; guint next_image_index, next_image_delay; @@ -497,7 +530,9 @@ gdk_wayland_device_set_surface_cursor (GdkDevice *device, GdkCursor *cursor) { GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); if (device == seat->logical_touch) return; @@ -540,7 +575,9 @@ static GdkModifierType device_get_modifiers (GdkDevice *device) { GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); GdkModifierType mask; mask = seat->key_modifiers; @@ -558,13 +595,14 @@ gdk_wayland_device_query_state (GdkDevice *device, double *win_y, GdkModifierType *mask) { + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); GdkWaylandPointerData *pointer; double x, y; if (mask) *mask = device_get_modifiers (device); - pointer = GDK_WAYLAND_DEVICE (device)->pointer; + pointer = gdk_wayland_device_get_pointer (wayland_device); if (pointer->focus == surface) { @@ -669,13 +707,14 @@ GdkSurface * gdk_wayland_device_get_focus (GdkDevice *device) { GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); GdkWaylandPointerData *pointer; if (device == wayland_seat->logical_keyboard) return wayland_seat->keyboard_focus; else { - pointer = GDK_WAYLAND_DEVICE (device)->pointer; + pointer = gdk_wayland_device_get_pointer (wayland_device); if (pointer) return pointer->focus; @@ -730,7 +769,9 @@ gdk_wayland_device_grab (GdkDevice *device, guint32 time_) { GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); if (GDK_IS_DRAG_SURFACE (surface) && gdk_surface_get_mapped (surface)) @@ -781,7 +822,9 @@ static void gdk_wayland_device_ungrab (GdkDevice *device, guint32 time_) { - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); GdkSurface *prev_focus; prev_focus = device_maybe_emit_ungrab_crossing (device, time_); @@ -810,9 +853,10 @@ gdk_wayland_device_surface_at_position (GdkDevice *device, double *win_y, GdkModifierType *mask) { + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); GdkWaylandPointerData *pointer; - pointer = GDK_WAYLAND_DEVICE(device)->pointer; + pointer = gdk_wayland_device_get_pointer (wayland_device); if (!pointer) return NULL; @@ -2476,9 +2520,10 @@ static void mimic_pointer_emulating_touch_info (GdkDevice *device, GdkWaylandTouchData *touch) { + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); GdkWaylandPointerData *pointer; - pointer = GDK_WAYLAND_DEVICE (device)->pointer; + pointer = gdk_wayland_device_get_pointer (wayland_device); g_set_object (&pointer->focus, touch->surface); pointer->press_serial = pointer->enter_serial = touch->touch_down_serial; pointer->surface_x = touch->x; @@ -2492,7 +2537,7 @@ touch_handle_logical_pointer_crossing (GdkWaylandSeat *seat, { GdkWaylandPointerData *pointer; - pointer = GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer; + pointer = gdk_wayland_device_get_pointer (GDK_WAYLAND_DEVICE (seat->logical_touch)); if (pointer->focus == touch->surface) return; @@ -2547,7 +2592,8 @@ touch_handle_down (void *data, if (touch->initial_touch) { touch_handle_logical_pointer_crossing (seat, touch, time); - GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = touch; + gdk_wayland_device_set_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch), + touch); mimic_pointer_emulating_touch_info (seat->logical_touch, touch); } @@ -2596,7 +2642,8 @@ touch_handle_up (void *data, _gdk_wayland_display_deliver_event (seat->display, event); if (touch->initial_touch) - GDK_WAYLAND_DEVICE(seat->logical_touch)->emulating_touch = NULL; + gdk_wayland_device_set_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch), + NULL); gdk_wayland_seat_remove_touch (seat, id); } @@ -2658,11 +2705,8 @@ touch_handle_cancel (void *data, GHashTableIter iter; GdkEvent *event; - if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch) - { - touch = GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch; - GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL; - } + gdk_wayland_device_set_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch), + NULL); g_hash_table_iter_init (&iter, seat->touches); @@ -3095,7 +3139,9 @@ tablet_handle_done (void *data, "display", display, "seat", seat, NULL); - GDK_WAYLAND_DEVICE (logical_device)->pointer = &tablet->pointer_info; + + gdk_wayland_device_set_pointer (GDK_WAYLAND_DEVICE (logical_device), + &tablet->pointer_info); stylus_device = g_object_new (GDK_TYPE_WAYLAND_DEVICE, "name", tablet->name, @@ -3328,7 +3374,9 @@ seat_handle_capabilities (void *data, "display", seat->display, "seat", seat, NULL); - GDK_WAYLAND_DEVICE (seat->logical_touch)->pointer = &seat->touch_info; + + gdk_wayland_device_set_pointer (GDK_WAYLAND_DEVICE (seat->logical_touch), + &seat->touch_info); _gdk_device_set_associated_device (seat->logical_touch, seat->logical_keyboard); gdk_seat_device_added (GDK_SEAT (seat), seat->logical_touch); @@ -4601,7 +4649,8 @@ init_devices (GdkWaylandSeat *seat) "seat", seat, NULL); - GDK_WAYLAND_DEVICE (seat->logical_pointer)->pointer = &seat->pointer_info; + gdk_wayland_device_set_pointer (GDK_WAYLAND_DEVICE (seat->logical_pointer), + &seat->pointer_info); /* keyboard */ seat->logical_keyboard = g_object_new (GDK_TYPE_WAYLAND_DEVICE, @@ -4625,7 +4674,9 @@ static void pointer_surface_update_scale (GdkDevice *device) { GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer; + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display); guint32 scale; GSList *l; @@ -5255,9 +5306,11 @@ gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device, touch = gdk_wayland_seat_get_touch (seat, GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); - if (GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch == touch) + if (touch == + gdk_wayland_device_get_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch))) { - GDK_WAYLAND_DEVICE (seat->logical_touch)->emulating_touch = NULL; + gdk_wayland_device_set_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch), + NULL); emulate_touch_crossing (touch->surface, NULL, seat->logical_touch, seat->touch, touch, GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, -- cgit v1.2.1 From af00beb772f1a140867951c5dce371f79aa81cc3 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 2 Feb 2023 18:03:29 +0100 Subject: gdk/wayland: Move struct declarations to header These will be used from outside the main file, after we are done splitting it. --- gdk/wayland/gdkdevice-wayland-private.h | 202 ++++++++++++++++++++++++++++++++ gdk/wayland/gdkseat-wayland.c | 198 ------------------------------- 2 files changed, 202 insertions(+), 198 deletions(-) diff --git a/gdk/wayland/gdkdevice-wayland-private.h b/gdk/wayland/gdkdevice-wayland-private.h index c159462d86..e9c0f9517c 100644 --- a/gdk/wayland/gdkdevice-wayland-private.h +++ b/gdk/wayland/gdkdevice-wayland-private.h @@ -2,8 +2,12 @@ #define __GDK_DEVICE_WAYLAND_PRIVATE_H__ #include "gdkwaylanddevice.h" +#include "gdkwaylandseat.h" #include +#include + +#include struct _GdkWaylandDevice { @@ -15,6 +19,204 @@ struct _GdkWaylandDeviceClass GdkDeviceClass parent_class; }; +typedef struct _GdkWaylandTouchData GdkWaylandTouchData; +typedef struct _GdkWaylandPointerFrameData GdkWaylandPointerFrameData; +typedef struct _GdkWaylandPointerData GdkWaylandPointerData; +typedef struct _GdkWaylandTabletPadGroupData GdkWaylandTabletPadGroupData; +typedef struct _GdkWaylandTabletPadData GdkWaylandTabletPadData; +typedef struct _GdkWaylandTabletData GdkWaylandTabletData; +typedef struct _GdkWaylandTabletToolData GdkWaylandTabletToolData; + +struct _GdkWaylandTouchData +{ + uint32_t id; + double x; + double y; + GdkSurface *surface; + uint32_t touch_down_serial; + guint initial_touch : 1; +}; + +struct _GdkWaylandPointerFrameData +{ + GdkEvent *event; + + /* Specific to the scroll event */ + double delta_x, delta_y; + int32_t value120_x, value120_y; + gint8 is_scroll_stop; + enum wl_pointer_axis_source source; +}; + +struct _GdkWaylandPointerData { + GdkSurface *focus; + + double surface_x, surface_y; + + GdkModifierType button_modifiers; + + uint32_t time; + uint32_t enter_serial; + uint32_t press_serial; + + GdkSurface *grab_surface; + uint32_t grab_time; + + struct wl_surface *pointer_surface; + guint cursor_is_default: 1; + GdkCursor *cursor; + guint cursor_timeout_id; + guint cursor_image_index; + guint cursor_image_delay; + guint touchpad_event_sequence; + + guint current_output_scale; + GSList *pointer_surface_outputs; + + /* Accumulated event data for a pointer frame */ + GdkWaylandPointerFrameData frame; +}; + +struct _GdkWaylandTabletPadGroupData +{ + GdkWaylandTabletPadData *pad; + struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group; + GList *rings; + GList *strips; + GList *buttons; + + guint mode_switch_serial; + guint n_modes; + guint current_mode; + + struct { + guint source; + gboolean is_stop; + double value; + } axis_tmp_info; +}; + +struct _GdkWaylandTabletPadData +{ + GdkSeat *seat; + struct zwp_tablet_pad_v2 *wp_tablet_pad; + GdkDevice *device; + + GdkWaylandTabletData *current_tablet; + + guint enter_serial; + uint32_t n_buttons; + char *path; + + GList *rings; + GList *strips; + GList *mode_groups; +}; + +struct _GdkWaylandTabletToolData +{ + GdkSeat *seat; + struct zwp_tablet_tool_v2 *wp_tablet_tool; + GdkAxisFlags axes; + GdkDeviceToolType type; + guint64 hardware_serial; + guint64 hardware_id_wacom; + + GdkDeviceTool *tool; + GdkWaylandTabletData *current_tablet; +}; + +struct _GdkWaylandTabletData +{ + struct zwp_tablet_v2 *wp_tablet; + char *name; + char *path; + uint32_t vid; + uint32_t pid; + + GdkDevice *logical_device; + GdkDevice *stylus_device; + GdkSeat *seat; + GdkWaylandPointerData pointer_info; + + GList *pads; + + GdkWaylandTabletToolData *current_tool; + + int axis_indices[GDK_AXIS_LAST]; + double axes[GDK_AXIS_LAST]; +}; + +struct _GdkWaylandSeat +{ + GdkSeat parent_instance; + + guint32 id; + struct wl_seat *wl_seat; + struct wl_pointer *wl_pointer; + struct wl_keyboard *wl_keyboard; + struct wl_touch *wl_touch; + struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe; + struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch; + struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold; + struct zwp_tablet_seat_v2 *wp_tablet_seat; + + GdkDisplay *display; + + GdkDevice *logical_pointer; + GdkDevice *logical_keyboard; + GdkDevice *pointer; + GdkDevice *wheel_scrolling; + GdkDevice *finger_scrolling; + GdkDevice *continuous_scrolling; + GdkDevice *keyboard; + GdkDevice *logical_touch; + GdkDevice *touch; + GdkCursor *cursor; + GdkKeymap *keymap; + + GHashTable *touches; + GList *tablets; + GList *tablet_tools; + GList *tablet_pads; + + GdkWaylandPointerData pointer_info; + GdkWaylandPointerData touch_info; + + GdkModifierType key_modifiers; + GdkSurface *keyboard_focus; + GdkSurface *grab_surface; + uint32_t grab_time; + gboolean have_server_repeat; + uint32_t server_repeat_rate; + uint32_t server_repeat_delay; + + struct wl_data_offer *pending_offer; + GdkContentFormatsBuilder *pending_builder; + GdkDragAction pending_source_actions; + GdkDragAction pending_action; + + struct wl_callback *repeat_callback; + guint32 repeat_timer; + guint32 repeat_key; + guint32 repeat_count; + gint64 repeat_deadline; + uint32_t keyboard_time; + uint32_t keyboard_key_serial; + + GdkClipboard *clipboard; + GdkClipboard *primary_clipboard; + struct wl_data_device *data_device; + GdkDrag *drag; + GdkDrop *drop; + + /* Some tracking on gesture events */ + guint gesture_n_fingers; + double gesture_scale; + + GdkCursor *grab_cursor; +}; + void gdk_wayland_device_query_state (GdkDevice *device, GdkSurface *surface, double *win_x, diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c index ee6532ff50..8c8f25534e 100644 --- a/gdk/wayland/gdkseat-wayland.c +++ b/gdk/wayland/gdkseat-wayland.c @@ -92,204 +92,6 @@ typedef struct _GdkWaylandDevicePad GdkWaylandDevicePad; typedef struct _GdkWaylandDevicePadClass GdkWaylandDevicePadClass; -typedef struct _GdkWaylandTouchData GdkWaylandTouchData; -typedef struct _GdkWaylandPointerFrameData GdkWaylandPointerFrameData; -typedef struct _GdkWaylandPointerData GdkWaylandPointerData; -typedef struct _GdkWaylandTabletData GdkWaylandTabletData; -typedef struct _GdkWaylandTabletToolData GdkWaylandTabletToolData; -typedef struct _GdkWaylandTabletPadGroupData GdkWaylandTabletPadGroupData; -typedef struct _GdkWaylandTabletPadData GdkWaylandTabletPadData; - -struct _GdkWaylandTouchData -{ - uint32_t id; - double x; - double y; - GdkSurface *surface; - uint32_t touch_down_serial; - guint initial_touch : 1; -}; - -struct _GdkWaylandPointerFrameData -{ - GdkEvent *event; - - /* Specific to the scroll event */ - double delta_x, delta_y; - int32_t value120_x, value120_y; - gint8 is_scroll_stop; - enum wl_pointer_axis_source source; -}; - -struct _GdkWaylandPointerData { - GdkSurface *focus; - - double surface_x, surface_y; - - GdkModifierType button_modifiers; - - uint32_t time; - uint32_t enter_serial; - uint32_t press_serial; - - GdkSurface *grab_surface; - uint32_t grab_time; - - struct wl_surface *pointer_surface; - guint cursor_is_default: 1; - GdkCursor *cursor; - guint cursor_timeout_id; - guint cursor_image_index; - guint cursor_image_delay; - guint touchpad_event_sequence; - - guint current_output_scale; - GSList *pointer_surface_outputs; - - /* Accumulated event data for a pointer frame */ - GdkWaylandPointerFrameData frame; -}; - -struct _GdkWaylandTabletToolData -{ - GdkSeat *seat; - struct zwp_tablet_tool_v2 *wp_tablet_tool; - GdkAxisFlags axes; - GdkDeviceToolType type; - guint64 hardware_serial; - guint64 hardware_id_wacom; - - GdkDeviceTool *tool; - GdkWaylandTabletData *current_tablet; -}; - -struct _GdkWaylandTabletPadGroupData -{ - GdkWaylandTabletPadData *pad; - struct zwp_tablet_pad_group_v2 *wp_tablet_pad_group; - GList *rings; - GList *strips; - GList *buttons; - - guint mode_switch_serial; - guint n_modes; - guint current_mode; - - struct { - guint source; - gboolean is_stop; - double value; - } axis_tmp_info; -}; - -struct _GdkWaylandTabletPadData -{ - GdkSeat *seat; - struct zwp_tablet_pad_v2 *wp_tablet_pad; - GdkDevice *device; - - GdkWaylandTabletData *current_tablet; - - guint enter_serial; - uint32_t n_buttons; - char *path; - - GList *rings; - GList *strips; - GList *mode_groups; -}; - -struct _GdkWaylandTabletData -{ - struct zwp_tablet_v2 *wp_tablet; - char *name; - char *path; - uint32_t vid; - uint32_t pid; - - GdkDevice *logical_device; - GdkDevice *stylus_device; - GdkSeat *seat; - GdkWaylandPointerData pointer_info; - - GList *pads; - - GdkWaylandTabletToolData *current_tool; - - int axis_indices[GDK_AXIS_LAST]; - double axes[GDK_AXIS_LAST]; -}; - -struct _GdkWaylandSeat -{ - GdkSeat parent_instance; - - guint32 id; - struct wl_seat *wl_seat; - struct wl_pointer *wl_pointer; - struct wl_keyboard *wl_keyboard; - struct wl_touch *wl_touch; - struct zwp_pointer_gesture_swipe_v1 *wp_pointer_gesture_swipe; - struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch; - struct zwp_pointer_gesture_hold_v1 *wp_pointer_gesture_hold; - struct zwp_tablet_seat_v2 *wp_tablet_seat; - - GdkDisplay *display; - - GdkDevice *logical_pointer; - GdkDevice *logical_keyboard; - GdkDevice *pointer; - GdkDevice *wheel_scrolling; - GdkDevice *finger_scrolling; - GdkDevice *continuous_scrolling; - GdkDevice *keyboard; - GdkDevice *logical_touch; - GdkDevice *touch; - GdkCursor *cursor; - GdkKeymap *keymap; - - GHashTable *touches; - GList *tablets; - GList *tablet_tools; - GList *tablet_pads; - - GdkWaylandPointerData pointer_info; - GdkWaylandPointerData touch_info; - - GdkModifierType key_modifiers; - GdkSurface *keyboard_focus; - GdkSurface *grab_surface; - uint32_t grab_time; - gboolean have_server_repeat; - uint32_t server_repeat_rate; - uint32_t server_repeat_delay; - - struct wl_data_offer *pending_offer; - GdkContentFormatsBuilder *pending_builder; - GdkDragAction pending_source_actions; - GdkDragAction pending_action; - - struct wl_callback *repeat_callback; - guint32 repeat_timer; - guint32 repeat_key; - guint32 repeat_count; - gint64 repeat_deadline; - uint32_t keyboard_time; - uint32_t keyboard_key_serial; - - GdkClipboard *clipboard; - GdkClipboard *primary_clipboard; - struct wl_data_device *data_device; - GdkDrag *drag; - GdkDrop *drop; - - /* Some tracking on gesture events */ - guint gesture_n_fingers; - double gesture_scale; - - GdkCursor *grab_cursor; -}; - G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT) typedef struct -- cgit v1.2.1 From a5246a6856e136b48c6b2d0bb8b1a3ca35aa1bcc Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 2 Feb 2023 18:06:52 +0100 Subject: gdk/wayland: Split GdkDevicePad wayland implementation This now lives in its own C file. --- gdk/wayland/gdkdevice-wayland-private.h | 6 + gdk/wayland/gdkdevicepad-wayland.c | 266 ++++++++++++++++++++++++++++++++ gdk/wayland/gdkseat-wayland.c | 227 +-------------------------- gdk/wayland/meson.build | 1 + 4 files changed, 274 insertions(+), 226 deletions(-) create mode 100644 gdk/wayland/gdkdevicepad-wayland.c diff --git a/gdk/wayland/gdkdevice-wayland-private.h b/gdk/wayland/gdkdevice-wayland-private.h index e9c0f9517c..5f43cd1fda 100644 --- a/gdk/wayland/gdkdevice-wayland-private.h +++ b/gdk/wayland/gdkdevice-wayland-private.h @@ -217,6 +217,9 @@ struct _GdkWaylandSeat GdkCursor *grab_cursor; }; +#define GDK_TYPE_WAYLAND_DEVICE_PAD (gdk_wayland_device_pad_get_type ()) +GType gdk_wayland_device_pad_get_type (void); + void gdk_wayland_device_query_state (GdkDevice *device, GdkSurface *surface, double *win_x, @@ -228,4 +231,7 @@ void gdk_wayland_device_pad_set_feedback (GdkDevice *device, guint feature_idx, const char *label); +GdkWaylandTabletPadData * gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, + GdkDevice *device); + #endif diff --git a/gdk/wayland/gdkdevicepad-wayland.c b/gdk/wayland/gdkdevicepad-wayland.c new file mode 100644 index 0000000000..060e18c143 --- /dev/null +++ b/gdk/wayland/gdkdevicepad-wayland.c @@ -0,0 +1,266 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2009 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkwaylanddevice.h" +#include "gdkdevice-wayland-private.h" + +#include "tablet-unstable-v2-client-protocol.h" + +#include + +typedef struct _GdkWaylandDevicePad GdkWaylandDevicePad; +typedef struct _GdkWaylandDevicePadClass GdkWaylandDevicePadClass; + +struct _GdkWaylandDevicePad +{ + GdkWaylandDevice parent_instance; +}; + +struct _GdkWaylandDevicePadClass +{ + GdkWaylandDeviceClass parent_class; +}; + +static void gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GdkWaylandDevicePad, gdk_wayland_device_pad, + GDK_TYPE_WAYLAND_DEVICE, + G_IMPLEMENT_INTERFACE (GDK_TYPE_DEVICE_PAD, + gdk_wayland_device_pad_iface_init)) + +static int +gdk_wayland_device_pad_get_n_groups (GdkDevicePad *pad) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadData *data; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); +#ifdef G_DISABLE_ASSERT + if (data == NULL) + return 0; +#else + g_assert (data != NULL); +#endif + + return g_list_length (data->mode_groups); +} + +static int +gdk_wayland_device_pad_get_group_n_modes (GdkDevicePad *pad, + int n_group) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadGroupData *group; + GdkWaylandTabletPadData *data; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); +#ifdef G_DISABLE_ASSERT + if (data == NULL) + return 0; +#else + g_assert (data != NULL); +#endif + + group = g_list_nth_data (data->mode_groups, n_group); + if (!group) + return -1; + + return group->n_modes; +} + +static int +gdk_wayland_device_pad_get_n_features (GdkDevicePad *pad, + GdkDevicePadFeature feature) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadData *data; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); + g_assert (data != NULL); + + switch (feature) + { + case GDK_DEVICE_PAD_FEATURE_BUTTON: + return data->n_buttons; + case GDK_DEVICE_PAD_FEATURE_RING: + return g_list_length (data->rings); + case GDK_DEVICE_PAD_FEATURE_STRIP: + return g_list_length (data->strips); + default: + return -1; + } +} + +static int +gdk_wayland_device_pad_get_feature_group (GdkDevicePad *pad, + GdkDevicePadFeature feature, + int idx) +{ + GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); + GdkWaylandTabletPadGroupData *group; + GdkWaylandTabletPadData *data; + GList *l; + int i; + + data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), + GDK_DEVICE (pad)); +#ifdef G_DISABLE_ASSERT + if (data == NULL) + return -1; +#else + g_assert (data != NULL); +#endif + + for (l = data->mode_groups, i = 0; l; l = l->next, i++) + { + group = l->data; + + switch (feature) + { + case GDK_DEVICE_PAD_FEATURE_BUTTON: + if (g_list_find (group->buttons, GINT_TO_POINTER (idx))) + return i; + break; + case GDK_DEVICE_PAD_FEATURE_RING: + { + gpointer ring; + + ring = g_list_nth_data (data->rings, idx); + if (ring && g_list_find (group->rings, ring)) + return i; + break; + } + case GDK_DEVICE_PAD_FEATURE_STRIP: + { + gpointer strip; + strip = g_list_nth_data (data->strips, idx); + if (strip && g_list_find (group->strips, strip)) + return i; + break; + } + default: + break; + } + } + + return -1; +} + +static void +gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface) +{ + iface->get_n_groups = gdk_wayland_device_pad_get_n_groups; + iface->get_group_n_modes = gdk_wayland_device_pad_get_group_n_modes; + iface->get_n_features = gdk_wayland_device_pad_get_n_features; + iface->get_feature_group = gdk_wayland_device_pad_get_feature_group; +} + +static void +gdk_wayland_device_pad_class_init (GdkWaylandDevicePadClass *klass) +{ +} + +static void +gdk_wayland_device_pad_init (GdkWaylandDevicePad *pad) +{ +} + +static GdkWaylandTabletPadGroupData * +tablet_pad_lookup_button_group (GdkWaylandTabletPadData *pad, + uint32_t button) +{ + GdkWaylandTabletPadGroupData *group; + GList *l; + + for (l = pad->mode_groups; l; l = l->next) + { + group = l->data; + + if (g_list_find (group->buttons, GUINT_TO_POINTER (button))) + return group; + } + + return NULL; +} + +/* + * gdk_wayland_device_pad_set_feedback: + * @device: (type GdkWaylandDevice): a %GDK_SOURCE_TABLET_PAD device + * @feature: Feature to set the feedback label for + * @feature_idx: 0-indexed index of the feature to set the feedback label for + * @label: Feedback label + * + * Sets the feedback label for the given feature/index. + * + * This may be used by the compositor to provide user feedback + * of the actions available/performed. + */ +void +gdk_wayland_device_pad_set_feedback (GdkDevice *device, + GdkDevicePadFeature feature, + guint feature_idx, + const char *label) +{ + GdkWaylandTabletPadData *pad; + GdkWaylandTabletPadGroupData *group; + GdkSeat *seat; + + seat = gdk_device_get_seat (device); + pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); + if (!pad) + return; + + if (feature == GDK_DEVICE_PAD_FEATURE_BUTTON) + { + group = tablet_pad_lookup_button_group (pad, feature_idx); + if (!group) + return; + + zwp_tablet_pad_v2_set_feedback (pad->wp_tablet_pad, feature_idx, label, + group->mode_switch_serial); + } + else if (feature == GDK_DEVICE_PAD_FEATURE_RING) + { + struct zwp_tablet_pad_ring_v2 *wp_pad_ring; + + wp_pad_ring = g_list_nth_data (pad->rings, feature_idx); + if (!wp_pad_ring) + return; + + group = zwp_tablet_pad_ring_v2_get_user_data (wp_pad_ring); + zwp_tablet_pad_ring_v2_set_feedback (wp_pad_ring, label, + group->mode_switch_serial); + + } + else if (feature == GDK_DEVICE_PAD_FEATURE_STRIP) + { + struct zwp_tablet_pad_strip_v2 *wp_pad_strip; + + wp_pad_strip = g_list_nth_data (pad->strips, feature_idx); + if (!wp_pad_strip) + return; + + group = zwp_tablet_pad_strip_v2_get_user_data (wp_pad_strip); + zwp_tablet_pad_strip_v2_set_feedback (wp_pad_strip, label, + group->mode_switch_serial); + } +} diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c index 8c8f25534e..a5e1ca95f6 100644 --- a/gdk/wayland/gdkseat-wayland.c +++ b/gdk/wayland/gdkseat-wayland.c @@ -89,9 +89,6 @@ #define GDK_SEAT_DEBUG(seat,type,...) GDK_DISPLAY_DEBUG(gdk_seat_get_display (GDK_SEAT (seat)),type,__VA_ARGS__) -typedef struct _GdkWaylandDevicePad GdkWaylandDevicePad; -typedef struct _GdkWaylandDevicePadClass GdkWaylandDevicePadClass; - G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT) typedef struct @@ -102,30 +99,11 @@ typedef struct G_DEFINE_TYPE_WITH_PRIVATE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) -struct _GdkWaylandDevicePad -{ - GdkWaylandDevice parent_instance; -}; - -struct _GdkWaylandDevicePadClass -{ - GdkWaylandDeviceClass parent_class; -}; - -static void gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface); static void init_pointer_data (GdkWaylandPointerData *pointer_data, GdkDisplay *display_wayland, GdkDevice *logical_device); static void pointer_surface_update_scale (GdkDevice *device); -#define GDK_TYPE_WAYLAND_DEVICE_PAD (gdk_wayland_device_pad_get_type ()) -GType gdk_wayland_device_pad_get_type (void); - -G_DEFINE_TYPE_WITH_CODE (GdkWaylandDevicePad, gdk_wayland_device_pad, - GDK_TYPE_WAYLAND_DEVICE, - G_IMPLEMENT_INTERFACE (GDK_TYPE_DEVICE_PAD, - gdk_wayland_device_pad_iface_init)) - #define GDK_SLOT_TO_EVENT_SEQUENCE(s) ((GdkEventSequence *) GUINT_TO_POINTER((s) + 1)) #define GDK_EVENT_SEQUENCE_TO_SLOT(s) (GPOINTER_TO_UINT(s) - 1) @@ -166,7 +144,7 @@ gdk_wayland_seat_find_tablet (GdkWaylandSeat *seat, return NULL; } -static GdkWaylandTabletPadData * +GdkWaylandTabletPadData * gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, GdkDevice *device) { @@ -695,146 +673,6 @@ gdk_wayland_device_init (GdkWaylandDevice *device_core) _gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1); } -static int -gdk_wayland_device_pad_get_n_groups (GdkDevicePad *pad) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadData *data; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); -#ifdef G_DISABLE_ASSERT - if (data == NULL) - return 0; -#else - g_assert (data != NULL); -#endif - - return g_list_length (data->mode_groups); -} - -static int -gdk_wayland_device_pad_get_group_n_modes (GdkDevicePad *pad, - int n_group) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadGroupData *group; - GdkWaylandTabletPadData *data; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); -#ifdef G_DISABLE_ASSERT - if (data == NULL) - return 0; -#else - g_assert (data != NULL); -#endif - - group = g_list_nth_data (data->mode_groups, n_group); - if (!group) - return -1; - - return group->n_modes; -} - -static int -gdk_wayland_device_pad_get_n_features (GdkDevicePad *pad, - GdkDevicePadFeature feature) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadData *data; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); - g_assert (data != NULL); - - switch (feature) - { - case GDK_DEVICE_PAD_FEATURE_BUTTON: - return data->n_buttons; - case GDK_DEVICE_PAD_FEATURE_RING: - return g_list_length (data->rings); - case GDK_DEVICE_PAD_FEATURE_STRIP: - return g_list_length (data->strips); - default: - return -1; - } -} - -static int -gdk_wayland_device_pad_get_feature_group (GdkDevicePad *pad, - GdkDevicePadFeature feature, - int idx) -{ - GdkSeat *seat = gdk_device_get_seat (GDK_DEVICE (pad)); - GdkWaylandTabletPadGroupData *group; - GdkWaylandTabletPadData *data; - GList *l; - int i; - - data = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), - GDK_DEVICE (pad)); -#ifdef G_DISABLE_ASSERT - if (data == NULL) - return -1; -#else - g_assert (data != NULL); -#endif - - for (l = data->mode_groups, i = 0; l; l = l->next, i++) - { - group = l->data; - - switch (feature) - { - case GDK_DEVICE_PAD_FEATURE_BUTTON: - if (g_list_find (group->buttons, GINT_TO_POINTER (idx))) - return i; - break; - case GDK_DEVICE_PAD_FEATURE_RING: - { - gpointer ring; - - ring = g_list_nth_data (data->rings, idx); - if (ring && g_list_find (group->rings, ring)) - return i; - break; - } - case GDK_DEVICE_PAD_FEATURE_STRIP: - { - gpointer strip; - strip = g_list_nth_data (data->strips, idx); - if (strip && g_list_find (group->strips, strip)) - return i; - break; - } - default: - break; - } - } - - return -1; -} - -static void -gdk_wayland_device_pad_iface_init (GdkDevicePadInterface *iface) -{ - iface->get_n_groups = gdk_wayland_device_pad_get_n_groups; - iface->get_group_n_modes = gdk_wayland_device_pad_get_group_n_modes; - iface->get_n_features = gdk_wayland_device_pad_get_n_features; - iface->get_feature_group = gdk_wayland_device_pad_get_feature_group; -} - -static void -gdk_wayland_device_pad_class_init (GdkWaylandDevicePadClass *klass) -{ -} - -static void -gdk_wayland_device_pad_init (GdkWaylandDevicePad *pad) -{ -} - /** * gdk_wayland_device_get_wl_seat: (skip) * @device: (type GdkWaylandDevice): a `GdkDevice` @@ -5251,66 +5089,3 @@ gdk_wayland_device_get_node_path (GdkDevice *device) return NULL; } - -/* - * gdk_wayland_device_pad_set_feedback: - * @device: (type GdkWaylandDevice): a %GDK_SOURCE_TABLET_PAD device - * @feature: Feature to set the feedback label for - * @feature_idx: 0-indexed index of the feature to set the feedback label for - * @label: Feedback label - * - * Sets the feedback label for the given feature/index. - * - * This may be used by the compositor to provide user feedback - * of the actions available/performed. - */ -void -gdk_wayland_device_pad_set_feedback (GdkDevice *device, - GdkDevicePadFeature feature, - guint feature_idx, - const char *label) -{ - GdkWaylandTabletPadData *pad; - GdkWaylandTabletPadGroupData *group; - GdkSeat *seat; - - seat = gdk_device_get_seat (device); - pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); - if (!pad) - return; - - if (feature == GDK_DEVICE_PAD_FEATURE_BUTTON) - { - group = tablet_pad_lookup_button_group (pad, feature_idx); - if (!group) - return; - - zwp_tablet_pad_v2_set_feedback (pad->wp_tablet_pad, feature_idx, label, - group->mode_switch_serial); - } - else if (feature == GDK_DEVICE_PAD_FEATURE_RING) - { - struct zwp_tablet_pad_ring_v2 *wp_pad_ring; - - wp_pad_ring = g_list_nth_data (pad->rings, feature_idx); - if (!wp_pad_ring) - return; - - group = zwp_tablet_pad_ring_v2_get_user_data (wp_pad_ring); - zwp_tablet_pad_ring_v2_set_feedback (wp_pad_ring, label, - group->mode_switch_serial); - - } - else if (feature == GDK_DEVICE_PAD_FEATURE_STRIP) - { - struct zwp_tablet_pad_strip_v2 *wp_pad_strip; - - wp_pad_strip = g_list_nth_data (pad->strips, feature_idx); - if (!wp_pad_strip) - return; - - group = zwp_tablet_pad_strip_v2_get_user_data (wp_pad_strip); - zwp_tablet_pad_strip_v2_set_feedback (wp_pad_strip, label, - group->mode_switch_serial); - } -} diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 76a069975f..79a770c1f1 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -5,6 +5,7 @@ gdk_wayland_sources = files([ 'gdkcairocontext-wayland.c', 'gdkclipboard-wayland.c', 'gdkcursor-wayland.c', + 'gdkdevicepad-wayland.c', 'gdkdisplay-wayland.c', 'gdkdrag-wayland.c', 'gdkdragsurface-wayland.c', -- cgit v1.2.1 From 1d4ceac2c5b43f689d773897ec2b041f82f69d7c Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 3 Feb 2023 15:55:09 +0100 Subject: gdk/wayland: "Split" GdkWaylandDevice implementation out This is a bit spaghetti right now, since seats and devices were heavily entangled there are a number of crossed private API calls that should ideally not be there. Let this be a first step, so more bits may move from the seat implementation to devices. --- gdk/wayland/gdkdevice-wayland-private.h | 30 ++ gdk/wayland/gdkdevice-wayland.c | 745 +++++++++++++++++++++++++++++++ gdk/wayland/gdkseat-wayland.c | 748 ++------------------------------ gdk/wayland/meson.build | 1 + 4 files changed, 816 insertions(+), 708 deletions(-) create mode 100644 gdk/wayland/gdkdevice-wayland.c diff --git a/gdk/wayland/gdkdevice-wayland-private.h b/gdk/wayland/gdkdevice-wayland-private.h index 5f43cd1fda..233270b4a3 100644 --- a/gdk/wayland/gdkdevice-wayland-private.h +++ b/gdk/wayland/gdkdevice-wayland-private.h @@ -220,6 +220,19 @@ struct _GdkWaylandSeat #define GDK_TYPE_WAYLAND_DEVICE_PAD (gdk_wayland_device_pad_get_type ()) GType gdk_wayland_device_pad_get_type (void); +void gdk_wayland_seat_stop_cursor_animation (GdkWaylandSeat *seat, + GdkWaylandPointerData *pointer); + +GdkWaylandPointerData * gdk_wayland_device_get_pointer (GdkWaylandDevice *wayland_device); + +void gdk_wayland_device_set_pointer (GdkWaylandDevice *wayland_device, + GdkWaylandPointerData *pointer); + +GdkWaylandTouchData * gdk_wayland_device_get_emulating_touch (GdkWaylandDevice *wayland_device); + +void gdk_wayland_device_set_emulating_touch (GdkWaylandDevice *wayland_device, + GdkWaylandTouchData *touch); + void gdk_wayland_device_query_state (GdkDevice *device, GdkSurface *surface, double *win_x, @@ -234,4 +247,21 @@ void gdk_wayland_device_pad_set_feedback (GdkDevice *device, GdkWaylandTabletPadData * gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, GdkDevice *device); +GdkWaylandTabletData * gdk_wayland_seat_find_tablet (GdkWaylandSeat *seat, + GdkDevice *device); + +GdkWaylandTouchData * gdk_wayland_seat_get_touch (GdkWaylandSeat *seat, + uint32_t id); + +void gdk_wayland_device_maybe_emit_grab_crossing (GdkDevice *device, + GdkSurface *window, + guint32 time); + +GdkSurface * gdk_wayland_device_maybe_emit_ungrab_crossing (GdkDevice *device, + guint32 time_); + +gboolean gdk_wayland_device_update_surface_cursor (GdkDevice *device); + +GdkModifierType gdk_wayland_device_get_modifiers (GdkDevice *device); + #endif diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c new file mode 100644 index 0000000000..9cb3cfbfda --- /dev/null +++ b/gdk/wayland/gdkdevice-wayland.c @@ -0,0 +1,745 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2009 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkdevice-wayland-private.h" +#include "gdkprivate-wayland.h" +#include "gdkcursorprivate.h" +#include "gdkeventsprivate.h" + +#define GDK_SLOT_TO_EVENT_SEQUENCE(s) ((GdkEventSequence *) GUINT_TO_POINTER((s) + 1)) +#define GDK_EVENT_SEQUENCE_TO_SLOT(s) (GPOINTER_TO_UINT(s) - 1) + +typedef struct +{ + GdkWaylandTouchData *emulating_touch; /* Only used on wd->logical_touch */ + GdkWaylandPointerData *pointer; +} GdkWaylandDevicePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) + +static void +gdk_wayland_device_set_surface_cursor (GdkDevice *device, + GdkSurface *surface, + GdkCursor *cursor) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); + + if (device == seat->logical_touch) + return; + + if (seat->grab_cursor) + cursor = seat->grab_cursor; + + if (pointer->cursor != NULL && + cursor != NULL && + gdk_cursor_equal (cursor, pointer->cursor)) + return; + + if (cursor == NULL) + { + if (!pointer->cursor_is_default) + { + g_clear_object (&pointer->cursor); + pointer->cursor = gdk_cursor_new_from_name ("default", NULL); + pointer->cursor_is_default = TRUE; + + gdk_wayland_seat_stop_cursor_animation (seat, pointer); + gdk_wayland_device_update_surface_cursor (device); + } + else + { + /* Nothing to do, we'already using the default cursor */ + } + } + else + { + g_set_object (&pointer->cursor, cursor); + pointer->cursor_is_default = FALSE; + + gdk_wayland_seat_stop_cursor_animation (seat, pointer); + gdk_wayland_device_update_surface_cursor (device); + } +} + +static GdkGrabStatus +gdk_wayland_device_grab (GdkDevice *device, + GdkSurface *surface, + gboolean owner_events, + GdkEventMask event_mask, + GdkSurface *confine_to, + GdkCursor *cursor, + guint32 time_) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); + + if (GDK_IS_DRAG_SURFACE (surface) && + gdk_surface_get_mapped (surface)) + { + g_warning ("Surface %p is already mapped at the time of grabbing. " + "gdk_seat_grab() should be used to simultaneously grab input " + "and show this popup. You may find oddities ahead.", + surface); + } + + gdk_wayland_device_maybe_emit_grab_crossing (device, surface, time_); + + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + { + /* Device is a keyboard */ + gdk_wayland_surface_inhibit_shortcuts (surface, + gdk_device_get_seat (device)); + return GDK_GRAB_SUCCESS; + } + else + { + /* Device is a pointer */ + if (pointer->grab_surface != NULL && + time_ != 0 && pointer->grab_time > time_) + { + return GDK_GRAB_ALREADY_GRABBED; + } + + if (time_ == 0) + time_ = pointer->time; + + pointer->grab_surface = surface; + pointer->grab_time = time_; + _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (wayland_seat)); + + g_clear_object (&wayland_seat->cursor); + + if (cursor) + wayland_seat->cursor = g_object_ref (cursor); + + gdk_wayland_device_update_surface_cursor (device); + } + + return GDK_GRAB_SUCCESS; +} + +static void +gdk_wayland_device_ungrab (GdkDevice *device, + guint32 time_) +{ + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); + GdkSurface *prev_focus; + + prev_focus = gdk_wayland_device_maybe_emit_ungrab_crossing (device, time_); + + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + { + /* Device is a keyboard */ + if (prev_focus) + gdk_wayland_surface_restore_shortcuts (prev_focus, + gdk_device_get_seat (device)); + } + else + { + /* Device is a pointer */ + gdk_wayland_device_update_surface_cursor (device); + + if (pointer->grab_surface) + _gdk_wayland_surface_set_grab_seat (pointer->grab_surface, + NULL); + } +} + +static GdkSurface * +gdk_wayland_device_surface_at_position (GdkDevice *device, + double *win_x, + double *win_y, + GdkModifierType *mask) +{ + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer; + + pointer = gdk_wayland_device_get_pointer (wayland_device); + + if (!pointer) + return NULL; + + if (win_x) + *win_x = pointer->surface_x; + if (win_y) + *win_y = pointer->surface_y; + if (mask) + *mask = gdk_wayland_device_get_modifiers (device); + + return pointer->focus; +} + +static void +gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass) +{ + GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass); + + device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor; + device_class->grab = gdk_wayland_device_grab; + device_class->ungrab = gdk_wayland_device_ungrab; + device_class->surface_at_position = gdk_wayland_device_surface_at_position; +} + +static void +gdk_wayland_device_init (GdkWaylandDevice *device_core) +{ + GdkDevice *device; + + device = GDK_DEVICE (device_core); + + _gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1); + _gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1); +} + +GdkWaylandPointerData * +gdk_wayland_device_get_pointer (GdkWaylandDevice *wayland_device) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + return priv->pointer; +} + +void +gdk_wayland_device_set_pointer (GdkWaylandDevice *wayland_device, + GdkWaylandPointerData *pointer) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + priv->pointer = pointer; +} + +GdkWaylandTouchData * +gdk_wayland_device_get_emulating_touch (GdkWaylandDevice *wayland_device) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + return priv->emulating_touch; +} + +void +gdk_wayland_device_set_emulating_touch (GdkWaylandDevice *wayland_device, + GdkWaylandTouchData *touch) +{ + GdkWaylandDevicePrivate *priv = + gdk_wayland_device_get_instance_private (wayland_device); + + priv->emulating_touch = touch; +} + +gboolean +gdk_wayland_device_update_surface_cursor (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); + struct wl_buffer *buffer; + int x, y, w, h, scale; + guint next_image_index, next_image_delay; + gboolean retval = G_SOURCE_REMOVE; + GdkWaylandTabletData *tablet; + + tablet = gdk_wayland_seat_find_tablet (seat, device); + + if (pointer->cursor) + { + buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display), + pointer->cursor, + pointer->current_output_scale, + pointer->cursor_image_index, + &x, &y, &w, &h, &scale); + } + else + { + pointer->cursor_timeout_id = 0; + return G_SOURCE_REMOVE; + } + + if (tablet) + { + if (!tablet->current_tool) + { + pointer->cursor_timeout_id = 0; + return G_SOURCE_REMOVE; + } + + zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool, + pointer->enter_serial, + pointer->pointer_surface, + x, y); + } + else if (seat->wl_pointer) + { + wl_pointer_set_cursor (seat->wl_pointer, + pointer->enter_serial, + pointer->pointer_surface, + x, y); + } + else + { + pointer->cursor_timeout_id = 0; + return G_SOURCE_REMOVE; + } + + if (buffer) + { + wl_surface_attach (pointer->pointer_surface, buffer, 0, 0); + wl_surface_set_buffer_scale (pointer->pointer_surface, scale); + wl_surface_damage (pointer->pointer_surface, 0, 0, w, h); + wl_surface_commit (pointer->pointer_surface); + } + else + { + wl_surface_attach (pointer->pointer_surface, NULL, 0, 0); + wl_surface_commit (pointer->pointer_surface); + } + + next_image_index = + _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display), + pointer->cursor, + pointer->current_output_scale, + pointer->cursor_image_index, + &next_image_delay); + + if (next_image_index != pointer->cursor_image_index) + { + if (next_image_delay != pointer->cursor_image_delay || + pointer->cursor_timeout_id == 0) + { + guint id; + GSource *source; + + gdk_wayland_seat_stop_cursor_animation (seat, pointer); + + /* Queue timeout for next frame */ + id = g_timeout_add (next_image_delay, + (GSourceFunc) gdk_wayland_device_update_surface_cursor, + device); + source = g_main_context_find_source_by_id (NULL, id); + g_source_set_static_name (source, "[gtk] gdk_wayland_device_update_surface_cursor"); + pointer->cursor_timeout_id = id; + } + else + retval = G_SOURCE_CONTINUE; + + pointer->cursor_image_index = next_image_index; + pointer->cursor_image_delay = next_image_delay; + } + else + gdk_wayland_seat_stop_cursor_animation (seat, pointer); + + return retval; +} + +GdkModifierType +gdk_wayland_device_get_modifiers (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer = + gdk_wayland_device_get_pointer (wayland_device); + GdkModifierType mask; + + mask = seat->key_modifiers; + + if (pointer) + mask |= pointer->button_modifiers; + + return mask; +} + +void +gdk_wayland_device_query_state (GdkDevice *device, + GdkSurface *surface, + double *win_x, + double *win_y, + GdkModifierType *mask) +{ + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer; + double x, y; + + if (mask) + *mask = gdk_wayland_device_get_modifiers (device); + + pointer = gdk_wayland_device_get_pointer (wayland_device); + + if (pointer->focus == surface) + { + x = pointer->surface_x; + y = pointer->surface_y; + } + else + { + x = y = -1; + } + + if (win_x) + *win_x = x; + if (win_y) + *win_y = y; +} + +GdkSurface * +gdk_wayland_device_get_focus (GdkDevice *device) +{ + GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); + GdkWaylandPointerData *pointer; + + if (device == wayland_seat->logical_keyboard) + return wayland_seat->keyboard_focus; + else + { + pointer = gdk_wayland_device_get_pointer (wayland_device); + + if (pointer) + return pointer->focus; + } + + return NULL; +} + +static void +emulate_touch_crossing (GdkSurface *surface, + GdkSurface *child_surface, + GdkDevice *device, + GdkDevice *source, + GdkWaylandTouchData *touch, + GdkEventType type, + GdkCrossingMode mode, + guint32 time_) +{ + GdkEvent *event; + + event = gdk_crossing_event_new (type, + surface, + device, + time_, + 0, + touch->x, touch->y, + mode, + GDK_NOTIFY_NONLINEAR); + + _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); +} + +void +gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device, + GdkEventSequence *sequence) +{ + GdkWaylandSeat *seat; + GdkWaylandTouchData *touch; + GdkEvent *event; + + g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); + touch = gdk_wayland_seat_get_touch (seat, + GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); + + if (touch == + gdk_wayland_device_get_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch))) + { + gdk_wayland_device_set_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch), + NULL); + emulate_touch_crossing (touch->surface, NULL, + seat->logical_touch, seat->touch, + touch, GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, + GDK_CURRENT_TIME); + } + + event = gdk_touch_event_new (GDK_TOUCH_CANCEL, + GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), + touch->surface, + seat->logical_touch, + GDK_CURRENT_TIME, + gdk_wayland_device_get_modifiers (seat->logical_touch), + touch->x, touch->y, + NULL, + touch->initial_touch); + _gdk_wayland_display_deliver_event (seat->display, event); +} + +/** + * gdk_wayland_device_get_wl_seat: (skip) + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_seat` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_seat` + */ +struct wl_seat * +gdk_wayland_device_get_wl_seat (GdkDevice *device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->wl_seat; +} + +/** + * gdk_wayland_device_get_wl_pointer: (skip) + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_pointer` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_pointer` + */ +struct wl_pointer * +gdk_wayland_device_get_wl_pointer (GdkDevice *device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->wl_pointer; +} + +/** + * gdk_wayland_device_get_wl_keyboard: (skip) + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_keyboard` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_keyboard` + */ +struct wl_keyboard * +gdk_wayland_device_get_wl_keyboard (GdkDevice *device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->wl_keyboard; +} + +/** + * gdk_wayland_device_get_xkb_keymap: + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the `xkb_keymap` of a `GdkDevice`. + * + * Returns: (transfer none): a `struct xkb_keymap` + * + * Since: 4.4 + */ +struct xkb_keymap * +gdk_wayland_device_get_xkb_keymap (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return _gdk_wayland_keymap_get_xkb_keymap (seat->keymap); +} + +GdkKeymap * +_gdk_wayland_device_get_keymap (GdkDevice *device) +{ + GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); + return seat->keymap; +} + +/** + * gdk_wayland_device_get_data_device: (skip) + * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the Wayland `wl_data_device` of a `GdkDevice`. + * + * Returns: (transfer none): a Wayland `wl_data_device` + */ +struct wl_data_device * +gdk_wayland_device_get_data_device (GdkDevice *gdk_device) +{ + GdkWaylandSeat *seat; + + g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device), NULL); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); + return seat->data_device; +} + +/** + * gdk_wayland_device_set_selection: (skip) + * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` + * @source: the data source for the selection + * + * Sets the selection of the `GdkDevice. + * + * This is calling wl_data_device_set_selection() on + * the `wl_data_device` of @gdk_device. + */ +void +gdk_wayland_device_set_selection (GdkDevice *gdk_device, + struct wl_data_source *source) +{ + GdkWaylandSeat *seat; + guint32 serial; + + g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); + + seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); + serial = _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL); + wl_data_device_set_selection (seat->data_device, source, serial); +} + +/** + * gdk_wayland_device_get_node_path: + * @device: (type GdkWaylandDevice): a `GdkDevice` + * + * Returns the `/dev/input/event*` path of this device. + * + * For `GdkDevice`s that possibly coalesce multiple hardware + * devices (eg. mouse, keyboard, touch,...), this function + * will return %NULL. + * + * This is most notably implemented for devices of type + * %GDK_SOURCE_PEN, %GDK_SOURCE_TABLET_PAD. + * + * Returns: (nullable) (transfer none): the `/dev/input/event*` + * path of this device + */ +const char * +gdk_wayland_device_get_node_path (GdkDevice *device) +{ + GdkWaylandTabletData *tablet; + GdkWaylandTabletPadData *pad; + + GdkSeat *seat; + + g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); + + seat = gdk_device_get_seat (device); + tablet = gdk_wayland_seat_find_tablet (GDK_WAYLAND_SEAT (seat), device); + if (tablet) + return tablet->path; + + pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); + if (pad) + return pad->path; + + return NULL; +} + +static void +emulate_focus (GdkSurface *surface, + GdkDevice *device, + gboolean focus_in, + guint32 time_) +{ + GdkEvent *event = gdk_focus_event_new (surface, device, focus_in); + + _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); +} + +static void +emulate_crossing (GdkSurface *surface, + GdkSurface *child_surface, + GdkDevice *device, + GdkEventType type, + GdkCrossingMode mode, + guint32 time_) +{ + GdkEvent *event; + GdkModifierType state; + double x, y; + + gdk_surface_get_device_position (surface, device, &x, &y, &state); + event = gdk_crossing_event_new (type, + surface, + device, + time_, + state, + x, y, + mode, + GDK_NOTIFY_NONLINEAR); + + _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); +} + +static void +device_emit_grab_crossing (GdkDevice *device, + GdkSurface *from, + GdkSurface *to, + GdkCrossingMode mode, + guint32 time_) +{ + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + { + if (from) + emulate_focus (from, device, FALSE, time_); + if (to) + emulate_focus (to, device, TRUE, time_); + } + else + { + if (from) + emulate_crossing (from, to, device, GDK_LEAVE_NOTIFY, mode, time_); + if (to) + emulate_crossing (to, from, device, GDK_ENTER_NOTIFY, mode, time_); + } +} + +void +gdk_wayland_device_maybe_emit_grab_crossing (GdkDevice *device, + GdkSurface *window, + guint32 time) +{ + GdkSurface *surface = gdk_wayland_device_get_focus (device); + GdkSurface *focus = window; + + if (focus != surface) + device_emit_grab_crossing (device, focus, window, GDK_CROSSING_GRAB, time); +} + +GdkSurface* +gdk_wayland_device_maybe_emit_ungrab_crossing (GdkDevice *device, + guint32 time_) +{ + GdkDeviceGrabInfo *grab; + GdkSurface *focus = NULL; + GdkSurface *surface = NULL; + GdkSurface *prev_focus = NULL; + + focus = gdk_wayland_device_get_focus (device); + grab = _gdk_display_get_last_device_grab (gdk_device_get_display (device), device); + + if (grab) + { + prev_focus = grab->surface; + surface = grab->surface; + } + + if (focus != surface) + device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time_); + + return prev_focus; +} diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c index a5e1ca95f6..d3e31a4920 100644 --- a/gdk/wayland/gdkseat-wayland.c +++ b/gdk/wayland/gdkseat-wayland.c @@ -91,14 +91,6 @@ G_DEFINE_TYPE (GdkWaylandSeat, gdk_wayland_seat, GDK_TYPE_SEAT) -typedef struct -{ - GdkWaylandTouchData *emulating_touch; /* Only used on wd->logical_touch */ - GdkWaylandPointerData *pointer; -} GdkWaylandDevicePrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (GdkWaylandDevice, gdk_wayland_device, GDK_TYPE_DEVICE) - static void init_pointer_data (GdkWaylandPointerData *pointer_data, GdkDisplay *display_wayland, GdkDevice *logical_device); @@ -113,8 +105,9 @@ static void deliver_key_event (GdkWaylandSeat *seat, uint32_t state, gboolean from_key_repeat); -static void -gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer) +void +gdk_wayland_seat_stop_cursor_animation (GdkWaylandSeat *seat, + GdkWaylandPointerData *pointer) { if (pointer->cursor_timeout_id > 0) { @@ -126,7 +119,7 @@ gdk_wayland_pointer_stop_cursor_animation (GdkWaylandPointerData *pointer) pointer->cursor_image_index = 0; } -static GdkWaylandTabletData * +GdkWaylandTabletData * gdk_wayland_seat_find_tablet (GdkWaylandSeat *seat, GdkDevice *device) { @@ -161,245 +154,6 @@ gdk_wayland_seat_find_pad (GdkWaylandSeat *seat, return NULL; } -static GdkWaylandPointerData * -gdk_wayland_device_get_pointer (GdkWaylandDevice *wayland_device) -{ - GdkWaylandDevicePrivate *priv = - gdk_wayland_device_get_instance_private (wayland_device); - - return priv->pointer; -} - -static void -gdk_wayland_device_set_pointer (GdkWaylandDevice *wayland_device, - GdkWaylandPointerData *pointer) -{ - GdkWaylandDevicePrivate *priv = - gdk_wayland_device_get_instance_private (wayland_device); - - priv->pointer = pointer; -} - -static GdkWaylandTouchData * -gdk_wayland_device_get_emulating_touch (GdkWaylandDevice *wayland_device) -{ - GdkWaylandDevicePrivate *priv = - gdk_wayland_device_get_instance_private (wayland_device); - - return priv->emulating_touch; -} - -static void -gdk_wayland_device_set_emulating_touch (GdkWaylandDevice *wayland_device, - GdkWaylandTouchData *touch) -{ - GdkWaylandDevicePrivate *priv = - gdk_wayland_device_get_instance_private (wayland_device); - - priv->emulating_touch = touch; -} - -static gboolean -gdk_wayland_device_update_surface_cursor (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer = - gdk_wayland_device_get_pointer (wayland_device); - struct wl_buffer *buffer; - int x, y, w, h, scale; - guint next_image_index, next_image_delay; - gboolean retval = G_SOURCE_REMOVE; - GdkWaylandTabletData *tablet; - - tablet = gdk_wayland_seat_find_tablet (seat, device); - - if (pointer->cursor) - { - buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display), - pointer->cursor, - pointer->current_output_scale, - pointer->cursor_image_index, - &x, &y, &w, &h, &scale); - } - else - { - pointer->cursor_timeout_id = 0; - return G_SOURCE_REMOVE; - } - - if (tablet) - { - if (!tablet->current_tool) - { - pointer->cursor_timeout_id = 0; - return G_SOURCE_REMOVE; - } - - zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool, - pointer->enter_serial, - pointer->pointer_surface, - x, y); - } - else if (seat->wl_pointer) - { - wl_pointer_set_cursor (seat->wl_pointer, - pointer->enter_serial, - pointer->pointer_surface, - x, y); - } - else - { - pointer->cursor_timeout_id = 0; - return G_SOURCE_REMOVE; - } - - if (buffer) - { - wl_surface_attach (pointer->pointer_surface, buffer, 0, 0); - wl_surface_set_buffer_scale (pointer->pointer_surface, scale); - wl_surface_damage (pointer->pointer_surface, 0, 0, w, h); - wl_surface_commit (pointer->pointer_surface); - } - else - { - wl_surface_attach (pointer->pointer_surface, NULL, 0, 0); - wl_surface_commit (pointer->pointer_surface); - } - - next_image_index = - _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display), - pointer->cursor, - pointer->current_output_scale, - pointer->cursor_image_index, - &next_image_delay); - - if (next_image_index != pointer->cursor_image_index) - { - if (next_image_delay != pointer->cursor_image_delay || - pointer->cursor_timeout_id == 0) - { - guint id; - GSource *source; - - gdk_wayland_pointer_stop_cursor_animation (pointer); - - /* Queue timeout for next frame */ - id = g_timeout_add (next_image_delay, - (GSourceFunc) gdk_wayland_device_update_surface_cursor, - device); - source = g_main_context_find_source_by_id (NULL, id); - g_source_set_static_name (source, "[gtk] gdk_wayland_device_update_surface_cursor"); - pointer->cursor_timeout_id = id; - } - else - retval = G_SOURCE_CONTINUE; - - pointer->cursor_image_index = next_image_index; - pointer->cursor_image_delay = next_image_delay; - } - else - gdk_wayland_pointer_stop_cursor_animation (pointer); - - return retval; -} - -static void -gdk_wayland_device_set_surface_cursor (GdkDevice *device, - GdkSurface *surface, - GdkCursor *cursor) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer = - gdk_wayland_device_get_pointer (wayland_device); - - if (device == seat->logical_touch) - return; - - if (seat->grab_cursor) - cursor = seat->grab_cursor; - - if (pointer->cursor != NULL && - cursor != NULL && - gdk_cursor_equal (cursor, pointer->cursor)) - return; - - if (cursor == NULL) - { - if (!pointer->cursor_is_default) - { - g_clear_object (&pointer->cursor); - pointer->cursor = gdk_cursor_new_from_name ("default", NULL); - pointer->cursor_is_default = TRUE; - - gdk_wayland_pointer_stop_cursor_animation (pointer); - gdk_wayland_device_update_surface_cursor (device); - } - else - { - /* Nothing to do, we'already using the default cursor */ - } - } - else - { - g_set_object (&pointer->cursor, cursor); - pointer->cursor_is_default = FALSE; - - gdk_wayland_pointer_stop_cursor_animation (pointer); - gdk_wayland_device_update_surface_cursor (device); - } -} - -static GdkModifierType -device_get_modifiers (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer = - gdk_wayland_device_get_pointer (wayland_device); - GdkModifierType mask; - - mask = seat->key_modifiers; - - if (pointer) - mask |= pointer->button_modifiers; - - return mask; -} - -void -gdk_wayland_device_query_state (GdkDevice *device, - GdkSurface *surface, - double *win_x, - double *win_y, - GdkModifierType *mask) -{ - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer; - double x, y; - - if (mask) - *mask = device_get_modifiers (device); - - pointer = gdk_wayland_device_get_pointer (wayland_device); - - if (pointer->focus == surface) - { - x = pointer->surface_x; - y = pointer->surface_y; - } - else - { - x = y = -1; - } - - if (win_x) - *win_x = x; - if (win_y) - *win_y = y; -} - static void emulate_crossing (GdkSurface *surface, GdkSurface *child_surface, @@ -449,311 +203,6 @@ emulate_touch_crossing (GdkSurface *surface, _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); } -static void -emulate_focus (GdkSurface *surface, - GdkDevice *device, - gboolean focus_in, - guint32 time_) -{ - GdkEvent *event = gdk_focus_event_new (surface, device, focus_in); - - _gdk_wayland_display_deliver_event (gdk_surface_get_display (surface), event); -} - -static void -device_emit_grab_crossing (GdkDevice *device, - GdkSurface *from, - GdkSurface *to, - GdkCrossingMode mode, - guint32 time_) -{ - if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) - { - if (from) - emulate_focus (from, device, FALSE, time_); - if (to) - emulate_focus (to, device, TRUE, time_); - } - else - { - if (from) - emulate_crossing (from, to, device, GDK_LEAVE_NOTIFY, mode, time_); - if (to) - emulate_crossing (to, from, device, GDK_ENTER_NOTIFY, mode, time_); - } -} - -GdkSurface * -gdk_wayland_device_get_focus (GdkDevice *device) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer; - - if (device == wayland_seat->logical_keyboard) - return wayland_seat->keyboard_focus; - else - { - pointer = gdk_wayland_device_get_pointer (wayland_device); - - if (pointer) - return pointer->focus; - } - - return NULL; -} - -static void -device_maybe_emit_grab_crossing (GdkDevice *device, - GdkSurface *window, - guint32 time) -{ - GdkSurface *surface = gdk_wayland_device_get_focus (device); - GdkSurface *focus = window; - - if (focus != surface) - device_emit_grab_crossing (device, focus, window, GDK_CROSSING_GRAB, time); -} - -static GdkSurface* -device_maybe_emit_ungrab_crossing (GdkDevice *device, - guint32 time_) -{ - GdkDeviceGrabInfo *grab; - GdkSurface *focus = NULL; - GdkSurface *surface = NULL; - GdkSurface *prev_focus = NULL; - - focus = gdk_wayland_device_get_focus (device); - grab = _gdk_display_get_last_device_grab (gdk_device_get_display (device), device); - - if (grab) - { - prev_focus = grab->surface; - surface = grab->surface; - } - - if (focus != surface) - device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time_); - - return prev_focus; -} - -static GdkGrabStatus -gdk_wayland_device_grab (GdkDevice *device, - GdkSurface *surface, - gboolean owner_events, - GdkEventMask event_mask, - GdkSurface *confine_to, - GdkCursor *cursor, - guint32 time_) -{ - GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer = - gdk_wayland_device_get_pointer (wayland_device); - - if (GDK_IS_DRAG_SURFACE (surface) && - gdk_surface_get_mapped (surface)) - { - g_warning ("Surface %p is already mapped at the time of grabbing. " - "gdk_seat_grab() should be used to simultaneously grab input " - "and show this popup. You may find oddities ahead.", - surface); - } - - device_maybe_emit_grab_crossing (device, surface, time_); - - if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) - { - /* Device is a keyboard */ - gdk_wayland_surface_inhibit_shortcuts (surface, - gdk_device_get_seat (device)); - return GDK_GRAB_SUCCESS; - } - else - { - /* Device is a pointer */ - if (pointer->grab_surface != NULL && - time_ != 0 && pointer->grab_time > time_) - { - return GDK_GRAB_ALREADY_GRABBED; - } - - if (time_ == 0) - time_ = pointer->time; - - pointer->grab_surface = surface; - pointer->grab_time = time_; - _gdk_wayland_surface_set_grab_seat (surface, GDK_SEAT (wayland_seat)); - - g_clear_object (&wayland_seat->cursor); - - if (cursor) - wayland_seat->cursor = g_object_ref (cursor); - - gdk_wayland_device_update_surface_cursor (device); - } - - return GDK_GRAB_SUCCESS; -} - -static void -gdk_wayland_device_ungrab (GdkDevice *device, - guint32 time_) -{ - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer = - gdk_wayland_device_get_pointer (wayland_device); - GdkSurface *prev_focus; - - prev_focus = device_maybe_emit_ungrab_crossing (device, time_); - - if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) - { - /* Device is a keyboard */ - if (prev_focus) - gdk_wayland_surface_restore_shortcuts (prev_focus, - gdk_device_get_seat (device)); - } - else - { - /* Device is a pointer */ - gdk_wayland_device_update_surface_cursor (device); - - if (pointer->grab_surface) - _gdk_wayland_surface_set_grab_seat (pointer->grab_surface, - NULL); - } -} - -static GdkSurface * -gdk_wayland_device_surface_at_position (GdkDevice *device, - double *win_x, - double *win_y, - GdkModifierType *mask) -{ - GdkWaylandDevice *wayland_device = GDK_WAYLAND_DEVICE (device); - GdkWaylandPointerData *pointer; - - pointer = gdk_wayland_device_get_pointer (wayland_device); - - if (!pointer) - return NULL; - - if (win_x) - *win_x = pointer->surface_x; - if (win_y) - *win_y = pointer->surface_y; - if (mask) - *mask = device_get_modifiers (device); - - return pointer->focus; -} - -static void -gdk_wayland_device_class_init (GdkWaylandDeviceClass *klass) -{ - GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass); - - device_class->set_surface_cursor = gdk_wayland_device_set_surface_cursor; - device_class->grab = gdk_wayland_device_grab; - device_class->ungrab = gdk_wayland_device_ungrab; - device_class->surface_at_position = gdk_wayland_device_surface_at_position; -} - -static void -gdk_wayland_device_init (GdkWaylandDevice *device_core) -{ - GdkDevice *device; - - device = GDK_DEVICE (device_core); - - _gdk_device_add_axis (device, GDK_AXIS_X, 0, 0, 1); - _gdk_device_add_axis (device, GDK_AXIS_Y, 0, 0, 1); -} - -/** - * gdk_wayland_device_get_wl_seat: (skip) - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_seat` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_seat` - */ -struct wl_seat * -gdk_wayland_device_get_wl_seat (GdkDevice *device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->wl_seat; -} - -/** - * gdk_wayland_device_get_wl_pointer: (skip) - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_pointer` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_pointer` - */ -struct wl_pointer * -gdk_wayland_device_get_wl_pointer (GdkDevice *device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->wl_pointer; -} - -/** - * gdk_wayland_device_get_wl_keyboard: (skip) - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_keyboard` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_keyboard` - */ -struct wl_keyboard * -gdk_wayland_device_get_wl_keyboard (GdkDevice *device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->wl_keyboard; -} - -/** - * gdk_wayland_device_get_xkb_keymap: - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the `xkb_keymap` of a `GdkDevice`. - * - * Returns: (transfer none): a `struct xkb_keymap` - * - * Since: 4.4 - */ -struct xkb_keymap * -gdk_wayland_device_get_xkb_keymap (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return _gdk_wayland_keymap_get_xkb_keymap (seat->keymap); -} - -GdkKeymap * -_gdk_wayland_device_get_keymap (GdkDevice *device) -{ - GdkWaylandSeat *seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device)); - return seat->keymap; -} - static void gdk_wayland_seat_discard_pending_offer (GdkWaylandSeat *seat) { @@ -1096,7 +545,7 @@ flush_discrete_scroll_event (GdkWaylandSeat *seat, source, NULL, seat->pointer_info.time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), direction, value120_x, value120_y); @@ -1112,7 +561,7 @@ flush_discrete_scroll_event (GdkWaylandSeat *seat, source, NULL, seat->pointer_info.time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), direction); } } @@ -1135,7 +584,7 @@ flush_smooth_scroll_event (GdkWaylandSeat *seat, source, NULL, seat->pointer_info.time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), delta_x, delta_y, is_stop, GDK_SCROLL_UNIT_SURFACE); @@ -1307,7 +756,7 @@ pointer_handle_leave (void *data, g_object_unref (seat->pointer_info.focus); seat->pointer_info.focus = NULL; if (seat->cursor) - gdk_wayland_pointer_stop_cursor_animation (&seat->pointer_info); + gdk_wayland_seat_stop_cursor_animation (seat, &seat->pointer_info); if (display_wayland->seat_version < WL_POINTER_HAS_FRAME) gdk_wayland_seat_flush_frame_event (seat); @@ -1335,7 +784,7 @@ pointer_handle_motion (void *data, seat->logical_pointer, NULL, time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), seat->pointer_info.surface_x, seat->pointer_info.surface_y, NULL); @@ -1396,7 +845,7 @@ pointer_handle_button (void *data, seat->logical_pointer, NULL, time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), gdk_button, seat->pointer_info.surface_x, seat->pointer_info.surface_y, @@ -1902,7 +1351,7 @@ deliver_key_event (GdkWaylandSeat *seat, seat->logical_keyboard, time_, key, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), _gdk_wayland_keymap_key_is_modifier (keymap, key), &translated, &no_lock, @@ -2126,7 +1575,7 @@ gdk_wayland_seat_add_touch (GdkWaylandSeat *seat, return touch; } -static GdkWaylandTouchData * +GdkWaylandTouchData * gdk_wayland_seat_get_touch (GdkWaylandSeat *seat, uint32_t id) { @@ -2224,7 +1673,7 @@ touch_handle_down (void *data, touch->surface, seat->logical_touch, time, - device_get_modifiers (seat->logical_touch), + gdk_wayland_device_get_modifiers (seat->logical_touch), touch->x, touch->y, NULL, touch->initial_touch); @@ -2267,7 +1716,7 @@ touch_handle_up (void *data, touch->surface, seat->logical_touch, time, - device_get_modifiers (seat->logical_touch), + gdk_wayland_device_get_modifiers (seat->logical_touch), touch->x, touch->y, NULL, touch->initial_touch); @@ -2315,7 +1764,7 @@ touch_handle_motion (void *data, touch->surface, seat->logical_touch, time, - device_get_modifiers (seat->logical_touch), + gdk_wayland_device_get_modifiers (seat->logical_touch), touch->x, touch->y, NULL, touch->initial_touch); @@ -2357,7 +1806,7 @@ touch_handle_cancel (void *data, touch->surface, seat->logical_touch, GDK_CURRENT_TIME, - device_get_modifiers (seat->logical_touch), + gdk_wayland_device_get_modifiers (seat->logical_touch), touch->x, touch->y, NULL, touch->initial_touch); @@ -2407,7 +1856,7 @@ emit_gesture_swipe_event (GdkWaylandSeat *seat, GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), seat->logical_pointer, _time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), phase, seat->pointer_info.surface_x, seat->pointer_info.surface_y, @@ -2501,7 +1950,7 @@ emit_gesture_pinch_event (GdkWaylandSeat *seat, GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), seat->logical_pointer, _time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), phase, seat->pointer_info.surface_x, seat->pointer_info.surface_y, @@ -2597,7 +2046,7 @@ emit_gesture_hold_event (GdkWaylandSeat *seat, GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence), seat->logical_pointer, _time, - device_get_modifiers (seat->logical_pointer), + gdk_wayland_device_get_modifiers (seat->logical_pointer), phase, seat->pointer_info.surface_x, seat->pointer_info.surface_y, @@ -3417,7 +2866,8 @@ tablet_tool_handle_proximity_out (void *data, tablet->pointer_info.time); gdk_wayland_tablet_set_frame_event (tablet, event); - gdk_wayland_pointer_stop_cursor_animation (&tablet->pointer_info); + gdk_wayland_seat_stop_cursor_animation (GDK_WAYLAND_SEAT (tool->seat), + &tablet->pointer_info); tablet->pointer_info.pointer_surface_outputs = g_slist_remove (tablet->pointer_info.pointer_surface_outputs, @@ -3453,7 +2903,7 @@ tablet_create_button_event_frame (GdkWaylandTabletData *tablet, tablet->logical_device, tablet->current_tool->tool, tablet->pointer_info.time, - device_get_modifiers (tablet->logical_device), + gdk_wayland_device_get_modifiers (tablet->logical_device), button, tablet->pointer_info.surface_x, tablet->pointer_info.surface_y, @@ -3517,7 +2967,7 @@ tablet_tool_handle_motion (void *data, tablet->logical_device, tool->tool, tablet->pointer_info.time, - device_get_modifiers (tablet->logical_device), + gdk_wayland_device_get_modifiers (tablet->logical_device), tablet->pointer_info.surface_x, tablet->pointer_info.surface_y, tablet_copy_axes (tablet)); @@ -3709,7 +3159,7 @@ tablet_tool_handle_wheel (void *data, tablet->logical_device, tablet->current_tool->tool, tablet->pointer_info.time, - device_get_modifiers (tablet->logical_device), + gdk_wayland_device_get_modifiers (tablet->logical_device), 0, clicks, FALSE, GDK_SCROLL_UNIT_WHEEL); @@ -4531,8 +3981,8 @@ gdk_wayland_seat_grab (GdkSeat *seat, if (wayland_seat->logical_pointer && capabilities & GDK_SEAT_CAPABILITY_POINTER) { - device_maybe_emit_grab_crossing (wayland_seat->logical_pointer, - surface, evtime); + gdk_wayland_device_maybe_emit_grab_crossing (wayland_seat->logical_pointer, + surface, evtime); _gdk_display_add_device_grab (display, wayland_seat->logical_pointer, @@ -4551,8 +4001,8 @@ gdk_wayland_seat_grab (GdkSeat *seat, if (wayland_seat->logical_touch && capabilities & GDK_SEAT_CAPABILITY_TOUCH) { - device_maybe_emit_grab_crossing (wayland_seat->logical_touch, - surface, evtime); + gdk_wayland_device_maybe_emit_grab_crossing (wayland_seat->logical_touch, + surface, evtime); _gdk_display_add_device_grab (display, wayland_seat->logical_touch, @@ -4567,8 +4017,8 @@ gdk_wayland_seat_grab (GdkSeat *seat, if (wayland_seat->logical_keyboard && capabilities & GDK_SEAT_CAPABILITY_KEYBOARD) { - device_maybe_emit_grab_crossing (wayland_seat->logical_keyboard, - surface, evtime); + gdk_wayland_device_maybe_emit_grab_crossing (wayland_seat->logical_keyboard, + surface, evtime); _gdk_display_add_device_grab (display, wayland_seat->logical_keyboard, @@ -4591,9 +4041,9 @@ gdk_wayland_seat_grab (GdkSeat *seat, { GdkWaylandTabletData *tablet = l->data; - device_maybe_emit_grab_crossing (tablet->logical_device, - surface, - evtime); + gdk_wayland_device_maybe_emit_grab_crossing (tablet->logical_device, + surface, + evtime); _gdk_display_add_device_grab (display, tablet->logical_device, @@ -4625,8 +4075,8 @@ gdk_wayland_seat_ungrab (GdkSeat *seat) if (wayland_seat->logical_pointer) { - device_maybe_emit_ungrab_crossing (wayland_seat->logical_pointer, - GDK_CURRENT_TIME); + gdk_wayland_device_maybe_emit_ungrab_crossing (wayland_seat->logical_pointer, + GDK_CURRENT_TIME); gdk_wayland_device_update_surface_cursor (wayland_seat->logical_pointer); } @@ -4635,8 +4085,8 @@ gdk_wayland_seat_ungrab (GdkSeat *seat) { GdkSurface *prev_focus; - prev_focus = device_maybe_emit_ungrab_crossing (wayland_seat->logical_keyboard, - GDK_CURRENT_TIME); + prev_focus = gdk_wayland_device_maybe_emit_ungrab_crossing (wayland_seat->logical_keyboard, + GDK_CURRENT_TIME); if (prev_focus) gdk_wayland_surface_restore_shortcuts (prev_focus, seat); } @@ -4932,43 +4382,6 @@ _gdk_wayland_seat_get_last_implicit_grab_serial (GdkWaylandSeat *seat, return serial; } -void -gdk_wayland_device_unset_touch_grab (GdkDevice *gdk_device, - GdkEventSequence *sequence) -{ - GdkWaylandSeat *seat; - GdkWaylandTouchData *touch; - GdkEvent *event; - - g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); - touch = gdk_wayland_seat_get_touch (seat, - GDK_EVENT_SEQUENCE_TO_SLOT (sequence)); - - if (touch == - gdk_wayland_device_get_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch))) - { - gdk_wayland_device_set_emulating_touch (GDK_WAYLAND_DEVICE (seat->logical_touch), - NULL); - emulate_touch_crossing (touch->surface, NULL, - seat->logical_touch, seat->touch, - touch, GDK_LEAVE_NOTIFY, GDK_CROSSING_NORMAL, - GDK_CURRENT_TIME); - } - - event = gdk_touch_event_new (GDK_TOUCH_CANCEL, - GDK_SLOT_TO_EVENT_SEQUENCE (touch->id), - touch->surface, - seat->logical_touch, - GDK_CURRENT_TIME, - device_get_modifiers (seat->logical_touch), - touch->x, touch->y, - NULL, - touch->initial_touch); - _gdk_wayland_display_deliver_event (seat->display, event); -} - void gdk_wayland_seat_set_global_cursor (GdkSeat *seat, GdkCursor *cursor) @@ -4979,9 +4392,9 @@ gdk_wayland_seat_set_global_cursor (GdkSeat *seat, pointer = gdk_seat_get_pointer (seat); g_set_object (&wayland_seat->grab_cursor, cursor); - gdk_wayland_device_set_surface_cursor (pointer, - gdk_wayland_device_get_focus (pointer), - NULL); + GDK_DEVICE_GET_CLASS (pointer)->set_surface_cursor (pointer, + gdk_wayland_device_get_focus (pointer), + NULL); } void @@ -4993,49 +4406,6 @@ gdk_wayland_seat_set_drag (GdkSeat *seat, g_set_object (&wayland_seat->drag, drag); } -/** - * gdk_wayland_device_get_data_device: (skip) - * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the Wayland `wl_data_device` of a `GdkDevice`. - * - * Returns: (transfer none): a Wayland `wl_data_device` - */ -struct wl_data_device * -gdk_wayland_device_get_data_device (GdkDevice *gdk_device) -{ - GdkWaylandSeat *seat; - - g_return_val_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device), NULL); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); - return seat->data_device; -} - -/** - * gdk_wayland_device_set_selection: (skip) - * @gdk_device: (type GdkWaylandDevice): a `GdkDevice` - * @source: the data source for the selection - * - * Sets the selection of the `GdkDevice. - * - * This is calling wl_data_device_set_selection() on - * the `wl_data_device` of @gdk_device. - */ -void -gdk_wayland_device_set_selection (GdkDevice *gdk_device, - struct wl_data_source *source) -{ - GdkWaylandSeat *seat; - guint32 serial; - - g_return_if_fail (GDK_IS_WAYLAND_DEVICE (gdk_device)); - - seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (gdk_device)); - serial = _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL); - wl_data_device_set_selection (seat->data_device, source, serial); -} - /** * gdk_wayland_seat_get_wl_seat: (skip) * @seat: (type GdkWaylandSeat): a `GdkSeat` @@ -5051,41 +4421,3 @@ gdk_wayland_seat_get_wl_seat (GdkSeat *seat) return GDK_WAYLAND_SEAT (seat)->wl_seat; } - -/** - * gdk_wayland_device_get_node_path: - * @device: (type GdkWaylandDevice): a `GdkDevice` - * - * Returns the `/dev/input/event*` path of this device. - * - * For `GdkDevice`s that possibly coalesce multiple hardware - * devices (eg. mouse, keyboard, touch,...), this function - * will return %NULL. - * - * This is most notably implemented for devices of type - * %GDK_SOURCE_PEN, %GDK_SOURCE_TABLET_PAD. - * - * Returns: (nullable) (transfer none): the `/dev/input/event*` - * path of this device - */ -const char * -gdk_wayland_device_get_node_path (GdkDevice *device) -{ - GdkWaylandTabletData *tablet; - GdkWaylandTabletPadData *pad; - - GdkSeat *seat; - - g_return_val_if_fail (GDK_IS_DEVICE (device), NULL); - - seat = gdk_device_get_seat (device); - tablet = gdk_wayland_seat_find_tablet (GDK_WAYLAND_SEAT (seat), device); - if (tablet) - return tablet->path; - - pad = gdk_wayland_seat_find_pad (GDK_WAYLAND_SEAT (seat), device); - if (pad) - return pad->path; - - return NULL; -} diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 79a770c1f1..48317bdb88 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -5,6 +5,7 @@ gdk_wayland_sources = files([ 'gdkcairocontext-wayland.c', 'gdkclipboard-wayland.c', 'gdkcursor-wayland.c', + 'gdkdevice-wayland.c', 'gdkdevicepad-wayland.c', 'gdkdisplay-wayland.c', 'gdkdrag-wayland.c', -- cgit v1.2.1 From 4005eb8fe898f6f0e214a4bff6f29065e1952b62 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 3 Feb 2023 16:13:37 +0100 Subject: gdk/wayland: Rename gdkkeys-wayland.c file Since it contains the GdkKeymap implementation, give it a more obvious name. --- gdk/wayland/gdkkeymap-wayland.c | 620 ++++++++++++++++++++++++++++++++++++++++ gdk/wayland/gdkkeys-wayland.c | 620 ---------------------------------------- gdk/wayland/meson.build | 2 +- 3 files changed, 621 insertions(+), 621 deletions(-) create mode 100644 gdk/wayland/gdkkeymap-wayland.c delete mode 100644 gdk/wayland/gdkkeys-wayland.c diff --git a/gdk/wayland/gdkkeymap-wayland.c b/gdk/wayland/gdkkeymap-wayland.c new file mode 100644 index 0000000000..22b8cb0199 --- /dev/null +++ b/gdk/wayland/gdkkeymap-wayland.c @@ -0,0 +1,620 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "gdk.h" +#include "gdkwayland.h" + +#include "gdkprivate-wayland.h" +#include "gdkprivate.h" +#include "gdkkeysprivate.h" + +#include + +typedef struct _GdkWaylandKeymap GdkWaylandKeymap; +typedef struct _GdkWaylandKeymapClass GdkWaylandKeymapClass; + +struct _GdkWaylandKeymap +{ + GdkKeymap parent_instance; + + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + + PangoDirection *direction; + gboolean bidi; +}; + +struct _GdkWaylandKeymapClass +{ + GdkKeymapClass parent_class; +}; + +#define GDK_TYPE_WAYLAND_KEYMAP (_gdk_wayland_keymap_get_type ()) +#define GDK_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap)) +#define GDK_IS_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP)) + +GType _gdk_wayland_keymap_get_type (void); + +G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP) + +static void +gdk_wayland_keymap_finalize (GObject *object) +{ + GdkWaylandKeymap *keymap = GDK_WAYLAND_KEYMAP (object); + + xkb_keymap_unref (keymap->xkb_keymap); + xkb_state_unref (keymap->xkb_state); + g_free (keymap->direction); + + G_OBJECT_CLASS (_gdk_wayland_keymap_parent_class)->finalize (object); +} + +static PangoDirection +gdk_wayland_keymap_get_direction (GdkKeymap *keymap) +{ + GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap); + int i; + + for (i = 0; i < xkb_keymap_num_layouts (keymap_wayland->xkb_keymap); i++) + { + if (xkb_state_layout_index_is_active (keymap_wayland->xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) + return keymap_wayland->direction[i]; + } + + return PANGO_DIRECTION_NEUTRAL; +} + +static gboolean +gdk_wayland_keymap_have_bidi_layouts (GdkKeymap *keymap) +{ + GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap); + + return keymap_wayland->bidi; +} + +static gboolean +gdk_wayland_keymap_get_caps_lock_state (GdkKeymap *keymap) +{ + return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state, + XKB_LED_NAME_CAPS); +} + +static gboolean +gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap) +{ + return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state, + XKB_LED_NAME_NUM); +} + +static gboolean +gdk_wayland_keymap_get_scroll_lock_state (GdkKeymap *keymap) +{ + return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state, + XKB_LED_NAME_SCROLL); +} + +static gboolean +gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap *keymap, + guint keyval, + GArray *retval) +{ + struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + guint keycode; + xkb_keycode_t min_keycode, max_keycode; + guint len = retval->len; + + min_keycode = xkb_keymap_min_keycode (xkb_keymap); + max_keycode = xkb_keymap_max_keycode (xkb_keymap); + for (keycode = min_keycode; keycode < max_keycode; keycode++) + { + int num_layouts, layout; + num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode); + for (layout = 0; layout < num_layouts; layout++) + { + int num_levels, level; + num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout); + for (level = 0; level < num_levels; level++) + { + const xkb_keysym_t *syms; + int num_syms, sym; + num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms); + for (sym = 0; sym < num_syms; sym++) + { + if (syms[sym] == keyval) + { + GdkKeymapKey key; + + key.keycode = keycode; + key.group = layout; + key.level = level; + + g_array_append_val (retval, key); + } + } + } + } + } + + return retval->len > len; +} + +static gboolean +gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap *keymap, + guint hardware_keycode, + GdkKeymapKey **keys, + guint **keyvals, + int *n_entries) +{ + struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + int num_layouts, layout; + int num_entries; + int i; + + num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, hardware_keycode); + + num_entries = 0; + for (layout = 0; layout < num_layouts; layout++) + num_entries += xkb_keymap_num_levels_for_key (xkb_keymap, hardware_keycode, layout); + + if (n_entries) + *n_entries = num_entries; + if (keys) + *keys = g_new0 (GdkKeymapKey, num_entries); + if (keyvals) + *keyvals = g_new0 (guint, num_entries); + + i = 0; + for (layout = 0; layout < num_layouts; layout++) + { + int num_levels, level; + num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, hardware_keycode, layout); + for (level = 0; level < num_levels; level++) + { + const xkb_keysym_t *syms; + int num_syms; + num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, hardware_keycode, layout, level, &syms); + if (keys) + { + (*keys)[i].keycode = hardware_keycode; + (*keys)[i].group = layout; + (*keys)[i].level = level; + } + if (keyvals && num_syms > 0) + (*keyvals)[i] = syms[0]; + + i++; + } + } + + return num_entries > 0; +} + +static guint +gdk_wayland_keymap_lookup_key (GdkKeymap *keymap, + const GdkKeymapKey *key) +{ + struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + const xkb_keysym_t *syms; + int num_syms; + + num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, + key->keycode, + key->group, + key->level, + &syms); + if (num_syms > 0) + return syms[0]; + else + return XKB_KEY_NoSymbol; +} + +static guint32 +get_xkb_modifiers (struct xkb_keymap *xkb_keymap, + GdkModifierType state) +{ + guint32 mods = 0; + + if (state & GDK_SHIFT_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT); + if (state & GDK_LOCK_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS); + if (state & GDK_CONTROL_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CTRL); + if (state & GDK_ALT_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT); + if (state & GDK_SUPER_MASK) + mods |= (1 << xkb_keymap_mod_get_index (xkb_keymap, "Super") | 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_LOGO)); + if (state & GDK_HYPER_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Hyper"); + if (state & GDK_META_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Meta"); + + return mods; +} + +static GdkModifierType +get_gdk_modifiers (struct xkb_keymap *xkb_keymap, + guint32 mods) +{ + GdkModifierType state = 0; + + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT))) + state |= GDK_SHIFT_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS))) + state |= GDK_LOCK_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CTRL))) + state |= GDK_CONTROL_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT))) + state |= GDK_ALT_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_LOGO))) + state |= GDK_SUPER_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Super"))) + state |= GDK_SUPER_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Hyper"))) + state |= GDK_HYPER_MASK; + /* GTK treats MOD1 as a synonym for Alt, and does not expect it to + * be mapped around, so we should avoid adding GDK_META_MASK if MOD1 + * is already included to avoid confusing GTK and applications that + * rely on that behavior. + */ + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Meta")) && + (state & GDK_ALT_MASK) == 0) + state |= GDK_META_MASK; + + return state; +} + +GdkModifierType +gdk_wayland_keymap_get_gdk_modifiers (GdkKeymap *keymap, + guint32 mods) +{ + struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + + return get_gdk_modifiers (xkb_keymap, mods); +} + +static gboolean +gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, + guint hardware_keycode, + GdkModifierType state, + int group, + guint *keyval, + int *effective_group, + int *effective_level, + GdkModifierType *consumed_modifiers) +{ + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + guint32 modifiers; + guint32 consumed; + xkb_layout_index_t layout; + xkb_level_index_t level; + xkb_keysym_t sym; + + g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); + g_return_val_if_fail (group < 4, FALSE); + + xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + + modifiers = get_xkb_modifiers (xkb_keymap, state); + + xkb_state = xkb_state_new (xkb_keymap); + + xkb_state_update_mask (xkb_state, modifiers, 0, 0, group, 0, 0); + + layout = xkb_state_key_get_layout (xkb_state, hardware_keycode); + level = xkb_state_key_get_level (xkb_state, hardware_keycode, layout); + sym = xkb_state_key_get_one_sym (xkb_state, hardware_keycode); + consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (xkb_state, hardware_keycode, modifiers); + + xkb_state_unref (xkb_state); + + if (keyval) + *keyval = sym; + if (effective_group) + *effective_group = layout; + if (effective_level) + *effective_level = level; + if (consumed_modifiers) + *consumed_modifiers = get_gdk_modifiers (xkb_keymap, consumed); + + return (sym != XKB_KEY_NoSymbol); +} + +static guint +gdk_wayland_keymap_get_modifier_state (GdkKeymap *keymap) +{ + struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + struct xkb_state *xkb_state = GDK_WAYLAND_KEYMAP (keymap)->xkb_state; + xkb_mod_mask_t mods; + + mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); + + return get_gdk_modifiers (xkb_keymap, mods); +} + +static void +_gdk_wayland_keymap_class_init (GdkWaylandKeymapClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass); + + object_class->finalize = gdk_wayland_keymap_finalize; + + keymap_class->get_direction = gdk_wayland_keymap_get_direction; + keymap_class->have_bidi_layouts = gdk_wayland_keymap_have_bidi_layouts; + keymap_class->get_caps_lock_state = gdk_wayland_keymap_get_caps_lock_state; + keymap_class->get_num_lock_state = gdk_wayland_keymap_get_num_lock_state; + keymap_class->get_scroll_lock_state = gdk_wayland_keymap_get_scroll_lock_state; + keymap_class->get_entries_for_keyval = gdk_wayland_keymap_get_entries_for_keyval; + keymap_class->get_entries_for_keycode = gdk_wayland_keymap_get_entries_for_keycode; + keymap_class->lookup_key = gdk_wayland_keymap_lookup_key; + keymap_class->translate_keyboard_state = gdk_wayland_keymap_translate_keyboard_state; + keymap_class->get_modifier_state = gdk_wayland_keymap_get_modifier_state; +} + +static void +_gdk_wayland_keymap_init (GdkWaylandKeymap *keymap) +{ +} + +static void +update_direction (GdkWaylandKeymap *keymap) +{ + int num_layouts; + int i; + int *rtl; + xkb_keycode_t min_keycode, max_keycode; + guint key; + gboolean have_rtl, have_ltr; + + num_layouts = xkb_keymap_num_layouts (keymap->xkb_keymap); + + keymap->direction = g_renew (PangoDirection, keymap->direction, num_layouts); + rtl = g_newa (int, num_layouts); + for (i = 0; i < num_layouts; i++) + rtl[i] = 0; + + min_keycode = xkb_keymap_min_keycode (keymap->xkb_keymap); + max_keycode = xkb_keymap_max_keycode (keymap->xkb_keymap); + for (key = min_keycode; key < max_keycode; key++) + { + int layouts, layout; + + layouts = xkb_keymap_num_layouts_for_key (keymap->xkb_keymap, key); + g_assert (layouts <= num_layouts); + for (layout = 0; layout < layouts; layout++) + { + const xkb_keysym_t *syms; + int num_syms; + int sym; + + num_syms = xkb_keymap_key_get_syms_by_level (keymap->xkb_keymap, key, layout, 0, &syms); + for (sym = 0; sym < num_syms; sym++) + { + PangoDirection dir; + + dir = gdk_unichar_direction (xkb_keysym_to_utf32 (syms[sym])); + switch (dir) + { + case PANGO_DIRECTION_RTL: + rtl[layout]++; + break; + case PANGO_DIRECTION_LTR: + rtl[layout]--; + break; + case PANGO_DIRECTION_TTB_LTR: + case PANGO_DIRECTION_TTB_RTL: + case PANGO_DIRECTION_WEAK_LTR: + case PANGO_DIRECTION_WEAK_RTL: + case PANGO_DIRECTION_NEUTRAL: + default: + break; + } + } + } + } + + have_rtl = have_ltr = FALSE; + for (i = 0; i < num_layouts; i++) + { + if (rtl[i] > 0) + { + keymap->direction[i] = PANGO_DIRECTION_RTL; + have_rtl = TRUE; + } + else + { + keymap->direction[i] = PANGO_DIRECTION_LTR; + have_ltr = TRUE; + } + } + + if (have_rtl && have_ltr) + keymap->bidi = TRUE; +} + +GdkKeymap * +_gdk_wayland_keymap_new (GdkDisplay *display) +{ + GdkWaylandKeymap *keymap; + struct xkb_context *context; + struct xkb_rule_names names; + + keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL); + GDK_KEYMAP (keymap)->display = display; + + context = xkb_context_new (0); + + names.rules = "evdev"; + names.model = "pc105"; + names.layout = "us"; + names.variant = ""; + names.options = ""; + keymap->xkb_keymap = xkb_keymap_new_from_names (context, &names, 0); + keymap->xkb_state = xkb_state_new (keymap->xkb_keymap); + xkb_context_unref (context); + + update_direction (keymap); + + return GDK_KEYMAP (keymap); +} + +static void +print_modifiers (GdkDisplay *display, + struct xkb_keymap *keymap) +{ +#ifdef G_ENABLE_DEBUG + int i, j; + uint32_t real; + struct xkb_state *state; + GString *str; + + if (!GDK_DISPLAY_DEBUG_CHECK (display, INPUT)) + return; + + str = g_string_new (""); + + g_string_append (str, "modifiers:\n"); + for (i = 0; i < xkb_keymap_num_mods (keymap); i++) + g_string_append_printf (str, "%s ", xkb_keymap_mod_get_name (keymap, i)); + g_string_append (str, "\n\n"); + + g_string_append (str, "modifier mapping\n"); + state = xkb_state_new (keymap); + for (i = 0; i < 8; i++) + { + gboolean need_arrow = TRUE; + g_string_append_printf (str, "%s ", xkb_keymap_mod_get_name (keymap, i)); + for (j = 8; j < xkb_keymap_num_mods (keymap); j++) + { + xkb_state_update_mask (state, 1 << j, 0, 0, 0, 0, 0); + real = xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE); + if (real & (1 << i)) + { + if (need_arrow) + { + g_string_append (str, "-> "); + need_arrow = FALSE; + } + g_string_append_printf (str, "%s ", xkb_keymap_mod_get_name (keymap, j)); + } + } + } + + gdk_debug_message ("%s", str->str); + + g_string_free (str, TRUE); + + xkb_state_unref (state); +#endif +} + +void +_gdk_wayland_keymap_update_from_fd (GdkKeymap *keymap, + uint32_t format, + uint32_t fd, + uint32_t size) +{ + GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap); + struct xkb_context *context; + struct xkb_keymap *xkb_keymap; + char *map_str; + + context = xkb_context_new (0); + + map_str = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map_str == MAP_FAILED) + { + close(fd); + return; + } + + GDK_DISPLAY_DEBUG (keymap->display, INPUT, "keymap:\n%s", map_str); + + xkb_keymap = xkb_keymap_new_from_string (context, map_str, format, 0); + munmap (map_str, size); + close (fd); + + if (!xkb_keymap) + { + g_warning ("Got invalid keymap from compositor, keeping previous/default one"); + xkb_context_unref (context); + return; + } + + print_modifiers (keymap->display, xkb_keymap); + + xkb_keymap_unref (keymap_wayland->xkb_keymap); + keymap_wayland->xkb_keymap = xkb_keymap; + + xkb_state_unref (keymap_wayland->xkb_state); + keymap_wayland->xkb_state = xkb_state_new (keymap_wayland->xkb_keymap); + + xkb_context_unref (context); + + update_direction (keymap_wayland); +} + +struct xkb_keymap * +_gdk_wayland_keymap_get_xkb_keymap (GdkKeymap *keymap) +{ + return GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; +} + +struct xkb_state * +_gdk_wayland_keymap_get_xkb_state (GdkKeymap *keymap) +{ + return GDK_WAYLAND_KEYMAP (keymap)->xkb_state; +} + +gboolean +_gdk_wayland_keymap_key_is_modifier (GdkKeymap *keymap, + guint keycode) +{ + struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + struct xkb_state *xkb_state; + gboolean is_modifier; + + is_modifier = FALSE; + + xkb_state = xkb_state_new (xkb_keymap); + + if (xkb_state_update_key (xkb_state, keycode, XKB_KEY_DOWN) & XKB_STATE_MODS_EFFECTIVE) + is_modifier = TRUE; + + xkb_state_unref (xkb_state); + + return is_modifier; +} diff --git a/gdk/wayland/gdkkeys-wayland.c b/gdk/wayland/gdkkeys-wayland.c deleted file mode 100644 index 22b8cb0199..0000000000 --- a/gdk/wayland/gdkkeys-wayland.c +++ /dev/null @@ -1,620 +0,0 @@ -/* GDK - The GIMP Drawing Kit - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - */ - -/* - * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS - * file for a list of people on the GTK+ Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "gdk.h" -#include "gdkwayland.h" - -#include "gdkprivate-wayland.h" -#include "gdkprivate.h" -#include "gdkkeysprivate.h" - -#include - -typedef struct _GdkWaylandKeymap GdkWaylandKeymap; -typedef struct _GdkWaylandKeymapClass GdkWaylandKeymapClass; - -struct _GdkWaylandKeymap -{ - GdkKeymap parent_instance; - - struct xkb_keymap *xkb_keymap; - struct xkb_state *xkb_state; - - PangoDirection *direction; - gboolean bidi; -}; - -struct _GdkWaylandKeymapClass -{ - GdkKeymapClass parent_class; -}; - -#define GDK_TYPE_WAYLAND_KEYMAP (_gdk_wayland_keymap_get_type ()) -#define GDK_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap)) -#define GDK_IS_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP)) - -GType _gdk_wayland_keymap_get_type (void); - -G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP) - -static void -gdk_wayland_keymap_finalize (GObject *object) -{ - GdkWaylandKeymap *keymap = GDK_WAYLAND_KEYMAP (object); - - xkb_keymap_unref (keymap->xkb_keymap); - xkb_state_unref (keymap->xkb_state); - g_free (keymap->direction); - - G_OBJECT_CLASS (_gdk_wayland_keymap_parent_class)->finalize (object); -} - -static PangoDirection -gdk_wayland_keymap_get_direction (GdkKeymap *keymap) -{ - GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap); - int i; - - for (i = 0; i < xkb_keymap_num_layouts (keymap_wayland->xkb_keymap); i++) - { - if (xkb_state_layout_index_is_active (keymap_wayland->xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) - return keymap_wayland->direction[i]; - } - - return PANGO_DIRECTION_NEUTRAL; -} - -static gboolean -gdk_wayland_keymap_have_bidi_layouts (GdkKeymap *keymap) -{ - GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap); - - return keymap_wayland->bidi; -} - -static gboolean -gdk_wayland_keymap_get_caps_lock_state (GdkKeymap *keymap) -{ - return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state, - XKB_LED_NAME_CAPS); -} - -static gboolean -gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap) -{ - return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state, - XKB_LED_NAME_NUM); -} - -static gboolean -gdk_wayland_keymap_get_scroll_lock_state (GdkKeymap *keymap) -{ - return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state, - XKB_LED_NAME_SCROLL); -} - -static gboolean -gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap *keymap, - guint keyval, - GArray *retval) -{ - struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - guint keycode; - xkb_keycode_t min_keycode, max_keycode; - guint len = retval->len; - - min_keycode = xkb_keymap_min_keycode (xkb_keymap); - max_keycode = xkb_keymap_max_keycode (xkb_keymap); - for (keycode = min_keycode; keycode < max_keycode; keycode++) - { - int num_layouts, layout; - num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, keycode); - for (layout = 0; layout < num_layouts; layout++) - { - int num_levels, level; - num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout); - for (level = 0; level < num_levels; level++) - { - const xkb_keysym_t *syms; - int num_syms, sym; - num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms); - for (sym = 0; sym < num_syms; sym++) - { - if (syms[sym] == keyval) - { - GdkKeymapKey key; - - key.keycode = keycode; - key.group = layout; - key.level = level; - - g_array_append_val (retval, key); - } - } - } - } - } - - return retval->len > len; -} - -static gboolean -gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap *keymap, - guint hardware_keycode, - GdkKeymapKey **keys, - guint **keyvals, - int *n_entries) -{ - struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - int num_layouts, layout; - int num_entries; - int i; - - num_layouts = xkb_keymap_num_layouts_for_key (xkb_keymap, hardware_keycode); - - num_entries = 0; - for (layout = 0; layout < num_layouts; layout++) - num_entries += xkb_keymap_num_levels_for_key (xkb_keymap, hardware_keycode, layout); - - if (n_entries) - *n_entries = num_entries; - if (keys) - *keys = g_new0 (GdkKeymapKey, num_entries); - if (keyvals) - *keyvals = g_new0 (guint, num_entries); - - i = 0; - for (layout = 0; layout < num_layouts; layout++) - { - int num_levels, level; - num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, hardware_keycode, layout); - for (level = 0; level < num_levels; level++) - { - const xkb_keysym_t *syms; - int num_syms; - num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, hardware_keycode, layout, level, &syms); - if (keys) - { - (*keys)[i].keycode = hardware_keycode; - (*keys)[i].group = layout; - (*keys)[i].level = level; - } - if (keyvals && num_syms > 0) - (*keyvals)[i] = syms[0]; - - i++; - } - } - - return num_entries > 0; -} - -static guint -gdk_wayland_keymap_lookup_key (GdkKeymap *keymap, - const GdkKeymapKey *key) -{ - struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - const xkb_keysym_t *syms; - int num_syms; - - num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, - key->keycode, - key->group, - key->level, - &syms); - if (num_syms > 0) - return syms[0]; - else - return XKB_KEY_NoSymbol; -} - -static guint32 -get_xkb_modifiers (struct xkb_keymap *xkb_keymap, - GdkModifierType state) -{ - guint32 mods = 0; - - if (state & GDK_SHIFT_MASK) - mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT); - if (state & GDK_LOCK_MASK) - mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS); - if (state & GDK_CONTROL_MASK) - mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CTRL); - if (state & GDK_ALT_MASK) - mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT); - if (state & GDK_SUPER_MASK) - mods |= (1 << xkb_keymap_mod_get_index (xkb_keymap, "Super") | 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_LOGO)); - if (state & GDK_HYPER_MASK) - mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Hyper"); - if (state & GDK_META_MASK) - mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Meta"); - - return mods; -} - -static GdkModifierType -get_gdk_modifiers (struct xkb_keymap *xkb_keymap, - guint32 mods) -{ - GdkModifierType state = 0; - - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT))) - state |= GDK_SHIFT_MASK; - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS))) - state |= GDK_LOCK_MASK; - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CTRL))) - state |= GDK_CONTROL_MASK; - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT))) - state |= GDK_ALT_MASK; - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_LOGO))) - state |= GDK_SUPER_MASK; - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Super"))) - state |= GDK_SUPER_MASK; - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Hyper"))) - state |= GDK_HYPER_MASK; - /* GTK treats MOD1 as a synonym for Alt, and does not expect it to - * be mapped around, so we should avoid adding GDK_META_MASK if MOD1 - * is already included to avoid confusing GTK and applications that - * rely on that behavior. - */ - if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Meta")) && - (state & GDK_ALT_MASK) == 0) - state |= GDK_META_MASK; - - return state; -} - -GdkModifierType -gdk_wayland_keymap_get_gdk_modifiers (GdkKeymap *keymap, - guint32 mods) -{ - struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - - return get_gdk_modifiers (xkb_keymap, mods); -} - -static gboolean -gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap, - guint hardware_keycode, - GdkModifierType state, - int group, - guint *keyval, - int *effective_group, - int *effective_level, - GdkModifierType *consumed_modifiers) -{ - struct xkb_keymap *xkb_keymap; - struct xkb_state *xkb_state; - guint32 modifiers; - guint32 consumed; - xkb_layout_index_t layout; - xkb_level_index_t level; - xkb_keysym_t sym; - - g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); - g_return_val_if_fail (group < 4, FALSE); - - xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - - modifiers = get_xkb_modifiers (xkb_keymap, state); - - xkb_state = xkb_state_new (xkb_keymap); - - xkb_state_update_mask (xkb_state, modifiers, 0, 0, group, 0, 0); - - layout = xkb_state_key_get_layout (xkb_state, hardware_keycode); - level = xkb_state_key_get_level (xkb_state, hardware_keycode, layout); - sym = xkb_state_key_get_one_sym (xkb_state, hardware_keycode); - consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (xkb_state, hardware_keycode, modifiers); - - xkb_state_unref (xkb_state); - - if (keyval) - *keyval = sym; - if (effective_group) - *effective_group = layout; - if (effective_level) - *effective_level = level; - if (consumed_modifiers) - *consumed_modifiers = get_gdk_modifiers (xkb_keymap, consumed); - - return (sym != XKB_KEY_NoSymbol); -} - -static guint -gdk_wayland_keymap_get_modifier_state (GdkKeymap *keymap) -{ - struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - struct xkb_state *xkb_state = GDK_WAYLAND_KEYMAP (keymap)->xkb_state; - xkb_mod_mask_t mods; - - mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); - - return get_gdk_modifiers (xkb_keymap, mods); -} - -static void -_gdk_wayland_keymap_class_init (GdkWaylandKeymapClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass); - - object_class->finalize = gdk_wayland_keymap_finalize; - - keymap_class->get_direction = gdk_wayland_keymap_get_direction; - keymap_class->have_bidi_layouts = gdk_wayland_keymap_have_bidi_layouts; - keymap_class->get_caps_lock_state = gdk_wayland_keymap_get_caps_lock_state; - keymap_class->get_num_lock_state = gdk_wayland_keymap_get_num_lock_state; - keymap_class->get_scroll_lock_state = gdk_wayland_keymap_get_scroll_lock_state; - keymap_class->get_entries_for_keyval = gdk_wayland_keymap_get_entries_for_keyval; - keymap_class->get_entries_for_keycode = gdk_wayland_keymap_get_entries_for_keycode; - keymap_class->lookup_key = gdk_wayland_keymap_lookup_key; - keymap_class->translate_keyboard_state = gdk_wayland_keymap_translate_keyboard_state; - keymap_class->get_modifier_state = gdk_wayland_keymap_get_modifier_state; -} - -static void -_gdk_wayland_keymap_init (GdkWaylandKeymap *keymap) -{ -} - -static void -update_direction (GdkWaylandKeymap *keymap) -{ - int num_layouts; - int i; - int *rtl; - xkb_keycode_t min_keycode, max_keycode; - guint key; - gboolean have_rtl, have_ltr; - - num_layouts = xkb_keymap_num_layouts (keymap->xkb_keymap); - - keymap->direction = g_renew (PangoDirection, keymap->direction, num_layouts); - rtl = g_newa (int, num_layouts); - for (i = 0; i < num_layouts; i++) - rtl[i] = 0; - - min_keycode = xkb_keymap_min_keycode (keymap->xkb_keymap); - max_keycode = xkb_keymap_max_keycode (keymap->xkb_keymap); - for (key = min_keycode; key < max_keycode; key++) - { - int layouts, layout; - - layouts = xkb_keymap_num_layouts_for_key (keymap->xkb_keymap, key); - g_assert (layouts <= num_layouts); - for (layout = 0; layout < layouts; layout++) - { - const xkb_keysym_t *syms; - int num_syms; - int sym; - - num_syms = xkb_keymap_key_get_syms_by_level (keymap->xkb_keymap, key, layout, 0, &syms); - for (sym = 0; sym < num_syms; sym++) - { - PangoDirection dir; - - dir = gdk_unichar_direction (xkb_keysym_to_utf32 (syms[sym])); - switch (dir) - { - case PANGO_DIRECTION_RTL: - rtl[layout]++; - break; - case PANGO_DIRECTION_LTR: - rtl[layout]--; - break; - case PANGO_DIRECTION_TTB_LTR: - case PANGO_DIRECTION_TTB_RTL: - case PANGO_DIRECTION_WEAK_LTR: - case PANGO_DIRECTION_WEAK_RTL: - case PANGO_DIRECTION_NEUTRAL: - default: - break; - } - } - } - } - - have_rtl = have_ltr = FALSE; - for (i = 0; i < num_layouts; i++) - { - if (rtl[i] > 0) - { - keymap->direction[i] = PANGO_DIRECTION_RTL; - have_rtl = TRUE; - } - else - { - keymap->direction[i] = PANGO_DIRECTION_LTR; - have_ltr = TRUE; - } - } - - if (have_rtl && have_ltr) - keymap->bidi = TRUE; -} - -GdkKeymap * -_gdk_wayland_keymap_new (GdkDisplay *display) -{ - GdkWaylandKeymap *keymap; - struct xkb_context *context; - struct xkb_rule_names names; - - keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL); - GDK_KEYMAP (keymap)->display = display; - - context = xkb_context_new (0); - - names.rules = "evdev"; - names.model = "pc105"; - names.layout = "us"; - names.variant = ""; - names.options = ""; - keymap->xkb_keymap = xkb_keymap_new_from_names (context, &names, 0); - keymap->xkb_state = xkb_state_new (keymap->xkb_keymap); - xkb_context_unref (context); - - update_direction (keymap); - - return GDK_KEYMAP (keymap); -} - -static void -print_modifiers (GdkDisplay *display, - struct xkb_keymap *keymap) -{ -#ifdef G_ENABLE_DEBUG - int i, j; - uint32_t real; - struct xkb_state *state; - GString *str; - - if (!GDK_DISPLAY_DEBUG_CHECK (display, INPUT)) - return; - - str = g_string_new (""); - - g_string_append (str, "modifiers:\n"); - for (i = 0; i < xkb_keymap_num_mods (keymap); i++) - g_string_append_printf (str, "%s ", xkb_keymap_mod_get_name (keymap, i)); - g_string_append (str, "\n\n"); - - g_string_append (str, "modifier mapping\n"); - state = xkb_state_new (keymap); - for (i = 0; i < 8; i++) - { - gboolean need_arrow = TRUE; - g_string_append_printf (str, "%s ", xkb_keymap_mod_get_name (keymap, i)); - for (j = 8; j < xkb_keymap_num_mods (keymap); j++) - { - xkb_state_update_mask (state, 1 << j, 0, 0, 0, 0, 0); - real = xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE); - if (real & (1 << i)) - { - if (need_arrow) - { - g_string_append (str, "-> "); - need_arrow = FALSE; - } - g_string_append_printf (str, "%s ", xkb_keymap_mod_get_name (keymap, j)); - } - } - } - - gdk_debug_message ("%s", str->str); - - g_string_free (str, TRUE); - - xkb_state_unref (state); -#endif -} - -void -_gdk_wayland_keymap_update_from_fd (GdkKeymap *keymap, - uint32_t format, - uint32_t fd, - uint32_t size) -{ - GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap); - struct xkb_context *context; - struct xkb_keymap *xkb_keymap; - char *map_str; - - context = xkb_context_new (0); - - map_str = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map_str == MAP_FAILED) - { - close(fd); - return; - } - - GDK_DISPLAY_DEBUG (keymap->display, INPUT, "keymap:\n%s", map_str); - - xkb_keymap = xkb_keymap_new_from_string (context, map_str, format, 0); - munmap (map_str, size); - close (fd); - - if (!xkb_keymap) - { - g_warning ("Got invalid keymap from compositor, keeping previous/default one"); - xkb_context_unref (context); - return; - } - - print_modifiers (keymap->display, xkb_keymap); - - xkb_keymap_unref (keymap_wayland->xkb_keymap); - keymap_wayland->xkb_keymap = xkb_keymap; - - xkb_state_unref (keymap_wayland->xkb_state); - keymap_wayland->xkb_state = xkb_state_new (keymap_wayland->xkb_keymap); - - xkb_context_unref (context); - - update_direction (keymap_wayland); -} - -struct xkb_keymap * -_gdk_wayland_keymap_get_xkb_keymap (GdkKeymap *keymap) -{ - return GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; -} - -struct xkb_state * -_gdk_wayland_keymap_get_xkb_state (GdkKeymap *keymap) -{ - return GDK_WAYLAND_KEYMAP (keymap)->xkb_state; -} - -gboolean -_gdk_wayland_keymap_key_is_modifier (GdkKeymap *keymap, - guint keycode) -{ - struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; - struct xkb_state *xkb_state; - gboolean is_modifier; - - is_modifier = FALSE; - - xkb_state = xkb_state_new (xkb_keymap); - - if (xkb_state_update_key (xkb_state, keycode, XKB_KEY_DOWN) & XKB_STATE_MODS_EFFECTIVE) - is_modifier = TRUE; - - xkb_state_unref (xkb_state); - - return is_modifier; -} diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index 48317bdb88..e5ca9ae02f 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -13,7 +13,7 @@ gdk_wayland_sources = files([ 'gdkdrop-wayland.c', 'gdkeventsource.c', 'gdkglcontext-wayland.c', - 'gdkkeys-wayland.c', + 'gdkkeymap-wayland.c', 'gdkmonitor-wayland.c', 'gdkprimary-wayland.c', 'gdkseat-wayland.c', -- cgit v1.2.1