mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 21:51:08 +00:00
c5d05fdc88
Add the environment variable NO_POINTER_VIEWPORT to force the use of buffer scale for pointer surfaces. This is a temporary workaround for https://gitlab.gnome.org/GNOME/mutter/-/issues/2633.
763 lines
23 KiB
C
763 lines
23 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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;
|
|
double scale;
|
|
guint next_image_index, next_image_delay;
|
|
gboolean retval = G_SOURCE_REMOVE;
|
|
GdkWaylandTabletData *tablet;
|
|
gboolean use_viewport;
|
|
|
|
tablet = gdk_wayland_seat_find_tablet (seat, device);
|
|
|
|
use_viewport = pointer->pointer_surface_viewport != NULL;
|
|
if (g_getenv ("NO_POINTER_VIEWPORT"))
|
|
use_viewport = FALSE;
|
|
|
|
if (pointer->cursor)
|
|
{
|
|
buffer = _gdk_wayland_cursor_get_buffer (GDK_WAYLAND_DISPLAY (seat->display),
|
|
pointer->cursor,
|
|
pointer->current_output_scale,
|
|
use_viewport,
|
|
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);
|
|
if (use_viewport)
|
|
{
|
|
wp_viewport_set_source (pointer->pointer_surface_viewport,
|
|
wl_fixed_from_int (0),
|
|
wl_fixed_from_int (0),
|
|
wl_fixed_from_double (w * scale),
|
|
wl_fixed_from_double (h * scale));
|
|
wp_viewport_set_destination (pointer->pointer_surface_viewport, w, h);
|
|
}
|
|
else if (wl_surface_get_version (pointer->pointer_surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
|
|
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;
|
|
}
|