From 47c4e8346b99cd07ff9477da5259f4de3c21a719 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Thu, 6 Oct 2022 21:32:04 +0100 Subject: [PATCH] DnD: Stop using captured_event in Mutter 42 (#1468) --- lib/DragDropAction.vala | 203 ++++++++++++++++++++++++++++++++++- src/Widgets/WindowClone.vala | 4 + 2 files changed, 206 insertions(+), 1 deletion(-) diff --git a/lib/DragDropAction.vala b/lib/DragDropAction.vala index 17a53518..674d148f 100644 --- a/lib/DragDropAction.vala +++ b/lib/DragDropAction.vala @@ -103,6 +103,13 @@ namespace Gala { float last_x; float last_y; +#if HAS_MUTTER42 + Grab? grab = null; + static unowned Actor? grabbed_actor = null; + InputDevice? grabbed_device = null; + ulong on_event_id = 0; +#endif + /** * Create a new DragDropAction * @@ -141,7 +148,9 @@ namespace Gala { void release_actor (Actor actor) { if (DragDropActionType.SOURCE in drag_type) { +#if !HAS_MUTTER42 actor.button_press_event.disconnect (source_clicked); +#endif var source_list = sources.@get (drag_id); source_list.remove (actor); @@ -155,7 +164,9 @@ namespace Gala { void connect_actor (Actor actor) { if (DragDropActionType.SOURCE in drag_type) { +#if !HAS_MUTTER42 actor.button_press_event.connect (source_clicked); +#endif var source_list = sources.@get (drag_id); if (source_list == null) { @@ -182,6 +193,190 @@ namespace Gala { destination_crossed (destination, is_hovered); } +#if HAS_MUTTER42 + public override bool handle_event (Event event) { + switch (event.get_type ()) { + case EventType.BUTTON_PRESS: + if (event.get_button () != 1) { + actor_clicked (event.get_button ()); + return false; + } + + if (grabbed_actor != null) { + return false; + } + + grab_actor (actor, event.get_device ()); + clicked = true; + + float x, y; + event.get_coords (out x, out y); + + last_x = x; + last_y = y; + + return true; + + case EventType.BUTTON_RELEASE: + if (!dragging) { + float x, y, ex, ey; + event.get_coords (out ex, out ey); + actor.get_transformed_position (out x, out y); + + // release has happened within bounds of actor + if (x < ex && x + actor.width > ex && y < ey && y + actor.height > ey) { + actor_clicked (event.get_button ()); + } + + ungrab_actor (); + clicked = false; + dragging = false; + return true; + } else if (dragging) { + if (hovered != null) { + finish (); + } else { + cancel (); + } + + return true; + } + break; + + default: + break; + } + + return base.handle_event (event); + } + + void grab_actor (Actor actor, InputDevice device) { + if (grabbed_actor != null) { + critical ("Tried to grab an actor with a grab already in progress"); + } + + grab = actor.get_stage ().grab (actor); + grabbed_actor = actor; + grabbed_device = device; + on_event_id = actor.event.connect (on_event); + } + + void ungrab_actor () { + if (on_event_id == 0 || grabbed_actor == null) { + return; + } + + if (grab != null) { + grab.dismiss (); + grab = null; + } + + grabbed_device = null; + grabbed_actor.disconnect (on_event_id); + on_event_id = 0; + grabbed_actor = null; + } + + bool on_event (Clutter.Event event) { + var device = event.get_device (); + + if (grabbed_device != null && + device != grabbed_device && + device.get_device_type () != InputDeviceType.KEYBOARD_DEVICE) { + return false; + } + + switch (event.get_type ()) { + case EventType.KEY_PRESS: + if (event.get_key_symbol () == Key.Escape) { + cancel (); + } + break; + case EventType.MOTION: + float x, y; + event.get_coords (out x, out y); + + if (!dragging && clicked) { + var drag_threshold = Clutter.Settings.get_default ().dnd_drag_threshold; + if (Math.fabsf (last_x - x) > drag_threshold || Math.fabsf (last_y - y) > drag_threshold) { + handle = drag_begin (x, y); + if (handle == null) { + ungrab_actor (); + critical ("No handle has been returned by the started signal, aborting drag."); + return false; + } + + clicked = false; + dragging = true; + + ungrab_actor (); + grab_actor (handle, event.get_device ()); + + handle.reactive = false; + + var source_list = sources.@get (drag_id); + if (source_list != null) { + var dest_list = destinations[drag_id]; + foreach (var actor in source_list) { + // Do not unset reactivity on destinations + if (dest_list == null || actor in dest_list) { + continue; + } + + actor.reactive = false; + } + } + } + return true; + } else if (dragging) { + handle.x -= last_x - x; + handle.y -= last_y - y; + last_x = x; + last_y = y; + + var stage = actor.get_stage (); + var actor = stage.get_actor_at_pos (PickMode.REACTIVE, (int) x, (int) y); + DragDropAction action = null; + // if we're allowed to bubble and this actor is not a destination, check its parents + if (actor != null && (action = get_drag_drop_action (actor)) == null && allow_bubbling) { + while ((actor = actor.get_parent ()) != stage) { + if ((action = get_drag_drop_action (actor)) != null) + break; + } + } + + // didn't change, no need to do anything + if (actor == hovered) + return true; + + if (action == null) { + // apparently we left ours if we had one before + if (hovered != null) { + emit_crossed (hovered, false); + hovered = null; + } + + return true; + } + + // signal the previous one that we left it + if (hovered != null) { + emit_crossed (hovered, false); + } + + // tell the new one that it is hovered + hovered = actor; + emit_crossed (hovered, true); + + return true; + } + + break; + } + + return false; + } +#else bool source_clicked (ButtonEvent event) { if (event.button != 1) { actor_clicked (event.button); @@ -314,6 +509,7 @@ namespace Gala { return false; } +#endif /** * Looks for a DragDropAction instance if this actor has one or NULL. @@ -382,8 +578,13 @@ namespace Gala { } } - if (dragging) + if (dragging) { +#if HAS_MUTTER42 + ungrab_actor (); +#else actor.get_stage ().captured_event.disconnect (follow_move); +#endif + } dragging = false; } diff --git a/src/Widgets/WindowClone.vala b/src/Widgets/WindowClone.vala index 16374bb0..2cb48721 100644 --- a/src/Widgets/WindowClone.vala +++ b/src/Widgets/WindowClone.vala @@ -464,6 +464,10 @@ public class Gala.WindowClone : Clutter.Actor { } public override bool enter_event (Clutter.CrossingEvent event) { + if (drag_action.dragging) { + return false; + } + close_button.opacity = in_slot_animation ? 0 : 255; window_title.opacity = in_slot_animation ? 0 : 255; return false;