wayland/xdg-toplevel-drag: Add the protocol implementation
- For already mapped windows, the window drag session is started straight away; - For about-to-be-mapped window (ie: undocking window use case): - The "shown" signal for the dragged window triggers the actual MetaWindowDrag once it's mapped. - MetaWindowWayland now handles the case of toplevel-drag and position the window about to be mapped according to the toplevel-drag parameters. - While attached to a toplevel-drag, the window state is updated to: - Actor's "reactive" state is set to false, which in practice excludes it from the possible drag target list; - WindowActor's "tied to drag" state is set to true, which results in initial placement constraints to be skipped, so newly created (detached) windows can be freely dragged around. - Toplevel drag session ends upon: - dnd drop and cancellation. - xdg_toplevel_drag_v1 object destruction (client-side). - data source destruction. Status: - [x] Basic window drag triggering - [x] Exclude the dragged window from event targets - [x] Event forwarding (window drag vs wayland grabs) - [x] Offset calc relative to toplevel geometry - [x] Attach already mapped windows - [x] Properly support not-yet-mapped windows - [ ] Disable visibility change animations - [ ] Dnd events stream adaptations Signed-off-by: Nick Diego Yamane <nickdiego@igalia.com> Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4107>
This commit is contained in:
parent
1cb46f203c
commit
66cfbf03c9
@ -697,6 +697,8 @@ if have_wayland
|
|||||||
'wayland/meta-wayland-tablet-tool.h',
|
'wayland/meta-wayland-tablet-tool.h',
|
||||||
'wayland/meta-wayland-text-input.c',
|
'wayland/meta-wayland-text-input.c',
|
||||||
'wayland/meta-wayland-text-input.h',
|
'wayland/meta-wayland-text-input.h',
|
||||||
|
'wayland/meta-wayland-toplevel-drag.c',
|
||||||
|
'wayland/meta-wayland-toplevel-drag.h',
|
||||||
'wayland/meta-wayland-touch.c',
|
'wayland/meta-wayland-touch.c',
|
||||||
'wayland/meta-wayland-touch.h',
|
'wayland/meta-wayland-touch.h',
|
||||||
'wayland/meta-wayland-transaction.c',
|
'wayland/meta-wayland-transaction.c',
|
||||||
@ -1118,6 +1120,7 @@ if have_wayland
|
|||||||
['xdg-foreign', 'unstable', 'v2', ],
|
['xdg-foreign', 'unstable', 'v2', ],
|
||||||
['xdg-output', 'unstable', 'v1', ],
|
['xdg-output', 'unstable', 'v1', ],
|
||||||
['xdg-shell', 'stable', ],
|
['xdg-shell', 'stable', ],
|
||||||
|
['xdg-toplevel-drag', 'staging', 'v1'],
|
||||||
['xwayland-keyboard-grab', 'unstable', 'v1', ],
|
['xwayland-keyboard-grab', 'unstable', 'v1', ],
|
||||||
['linux-drm-syncobj-v1', 'private', ],
|
['linux-drm-syncobj-v1', 'private', ],
|
||||||
['color-management-v1', 'private', ],
|
['color-management-v1', 'private', ],
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "wayland/meta-wayland-pointer.h"
|
#include "wayland/meta-wayland-pointer.h"
|
||||||
#include "wayland/meta-wayland-private.h"
|
#include "wayland/meta-wayland-private.h"
|
||||||
#include "wayland/meta-wayland-seat.h"
|
#include "wayland/meta-wayland-seat.h"
|
||||||
|
#include "wayland/meta-wayland-toplevel-drag.h"
|
||||||
|
|
||||||
#define ROOTWINDOW_DROP_MIME "application/x-rootwindow-drop"
|
#define ROOTWINDOW_DROP_MIME "application/x-rootwindow-drop"
|
||||||
|
|
||||||
@ -343,6 +344,12 @@ meta_wayland_drag_grab_get_origin (MetaWaylandDragGrab *drag_grab)
|
|||||||
return drag_grab->drag_origin;
|
return drag_grab->drag_origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetaWaylandDataSource *
|
||||||
|
meta_wayland_drag_grab_get_data_source (MetaWaylandDragGrab *drag_grab)
|
||||||
|
{
|
||||||
|
return drag_grab->drag_data_source;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
data_source_update_user_dnd_action (MetaWaylandDataSource *source,
|
data_source_update_user_dnd_action (MetaWaylandDataSource *source,
|
||||||
ClutterModifierType modifiers)
|
ClutterModifierType modifiers)
|
||||||
|
@ -98,3 +98,6 @@ ClutterInputDevice * meta_wayland_drag_grab_get_device (MetaWaylandDragGrab *
|
|||||||
ClutterEventSequence **sequence);
|
ClutterEventSequence **sequence);
|
||||||
|
|
||||||
MetaWaylandSurface * meta_wayland_drag_grab_get_origin (MetaWaylandDragGrab *drag_grab);
|
MetaWaylandSurface * meta_wayland_drag_grab_get_origin (MetaWaylandDragGrab *drag_grab);
|
||||||
|
|
||||||
|
MetaWaylandDataSource *
|
||||||
|
meta_wayland_drag_grab_get_data_source (MetaWaylandDragGrab *drag_grab);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "wayland/meta-wayland-data-source.h"
|
#include "wayland/meta-wayland-data-source.h"
|
||||||
#include "wayland/meta-wayland-private.h"
|
#include "wayland/meta-wayland-private.h"
|
||||||
|
#include "wayland/meta-wayland-toplevel-drag.h"
|
||||||
|
|
||||||
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
|
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
|
||||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
|
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
|
||||||
@ -44,6 +45,7 @@ typedef struct _MetaWaylandDataSourcePrivate
|
|||||||
enum wl_data_device_manager_dnd_action user_dnd_action;
|
enum wl_data_device_manager_dnd_action user_dnd_action;
|
||||||
enum wl_data_device_manager_dnd_action current_dnd_action;
|
enum wl_data_device_manager_dnd_action current_dnd_action;
|
||||||
MetaWaylandSeat *seat;
|
MetaWaylandSeat *seat;
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag;
|
||||||
guint actions_set : 1;
|
guint actions_set : 1;
|
||||||
guint in_ask : 1;
|
guint in_ask : 1;
|
||||||
guint drop_performed : 1;
|
guint drop_performed : 1;
|
||||||
@ -614,3 +616,22 @@ meta_wayland_data_source_get_compositor (MetaWaylandDataSource *source)
|
|||||||
|
|
||||||
return priv->compositor;
|
return priv->compositor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_data_source_set_toplevel_drag (MetaWaylandDataSource *source,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag)
|
||||||
|
{
|
||||||
|
MetaWaylandDataSourcePrivate *priv =
|
||||||
|
meta_wayland_data_source_get_instance_private (source);
|
||||||
|
|
||||||
|
priv->toplevel_drag = toplevel_drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaWaylandToplevelDrag *
|
||||||
|
meta_wayland_data_source_get_toplevel_drag (MetaWaylandDataSource *source)
|
||||||
|
{
|
||||||
|
MetaWaylandDataSourcePrivate *priv =
|
||||||
|
meta_wayland_data_source_get_instance_private (source);
|
||||||
|
|
||||||
|
return priv->toplevel_drag;
|
||||||
|
}
|
||||||
|
@ -110,3 +110,10 @@ gboolean meta_wayland_data_source_get_drop_performed (MetaWaylandDataSource *sou
|
|||||||
|
|
||||||
void meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source);
|
void meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source);
|
||||||
void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
|
void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_data_source_set_toplevel_drag (MetaWaylandDataSource *source,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag);
|
||||||
|
|
||||||
|
MetaWaylandToplevelDrag *
|
||||||
|
meta_wayland_data_source_get_toplevel_drag (MetaWaylandDataSource *source);
|
||||||
|
435
src/wayland/meta-wayland-toplevel-drag.c
Normal file
435
src/wayland/meta-wayland-toplevel-drag.c
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Igalia, S.L.
|
||||||
|
*
|
||||||
|
* Author: Nick Yamane <nickdiego@igalia.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "clutter-mutter.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "meta-wayland-toplevel-drag.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "compositor/compositor-private.h"
|
||||||
|
#include "compositor/meta-window-drag.h"
|
||||||
|
#include "core/window-private.h"
|
||||||
|
#include "meta/meta-debug.h"
|
||||||
|
#include "meta/meta-enums.h"
|
||||||
|
#include "meta/meta-wayland-surface.h"
|
||||||
|
#include "meta/types.h"
|
||||||
|
#include "meta/window.h"
|
||||||
|
#include "wayland/meta-wayland-data-device.h"
|
||||||
|
#include "wayland/meta-wayland-data-source.h"
|
||||||
|
#include "wayland/meta-wayland-private.h"
|
||||||
|
#include "wayland/meta-wayland-seat.h"
|
||||||
|
#include "wayland/meta-wayland-surface-private.h"
|
||||||
|
#include "wayland/meta-wayland-types.h"
|
||||||
|
#include "wayland/meta-wayland-versions.h"
|
||||||
|
#include "wayland/meta-wayland-xdg-shell.h"
|
||||||
|
|
||||||
|
#include "xdg-toplevel-drag-v1-server-protocol.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
xdg_toplevel_drag_destructor (struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag = wl_resource_get_user_data (resource);
|
||||||
|
g_assert (toplevel_drag);
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "Destroying xdg_toplevel_drag#%u",
|
||||||
|
wl_resource_get_id (resource));
|
||||||
|
|
||||||
|
meta_wayland_toplevel_drag_end (toplevel_drag);
|
||||||
|
g_free (toplevel_drag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_dragged_window_unmanaging (MetaWindow *window,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "Dragged window destroyed.");
|
||||||
|
g_clear_signal_handler (&toplevel_drag->window_unmanaging_handler_id, window);
|
||||||
|
g_clear_signal_handler (&toplevel_drag->window_shown_handler_id, window);
|
||||||
|
toplevel_drag->dragged_surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_window_drag_ended (MetaWindowDrag *window_drag,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "Window drag ended.");
|
||||||
|
g_clear_signal_handler (&toplevel_drag->drag_ended_handler_id, window_drag);
|
||||||
|
toplevel_drag->window_drag = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_data_source_destroyed (MetaWaylandDataSource *data_source,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag)
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WAYLAND,
|
||||||
|
"Data source destroyed before xdg_toplevel_drag#%d",
|
||||||
|
wl_resource_get_id (toplevel_drag->resource));
|
||||||
|
|
||||||
|
g_clear_signal_handler (&toplevel_drag->source_destroyed_handler_id,
|
||||||
|
data_source);
|
||||||
|
meta_wayland_toplevel_drag_end (toplevel_drag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_window_geometry_origin (MetaWaylandSurface *dragged_surface,
|
||||||
|
int *x_offset,
|
||||||
|
int *y_offset)
|
||||||
|
{
|
||||||
|
MtkRectangle toplevel_geometry;
|
||||||
|
toplevel_geometry = meta_wayland_xdg_surface_get_window_geometry (
|
||||||
|
META_WAYLAND_XDG_SURFACE (dragged_surface->role));
|
||||||
|
|
||||||
|
if (x_offset)
|
||||||
|
*x_offset = *x_offset + toplevel_geometry.x;
|
||||||
|
if (y_offset)
|
||||||
|
*y_offset = *y_offset + toplevel_geometry.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xdg_toplevel_drag_destroy (struct wl_client *client,
|
||||||
|
struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
wl_resource_destroy (resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaWaylandSurface *
|
||||||
|
surface_from_xdg_toplevel_resource (struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
MetaWaylandSurfaceRole *surface_role = wl_resource_get_user_data (resource);
|
||||||
|
|
||||||
|
if (!META_IS_WAYLAND_SURFACE_ROLE (surface_role))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return meta_wayland_surface_role_get_surface (surface_role);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
start_window_drag (MetaWindow *dragged_window,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag,
|
||||||
|
graphene_point_t *offset_hint)
|
||||||
|
{
|
||||||
|
MetaWaylandSeat *seat;
|
||||||
|
MetaWaylandDragGrab *drag_grab;
|
||||||
|
MetaSurfaceActor *surface_actor;
|
||||||
|
MetaContext *context;
|
||||||
|
MetaBackend *backend;
|
||||||
|
ClutterInputDevice *device;
|
||||||
|
ClutterEventSequence *sequence;
|
||||||
|
ClutterActor *stage, *grab_actor;
|
||||||
|
MetaCompositor *compositor;
|
||||||
|
uint32_t timestamp;
|
||||||
|
gboolean started;
|
||||||
|
|
||||||
|
g_assert (toplevel_drag);
|
||||||
|
g_assert (toplevel_drag->data_source);
|
||||||
|
g_assert (toplevel_drag->dragged_surface);
|
||||||
|
|
||||||
|
seat = meta_wayland_data_source_get_seat (toplevel_drag->data_source);
|
||||||
|
if (!seat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
drag_grab = meta_wayland_data_device_get_current_grab (&seat->data_device);
|
||||||
|
if (!drag_grab ||
|
||||||
|
toplevel_drag->data_source != meta_wayland_drag_grab_get_data_source (drag_grab))
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "No drag grab found, earlying out.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable events on the dragged surface, so drag enter and leave events
|
||||||
|
* can be detected for other surfaces. */
|
||||||
|
surface_actor = meta_wayland_surface_get_actor (toplevel_drag->dragged_surface);
|
||||||
|
clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), FALSE);
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "Starting window drag. window=%s offset=(%.0f, %.0f)",
|
||||||
|
dragged_window->desc,
|
||||||
|
(offset_hint ? offset_hint->x : -1),
|
||||||
|
(offset_hint ? offset_hint->y : -1));
|
||||||
|
|
||||||
|
device = meta_wayland_drag_grab_get_device (drag_grab, &sequence);
|
||||||
|
timestamp = meta_display_get_current_time_roundtrip (dragged_window->display);
|
||||||
|
|
||||||
|
/* Re-use the current wayland input's grab actor for the newly started
|
||||||
|
* window drag session. */
|
||||||
|
context = meta_display_get_context (dragged_window->display);
|
||||||
|
backend = meta_context_get_backend (context);
|
||||||
|
stage = meta_backend_get_stage (backend);
|
||||||
|
grab_actor = clutter_stage_get_grab_actor (CLUTTER_STAGE (stage));
|
||||||
|
|
||||||
|
compositor = dragged_window->display->compositor;
|
||||||
|
started = meta_compositor_drag_window (compositor, dragged_window,
|
||||||
|
META_GRAB_OP_MOVING_UNCONSTRAINED, device,
|
||||||
|
sequence, timestamp, offset_hint, grab_actor);
|
||||||
|
if (!started)
|
||||||
|
return;
|
||||||
|
|
||||||
|
toplevel_drag->window_drag = meta_compositor_get_current_window_drag (compositor);
|
||||||
|
toplevel_drag->drag_ended_handler_id =
|
||||||
|
g_signal_connect (toplevel_drag->window_drag,
|
||||||
|
"ended",
|
||||||
|
G_CALLBACK (on_window_drag_ended),
|
||||||
|
toplevel_drag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_dragged_window_shown (MetaWindow *window,
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag)
|
||||||
|
{
|
||||||
|
g_assert (window->mapped);
|
||||||
|
g_clear_signal_handler (&toplevel_drag->window_shown_handler_id, window);
|
||||||
|
if (toplevel_drag->data_source && toplevel_drag->dragged_surface)
|
||||||
|
start_window_drag (window, toplevel_drag, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xdg_toplevel_drag_attach (struct wl_client *client,
|
||||||
|
struct wl_resource *resource,
|
||||||
|
struct wl_resource *toplevel,
|
||||||
|
int32_t x_offset,
|
||||||
|
int32_t y_offset)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *dragged_surface;
|
||||||
|
MetaWindow *dragged_window;
|
||||||
|
float screen_x, screen_y;
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag = wl_resource_get_user_data (resource);
|
||||||
|
|
||||||
|
/* Toplevel drag becomes inert if the associated data source is destroyed */
|
||||||
|
if (!toplevel_drag->data_source)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dragged_surface = surface_from_xdg_toplevel_resource (toplevel);
|
||||||
|
dragged_window = meta_wayland_surface_get_window (dragged_surface);
|
||||||
|
g_return_if_fail (dragged_window != NULL);
|
||||||
|
|
||||||
|
if (toplevel_drag->dragged_surface != NULL)
|
||||||
|
{
|
||||||
|
wl_resource_post_error (
|
||||||
|
resource, XDG_TOPLEVEL_DRAG_V1_ERROR_TOPLEVEL_ATTACHED,
|
||||||
|
"toplevel drag already has a surface attached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_WAYLAND,
|
||||||
|
"Attaching xdg_toplevel#%u to xdg_toplevel_drag#%u "
|
||||||
|
"data_source#%p window=%s drag_offset=(%d, %d)",
|
||||||
|
wl_resource_get_id (toplevel), wl_resource_get_id (resource),
|
||||||
|
toplevel_drag->data_source, dragged_window->desc, x_offset, y_offset);
|
||||||
|
|
||||||
|
toplevel_drag->dragged_surface = dragged_surface;
|
||||||
|
toplevel_drag->x_offset = x_offset;
|
||||||
|
toplevel_drag->y_offset = y_offset;
|
||||||
|
toplevel_drag->window_unmanaging_handler_id =
|
||||||
|
g_signal_connect (dragged_window,
|
||||||
|
"unmanaging",
|
||||||
|
G_CALLBACK (on_dragged_window_unmanaging),
|
||||||
|
toplevel_drag);
|
||||||
|
|
||||||
|
if (dragged_window->mapped)
|
||||||
|
{
|
||||||
|
/* {x,y}_offset values are relative to the toplevel geometry. */
|
||||||
|
add_window_geometry_origin (dragged_surface, &x_offset, &y_offset);
|
||||||
|
meta_wayland_surface_get_absolute_coordinates (dragged_surface,
|
||||||
|
(float) x_offset,
|
||||||
|
(float) y_offset,
|
||||||
|
&screen_x, &screen_y);
|
||||||
|
start_window_drag (dragged_window, toplevel_drag,
|
||||||
|
&GRAPHENE_POINT_INIT (screen_x, screen_y));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "Window not mapped yet, monitoring.");
|
||||||
|
toplevel_drag->window_shown_handler_id =
|
||||||
|
g_signal_connect (dragged_window,
|
||||||
|
"shown",
|
||||||
|
G_CALLBACK (on_dragged_window_shown),
|
||||||
|
toplevel_drag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xdg_toplevel_drag_v1_interface meta_wayland_toplevel_drag_interface = {
|
||||||
|
.destroy = xdg_toplevel_drag_destroy,
|
||||||
|
.attach = xdg_toplevel_drag_attach,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
xdg_toplevel_drag_manager_destroy (struct wl_client *client,
|
||||||
|
struct wl_resource *resource)
|
||||||
|
{
|
||||||
|
wl_resource_destroy (resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xdg_toplevel_drag_manager_get_toplevel_drag (struct wl_client *client,
|
||||||
|
struct wl_resource *resource,
|
||||||
|
uint32_t toplevel_drag_id,
|
||||||
|
struct wl_resource *data_source_resource)
|
||||||
|
{
|
||||||
|
MetaWaylandDataSource *data_source;
|
||||||
|
MetaWaylandToplevelDrag *toplevel_drag;
|
||||||
|
struct wl_resource *toplevel_drag_resource;
|
||||||
|
|
||||||
|
data_source = wl_resource_get_user_data (data_source_resource);
|
||||||
|
toplevel_drag = meta_wayland_data_source_get_toplevel_drag (data_source);
|
||||||
|
|
||||||
|
if (toplevel_drag)
|
||||||
|
{
|
||||||
|
wl_resource_post_error (
|
||||||
|
resource, XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_INVALID_SOURCE,
|
||||||
|
"toplevel drag resource already exists on data source");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toplevel_drag_resource = wl_resource_create (client,
|
||||||
|
&xdg_toplevel_drag_v1_interface,
|
||||||
|
wl_resource_get_version (resource),
|
||||||
|
toplevel_drag_id);
|
||||||
|
|
||||||
|
toplevel_drag = g_new0 (MetaWaylandToplevelDrag, 1);
|
||||||
|
toplevel_drag->resource = toplevel_drag_resource;
|
||||||
|
toplevel_drag->data_source = data_source;
|
||||||
|
toplevel_drag->source_destroyed_handler_id =
|
||||||
|
g_signal_connect (data_source,
|
||||||
|
"destroy",
|
||||||
|
G_CALLBACK (on_data_source_destroyed),
|
||||||
|
toplevel_drag);
|
||||||
|
meta_wayland_data_source_set_toplevel_drag (data_source,
|
||||||
|
toplevel_drag);
|
||||||
|
|
||||||
|
wl_resource_set_implementation (toplevel_drag_resource,
|
||||||
|
&meta_wayland_toplevel_drag_interface,
|
||||||
|
toplevel_drag,
|
||||||
|
xdg_toplevel_drag_destructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xdg_toplevel_drag_manager_v1_interface meta_wayland_toplevel_drag_manager_interface = {
|
||||||
|
.destroy = xdg_toplevel_drag_manager_destroy,
|
||||||
|
.get_xdg_toplevel_drag = xdg_toplevel_drag_manager_get_toplevel_drag,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
xdg_toplevel_drag_bind (struct wl_client *client,
|
||||||
|
void *data,
|
||||||
|
uint32_t version,
|
||||||
|
uint32_t id)
|
||||||
|
{
|
||||||
|
struct wl_resource *resource;
|
||||||
|
|
||||||
|
resource = wl_resource_create (client,
|
||||||
|
&xdg_toplevel_drag_manager_v1_interface,
|
||||||
|
version,
|
||||||
|
id);
|
||||||
|
wl_resource_set_implementation (resource,
|
||||||
|
&meta_wayland_toplevel_drag_manager_interface,
|
||||||
|
data,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_init_toplevel_drag (MetaWaylandCompositor *compositor)
|
||||||
|
{
|
||||||
|
if (wl_global_create (compositor->wayland_display,
|
||||||
|
&xdg_toplevel_drag_manager_v1_interface,
|
||||||
|
META_XDG_TOPLEVEL_DRAG_VERSION,
|
||||||
|
compositor,
|
||||||
|
xdg_toplevel_drag_bind) == NULL)
|
||||||
|
g_error ("Failed to register a global xdg_toplevel_drag object");
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_toplevel_drag_calc_origin_for_dragged_window (MetaWaylandToplevelDrag *toplevel_drag,
|
||||||
|
MtkRectangle *bounds_out)
|
||||||
|
{
|
||||||
|
MetaWaylandSeat *seat;
|
||||||
|
MetaWaylandDragGrab *drag_grab;
|
||||||
|
ClutterInputDevice *device;
|
||||||
|
ClutterEventSequence *sequence;
|
||||||
|
graphene_point_t coords;
|
||||||
|
|
||||||
|
g_assert (toplevel_drag);
|
||||||
|
g_assert (bounds_out);
|
||||||
|
|
||||||
|
seat = meta_wayland_data_source_get_seat (toplevel_drag->data_source);
|
||||||
|
if (!seat)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
drag_grab = meta_wayland_data_device_get_current_grab (&seat->data_device);
|
||||||
|
if (!drag_grab)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
device = meta_wayland_drag_grab_get_device (drag_grab, &sequence);
|
||||||
|
clutter_seat_query_state (clutter_input_device_get_seat (device),
|
||||||
|
device, sequence, &coords, NULL);
|
||||||
|
|
||||||
|
meta_topic (META_DEBUG_WAYLAND,
|
||||||
|
"Calculated position for the dragged window. "
|
||||||
|
"offset=(%d, %d) new_origin=(%.0f, %.0f)",
|
||||||
|
toplevel_drag->x_offset, toplevel_drag->y_offset, coords.x, coords.y);
|
||||||
|
bounds_out->x = (int) coords.x - toplevel_drag->x_offset;
|
||||||
|
bounds_out->y = (int) coords.y - toplevel_drag->y_offset;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_toplevel_drag_end (MetaWaylandToplevelDrag *toplevel_drag)
|
||||||
|
{
|
||||||
|
MetaWindow *window;
|
||||||
|
MetaWindowActor *window_actor;
|
||||||
|
MetaSurfaceActor *surface_actor;
|
||||||
|
|
||||||
|
g_return_if_fail (toplevel_drag != NULL);
|
||||||
|
meta_topic (META_DEBUG_WAYLAND, "Ending toplevel drag.");
|
||||||
|
|
||||||
|
if (toplevel_drag->window_drag)
|
||||||
|
{
|
||||||
|
window = meta_window_drag_get_window (toplevel_drag->window_drag);
|
||||||
|
g_clear_signal_handler (&toplevel_drag->drag_ended_handler_id,
|
||||||
|
toplevel_drag->window_drag);
|
||||||
|
meta_window_drag_end (toplevel_drag->window_drag);
|
||||||
|
|
||||||
|
window_actor = meta_window_actor_from_window (window);
|
||||||
|
if (window_actor)
|
||||||
|
meta_window_actor_set_tied_to_drag (window_actor, FALSE);
|
||||||
|
toplevel_drag->window_drag = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toplevel_drag->dragged_surface)
|
||||||
|
{
|
||||||
|
surface_actor = meta_wayland_surface_get_actor (toplevel_drag->dragged_surface);
|
||||||
|
if (surface_actor)
|
||||||
|
clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), TRUE);
|
||||||
|
|
||||||
|
window = meta_wayland_surface_get_window (toplevel_drag->dragged_surface);
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
g_clear_signal_handler (&toplevel_drag->window_unmanaging_handler_id, window);
|
||||||
|
g_clear_signal_handler (&toplevel_drag->window_shown_handler_id, window);
|
||||||
|
}
|
||||||
|
toplevel_drag->dragged_surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toplevel_drag->data_source)
|
||||||
|
{
|
||||||
|
g_clear_signal_handler (&toplevel_drag->source_destroyed_handler_id,
|
||||||
|
toplevel_drag->data_source);
|
||||||
|
meta_wayland_data_source_set_toplevel_drag (toplevel_drag->data_source, NULL);
|
||||||
|
toplevel_drag->data_source = NULL;
|
||||||
|
}
|
||||||
|
}
|
54
src/wayland/meta-wayland-toplevel-drag.h
Normal file
54
src/wayland/meta-wayland-toplevel-drag.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Igalia, S.L.
|
||||||
|
*
|
||||||
|
* Author: Nick Yamane <nickdiego@igalia.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "compositor/meta-window-drag.h"
|
||||||
|
#include "mtk/mtk.h"
|
||||||
|
#include "wayland/meta-wayland-types.h"
|
||||||
|
#include "wayland/meta-wayland-data-source.h"
|
||||||
|
|
||||||
|
struct _MetaWaylandToplevelDrag
|
||||||
|
{
|
||||||
|
struct wl_resource *resource;
|
||||||
|
|
||||||
|
MetaWaylandDataSource *data_source;
|
||||||
|
MetaWaylandSurface *dragged_surface;
|
||||||
|
int32_t x_offset, y_offset;
|
||||||
|
|
||||||
|
MetaWindowDrag *window_drag;
|
||||||
|
gulong window_unmanaging_handler_id;
|
||||||
|
gulong window_shown_handler_id;
|
||||||
|
gulong drag_ended_handler_id;
|
||||||
|
gulong source_destroyed_handler_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_init_toplevel_drag (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_toplevel_drag_calc_origin_for_dragged_window (MetaWaylandToplevelDrag *drag,
|
||||||
|
MtkRectangle *bounds_out);
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_wayland_toplevel_drag_end (MetaWaylandToplevelDrag *drag);
|
@ -75,3 +75,5 @@ typedef struct _MetaWaylandClient MetaWaylandClient;
|
|||||||
typedef struct _MetaWaylandDrmLeaseManager MetaWaylandDrmLeaseManager;
|
typedef struct _MetaWaylandDrmLeaseManager MetaWaylandDrmLeaseManager;
|
||||||
|
|
||||||
typedef struct _MetaWaylandXdgSessionManager MetaWaylandXdgSessionManager;
|
typedef struct _MetaWaylandXdgSessionManager MetaWaylandXdgSessionManager;
|
||||||
|
|
||||||
|
typedef struct _MetaWaylandToplevelDrag MetaWaylandToplevelDrag;
|
||||||
|
@ -62,3 +62,4 @@
|
|||||||
#define META_WP_DRM_LEASE_DEVICE_V1_VERSION 1
|
#define META_WP_DRM_LEASE_DEVICE_V1_VERSION 1
|
||||||
#define META_XDG_SESSION_MANAGER_V1_VERSION 1
|
#define META_XDG_SESSION_MANAGER_V1_VERSION 1
|
||||||
#define META_WP_SYSTEM_BELL_V1_VERSION 1
|
#define META_WP_SYSTEM_BELL_V1_VERSION 1
|
||||||
|
#define META_XDG_TOPLEVEL_DRAG_VERSION 1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user