From 1a5aaa63a8ffd8e2d526fb6cb8266f86fd54af84 Mon Sep 17 00:00:00 2001 From: lenemter Date: Thu, 31 Jul 2025 23:21:45 +0900 Subject: [PATCH 1/4] Allow dropping windows directly to dock --- src/DBus.vala | 2 +- src/Widgets/MultitaskingView/WindowClone.vala | 8 +-- src/WindowDragProvider.vala | 64 ++++++++++++++++++- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/DBus.vala b/src/DBus.vala index f0968224c..00fc28d6f 100644 --- a/src/DBus.vala +++ b/src/DBus.vala @@ -18,7 +18,7 @@ public class Gala.DBus { SESSION, "io.elementary.gala", NONE, (connection) => { try { - connection.register_object ("/io/elementary/gala", WindowDragProvider.get_instance ()); + connection.register_object ("/io/elementary/gala", WindowDragProvider.get_instance (wm.get_display ())); } catch (Error e) { warning (e.message); } diff --git a/src/Widgets/MultitaskingView/WindowClone.vala b/src/Widgets/MultitaskingView/WindowClone.vala index c65a8e56a..a9513dfd1 100644 --- a/src/Widgets/MultitaskingView/WindowClone.vala +++ b/src/Widgets/MultitaskingView/WindowClone.vala @@ -519,14 +519,14 @@ public class Gala.WindowClone : ActorTarget, RootTarget { } if (hovered) { - WindowDragProvider.get_instance ().notify_enter (window.get_id ()); + WindowDragProvider.get_instance (wm.get_display ()).notify_enter (window.get_id ()); } else { - WindowDragProvider.get_instance ().notify_leave (); + WindowDragProvider.get_instance (wm.get_display ()).notify_leave (); } } private void destination_motion (Clutter.Actor destination, float x, float y) { - WindowDragProvider.get_instance ().notify_motion (x, y); + WindowDragProvider.get_instance (wm.get_display ()).notify_motion (x, y); } /** @@ -557,7 +557,7 @@ public class Gala.WindowClone : ActorTarget, RootTarget { return; } else if (destination is Meta.WindowActor) { - WindowDragProvider.get_instance ().notify_dropped (); + WindowDragProvider.get_instance (display).notify_dropped (); } bool did_move = false; diff --git a/src/WindowDragProvider.vala b/src/WindowDragProvider.vala index b71a6fdc9..13c9d4beb 100644 --- a/src/WindowDragProvider.vala +++ b/src/WindowDragProvider.vala @@ -8,8 +8,8 @@ [DBus (name = "io.elementary.desktop.wm.WindowDragProvider")] public class Gala.WindowDragProvider : Object { private static GLib.Once instance; - public static WindowDragProvider get_instance () { - return instance.once (() => { return new WindowDragProvider (); }); + public static unowned WindowDragProvider get_instance (Meta.Display display) { + return instance.once (() => { return new WindowDragProvider (display); }); } public signal void enter (uint64 window_id); @@ -17,6 +17,66 @@ public class Gala.WindowDragProvider : Object { public signal void leave (); public signal void dropped (); + [DBus (visible = false)] + public Meta.Display display { private get; construct; } + + private ulong position_invalidated_id = 0; + private Meta.Window? previous_window = null; + + public WindowDragProvider (Meta.Display display) { + Object (display: display); + } + + construct { + display.grab_op_begin.connect ((grabbed_window, grab_op) => { + if (grab_op == MOVING) { + unowned var cursor_tracker = display.get_cursor_tracker (); + position_invalidated_id = cursor_tracker.position_invalidated.connect (() => { + Graphene.Point pointer; + cursor_tracker.get_pointer (out pointer, null); + + foreach (unowned var window in display.list_all_windows ()) { + if (window.window_type == DOCK) { + var buffer_rect = window.get_buffer_rect (); + #if HAS_MUTTER48 + if (buffer_rect.contains_pointf (pointer.x, pointer.y)) { + #else + if (buffer_rect.contains_rect ({ (int) pointer.x, (int) pointer.y, 0, 0})) { + #endif + if (previous_window != window) { + notify_enter (grabbed_window.get_id ()); + previous_window = window; + } else { + notify_motion ((int) pointer.x - buffer_rect.x, (int) pointer.y - buffer_rect.y); + } + + return; + } + } + } + + if (previous_window != null) { + notify_leave (); + previous_window = null; + } + }); + } + }); + + display.grab_op_end.connect ((window, grab_op) => { + if (position_invalidated_id > 0) { + unowned var cursor_tracker = display.get_cursor_tracker (); + cursor_tracker.disconnect (position_invalidated_id); + position_invalidated_id = 0; + + if (previous_window != null) { + notify_dropped (); + previous_window = null; + } + } + }); + } + internal void notify_enter (uint64 window_id) { enter (window_id); } From 447bf66e8b39117c5859e15f4936126036476a94 Mon Sep 17 00:00:00 2001 From: lenemter Date: Thu, 31 Jul 2025 23:37:52 +0900 Subject: [PATCH 2/4] Center the windows when dragging directly to dock --- src/DesktopIntegration.vala | 2 ++ src/WindowDragProvider.vala | 48 ++++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/DesktopIntegration.vala b/src/DesktopIntegration.vala index b70b44fb7..d97e7db0c 100644 --- a/src/DesktopIntegration.vala +++ b/src/DesktopIntegration.vala @@ -168,6 +168,8 @@ public class Gala.DesktopIntegration : GLib.Object { public void move_window_to_workspace (uint64 uid, int index) throws DBusError, IOError { var window = find_window_by_uid (uid); window.change_workspace_by_index (index, false); + + WindowDragProvider.get_instance (wm.get_display ()).handle_move (uid); } public void activate_workspace (int index) throws GLib.DBusError, GLib.IOError { diff --git a/src/WindowDragProvider.vala b/src/WindowDragProvider.vala index 13c9d4beb..d95f7008a 100644 --- a/src/WindowDragProvider.vala +++ b/src/WindowDragProvider.vala @@ -21,7 +21,8 @@ public class Gala.WindowDragProvider : Object { public Meta.Display display { private get; construct; } private ulong position_invalidated_id = 0; - private Meta.Window? previous_window = null; + private Meta.Window? previous_dock_window = null; + private Meta.Window? window_waiting_to_move = null; public WindowDragProvider (Meta.Display display) { Object (display: display); @@ -43,9 +44,9 @@ public class Gala.WindowDragProvider : Object { #else if (buffer_rect.contains_rect ({ (int) pointer.x, (int) pointer.y, 0, 0})) { #endif - if (previous_window != window) { + if (previous_dock_window != window) { notify_enter (grabbed_window.get_id ()); - previous_window = window; + previous_dock_window = window; } else { notify_motion ((int) pointer.x - buffer_rect.x, (int) pointer.y - buffer_rect.y); } @@ -55,23 +56,29 @@ public class Gala.WindowDragProvider : Object { } } - if (previous_window != null) { + if (previous_dock_window != null) { notify_leave (); - previous_window = null; + previous_dock_window = null; } }); } }); - display.grab_op_end.connect ((window, grab_op) => { + display.grab_op_end.connect ((grabbed_window, grab_op) => { + if (grab_op != MOVING) { + return; + } + if (position_invalidated_id > 0) { unowned var cursor_tracker = display.get_cursor_tracker (); cursor_tracker.disconnect (position_invalidated_id); position_invalidated_id = 0; - if (previous_window != null) { + if (previous_dock_window != null) { notify_dropped (); - previous_window = null; + notify_leave (); + previous_dock_window = null; + window_waiting_to_move = grabbed_window; } } }); @@ -92,4 +99,29 @@ public class Gala.WindowDragProvider : Object { internal void notify_dropped () { dropped (); } + + /** + * Handles centering the window on the workspace in case it was dragged directly to the dock. + * If we don't do that, the dragged window will sit awkwardly at the bottom of the monitor. + */ + internal void handle_move (uint64 uid) { + if (uid != window_waiting_to_move.get_id ()) { + warning ("WindowDragProvider: Windows id don't match"); + window_waiting_to_move = null; + return; + } + + var frame = window_waiting_to_move.get_frame_rect (); + var monitor_geometry = display.get_monitor_geometry (window_waiting_to_move.get_monitor ()); + + window_waiting_to_move.move_resize_frame ( + true, + monitor_geometry.x + (monitor_geometry.width - frame.width) / 2, + monitor_geometry.y + (monitor_geometry.height - frame.height) / 2, + frame.width, + frame.height + ); + + window_waiting_to_move = null; + } } From 9800db4eabeabc93c5d2a9475f2d70e2fab7a71a Mon Sep 17 00:00:00 2001 From: lenemter Date: Thu, 31 Jul 2025 23:52:30 +0900 Subject: [PATCH 3/4] Fix Fedora build --- src/WindowDragProvider.vala | 65 +++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/WindowDragProvider.vala b/src/WindowDragProvider.vala index d95f7008a..3a8a98eb0 100644 --- a/src/WindowDragProvider.vala +++ b/src/WindowDragProvider.vala @@ -30,38 +30,43 @@ public class Gala.WindowDragProvider : Object { construct { display.grab_op_begin.connect ((grabbed_window, grab_op) => { - if (grab_op == MOVING) { - unowned var cursor_tracker = display.get_cursor_tracker (); - position_invalidated_id = cursor_tracker.position_invalidated.connect (() => { - Graphene.Point pointer; - cursor_tracker.get_pointer (out pointer, null); - - foreach (unowned var window in display.list_all_windows ()) { - if (window.window_type == DOCK) { - var buffer_rect = window.get_buffer_rect (); - #if HAS_MUTTER48 - if (buffer_rect.contains_pointf (pointer.x, pointer.y)) { - #else - if (buffer_rect.contains_rect ({ (int) pointer.x, (int) pointer.y, 0, 0})) { - #endif - if (previous_dock_window != window) { - notify_enter (grabbed_window.get_id ()); - previous_dock_window = window; - } else { - notify_motion ((int) pointer.x - buffer_rect.x, (int) pointer.y - buffer_rect.y); - } - - return; + if (grab_op != MOVING) { + return; + } +#if HAS_MUTTER48 + unowned var cursor_tracker = display.get_compositor ().get_backend ().get_cursor_tracker (); +#else + unowned var cursor_tracker = display.get_cursor_tracker (); +#endif + position_invalidated_id = cursor_tracker.position_invalidated.connect ((cursor_tracker) => { + Graphene.Point pointer; + cursor_tracker.get_pointer (out pointer, null); + + foreach (unowned var window in display.list_all_windows ()) { + if (window.window_type == DOCK) { + var buffer_rect = window.get_buffer_rect (); +#if HAS_MUTTER48 + if (buffer_rect.contains_pointf (pointer.x, pointer.y)) { +#else + if (buffer_rect.contains_rect ({ (int) pointer.x, (int) pointer.y, 0, 0})) { +#endif + if (previous_dock_window != window) { + notify_enter (grabbed_window.get_id ()); + previous_dock_window = window; + } else { + notify_motion ((int) pointer.x - buffer_rect.x, (int) pointer.y - buffer_rect.y); } + + return; } } + } - if (previous_dock_window != null) { - notify_leave (); - previous_dock_window = null; - } - }); - } + if (previous_dock_window != null) { + notify_leave (); + previous_dock_window = null; + } + }); }); display.grab_op_end.connect ((grabbed_window, grab_op) => { @@ -70,7 +75,11 @@ public class Gala.WindowDragProvider : Object { } if (position_invalidated_id > 0) { +#if HAS_MUTTER48 + unowned var cursor_tracker = display.get_compositor ().get_backend ().get_cursor_tracker (); +#else unowned var cursor_tracker = display.get_cursor_tracker (); +#endif cursor_tracker.disconnect (position_invalidated_id); position_invalidated_id = 0; From 7161c048db8879cf8c3ff382e1292b374fd30a83 Mon Sep 17 00:00:00 2001 From: lenemter Date: Fri, 1 Aug 2025 00:09:10 +0900 Subject: [PATCH 4/4] Cleanup --- src/WindowDragProvider.vala | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/WindowDragProvider.vala b/src/WindowDragProvider.vala index 3a8a98eb0..7e46bef0f 100644 --- a/src/WindowDragProvider.vala +++ b/src/WindowDragProvider.vala @@ -33,6 +33,7 @@ public class Gala.WindowDragProvider : Object { if (grab_op != MOVING) { return; } + #if HAS_MUTTER48 unowned var cursor_tracker = display.get_compositor ().get_backend ().get_cursor_tracker (); #else @@ -43,22 +44,23 @@ public class Gala.WindowDragProvider : Object { cursor_tracker.get_pointer (out pointer, null); foreach (unowned var window in display.list_all_windows ()) { - if (window.window_type == DOCK) { + if (window.window_type != DOCK) { + continue; + } var buffer_rect = window.get_buffer_rect (); #if HAS_MUTTER48 - if (buffer_rect.contains_pointf (pointer.x, pointer.y)) { + if (buffer_rect.contains_pointf (pointer.x, pointer.y)) { #else - if (buffer_rect.contains_rect ({ (int) pointer.x, (int) pointer.y, 0, 0})) { + if (buffer_rect.contains_rect ({ (int) pointer.x, (int) pointer.y, 0, 0})) { #endif - if (previous_dock_window != window) { - notify_enter (grabbed_window.get_id ()); - previous_dock_window = window; - } else { - notify_motion ((int) pointer.x - buffer_rect.x, (int) pointer.y - buffer_rect.y); - } - - return; + if (previous_dock_window != window) { + notify_enter (grabbed_window.get_id ()); + previous_dock_window = window; + } else { + notify_motion ((int) pointer.x - buffer_rect.x, (int) pointer.y - buffer_rect.y); } + + return; } }