wayland/xdg-toplevel-drag: Plumb xdg-toplevel-drag to core/compositor

- Event stream adaptations. When there is a toplevel-drag in place, do:
  - Send wl_data_source.dnd_finished and end the session successfully
  - Send wl_data_source.cancelled and end the MetaWindowDrag when ESC key
    is pressed.
- Modify MetaWaylandDataDevice such that, when a toplevel-drag is
  running, it does:
  - Propagate motion events, so that they can be processed further by
    MetaWindowDrag.
  - Ends the associated MetaWindowDrag upon release event.
- Hook up the window mapping process in MetaWindowWayand, such that:
  - the initial position of the window attached to the ongoing
    toplevel-drag instance can be calculated and set.
  - the appropriate gravity and flags can be set when calling MetaWindow's
    meta_window_move_resize_internal, which allows it for example to be
    moved freely (unconstrained) as per current dragging cursor.

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
- [x] Disable visibility change animations
- [x] 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:
Nick Diego Yamane 2024-11-21 11:50:58 -03:00
parent 66cfbf03c9
commit 0111f0de14
3 changed files with 81 additions and 2 deletions

View File

@ -36,14 +36,20 @@
#include "backends/meta-dnd-private.h"
#include "compositor/meta-dnd-actor-private.h"
#include "compositor/meta-surface-actor.h"
#include "compositor/meta-window-drag.h"
#include "core/meta-selection-private.h"
#include "meta/meta-debug.h"
#include "meta/meta-selection-source-memory.h"
#include "meta/meta-wayland-surface.h"
#include "wayland/meta-selection-source-wayland-private.h"
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-dnd-surface.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-seat.h"
#include "wayland/meta-wayland-toplevel-drag.h"
#include "wayland/meta-wayland-types.h"
#define ROOTWINDOW_DROP_MIME "application/x-rootwindow-drop"
@ -510,6 +516,12 @@ data_device_update_position (MetaWaylandDragGrab *drag_grab,
meta_wayland_surface_set_main_monitor (drag_grab->drag_surface, monitor);
}
static gboolean
is_dragging_window (MetaWaylandSeat *seat)
{
return meta_wayland_data_device_get_toplevel_drag (&seat->data_device) != NULL;
}
static gboolean
drag_grab_motion (MetaWaylandEventHandler *handler,
const ClutterEvent *event,
@ -540,7 +552,7 @@ drag_grab_motion (MetaWaylandEventHandler *handler,
meta_dnd_wayland_on_motion_event (meta_backend_get_dnd (backend), event);
return CLUTTER_EVENT_STOP;
return !is_dragging_window (drag_grab->seat);
}
static gboolean
@ -551,6 +563,7 @@ drag_grab_release (MetaWaylandEventHandler *handler,
MetaWaylandDragGrab *drag_grab = user_data;
MetaWaylandSeat *seat = drag_grab->seat;
MetaWaylandDataSource *source = drag_grab->drag_data_source;
MetaWaylandToplevelDrag *toplevel_drag;
gboolean success;
if (drag_grab->device != clutter_event_get_device (event) ||
@ -565,12 +578,22 @@ drag_grab_release (MetaWaylandEventHandler *handler,
CLUTTER_BUTTON5_MASK)) > 1)
return CLUTTER_EVENT_STOP;
toplevel_drag = meta_wayland_data_device_get_toplevel_drag (&seat->data_device);
if (toplevel_drag)
{
meta_topic (META_DEBUG_WAYLAND, "Will end xdg_toplevel_drag#%u.",
wl_resource_get_id (toplevel_drag->resource));
meta_wayland_data_source_notify_drop_performed (source);
meta_wayland_toplevel_drag_end (toplevel_drag);
}
if (drag_grab->drag_focus && source &&
meta_wayland_data_source_has_target (source) &&
meta_wayland_data_source_get_current_action (source))
{
meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus);
meta_wayland_data_source_notify_drop_performed (source);
if (!meta_wayland_data_source_get_drop_performed (source))
meta_wayland_data_source_notify_drop_performed (source);
meta_wayland_data_source_update_in_ask (source);
success = TRUE;
@ -609,11 +632,20 @@ drag_grab_key (MetaWaylandEventHandler *handler,
const ClutterEvent *event,
gpointer user_data)
{
MetaWaylandToplevelDrag *toplevel_drag;
MetaWaylandDragGrab *drag_grab = user_data;
ClutterModifierType modifiers;
if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_Escape)
{
toplevel_drag = meta_wayland_data_device_get_toplevel_drag (&drag_grab->seat->data_device);
if (toplevel_drag)
{
meta_topic (META_DEBUG_WAYLAND, "Will cancel xdg_toplevel_drag#%u.",
wl_resource_get_id (toplevel_drag->resource));
meta_wayland_toplevel_drag_end (toplevel_drag);
}
meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device,
NULL);
unset_selection_source (&drag_grab->seat->data_device, META_SELECTION_DND);
@ -1309,3 +1341,12 @@ meta_wayland_data_device_unset_dnd_selection (MetaWaylandDataDevice *data_device
{
unset_selection_source (data_device, META_SELECTION_DND);
}
MetaWaylandToplevelDrag *
meta_wayland_data_device_get_toplevel_drag (MetaWaylandDataDevice *data_device)
{
if (!data_device->current_grab || !data_device->current_grab->drag_data_source)
return NULL;
return meta_wayland_data_source_get_toplevel_drag (data_device->current_grab->drag_data_source);
}

View File

@ -87,6 +87,9 @@ void meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data_
void meta_wayland_data_device_end_drag (MetaWaylandDataDevice *data_device);
MetaWaylandToplevelDrag *
meta_wayland_data_device_get_toplevel_drag (MetaWaylandDataDevice *data_device);
void meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
MetaWaylandSurface *surface);
MetaWaylandSurface *

View File

@ -39,6 +39,7 @@
#include "wayland/meta-wayland-actor-surface.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface-private.h"
#include "wayland/meta-wayland-toplevel-drag.h"
#include "wayland/meta-wayland-window-configuration.h"
#include "wayland/meta-wayland-xdg-shell.h"
@ -732,6 +733,21 @@ on_window_shown (MetaWindow *window)
meta_compositor_sync_updates_frozen (window->display->compositor, window);
}
static MetaWaylandToplevelDrag *
get_toplevel_drag (MetaWindow *window)
{
MetaWaylandToplevelDrag *toplevel_drag;
MetaWindowWayland *wl_window = META_WINDOW_WAYLAND (window);
MetaDisplay *display = meta_window_get_display (window);
MetaContext *context = meta_display_get_context (display);
MetaWaylandCompositor *compositor = meta_context_get_wayland_compositor (context);
toplevel_drag = meta_wayland_data_device_get_toplevel_drag (&compositor->seat->data_device);
if (!toplevel_drag || toplevel_drag->dragged_surface != wl_window->surface)
return NULL;
return toplevel_drag;
}
static void
meta_window_wayland_init (MetaWindowWayland *wl_window)
{
@ -1179,6 +1195,8 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
gboolean is_client_resize;
MetaWindowDrag *window_drag;
MtkRectangle frame_rect;
MetaWindowActor *window_actor;
MetaWaylandToplevelDrag *toplevel_drag;
/* new_geom is in the logical pixel coordinate space, but MetaWindow wants its
* rects to represent what in turn will end up on the stage, i.e. we need to
@ -1263,6 +1281,14 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
calculate_position (acked_configuration, &new_geom, &rect);
}
toplevel_drag = get_toplevel_drag (window);
if (toplevel_drag && !is_window_being_resized && !window->mapped &&
rect.width > 0 && rect.height > 0)
{
meta_wayland_toplevel_drag_calc_origin_for_dragged_window (toplevel_drag,
&rect);
}
rect.x += dx;
rect.y += dy;
@ -1295,6 +1321,15 @@ meta_window_wayland_finish_move_resize (MetaWindow *window,
gravity = meta_resize_gravity_from_grab_op (meta_window_drag_get_grab_op (window_drag));
else
gravity = META_GRAVITY_STATIC;
/* Force unconstrained move + northwest gravity when running toplevel drags */
if (toplevel_drag && surface == toplevel_drag->dragged_surface)
{
gravity = META_GRAVITY_NORTH_WEST;
window_actor = meta_window_actor_from_window (window);
meta_window_actor_set_tied_to_drag (window_actor, TRUE);
}
meta_window_move_resize_internal (window,
flags,
META_PLACE_FLAG_NONE,