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/DesktopIntegration.vala b/src/DesktopIntegration.vala index a186b2928..eb8e88a54 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/Widgets/MultitaskingView/WindowClone.vala b/src/Widgets/MultitaskingView/WindowClone.vala index 44830a23a..e7c925ad6 100644 --- a/src/Widgets/MultitaskingView/WindowClone.vala +++ b/src/Widgets/MultitaskingView/WindowClone.vala @@ -506,14 +506,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); } /** @@ -549,7 +549,7 @@ public class Gala.WindowClone : ActorTarget, RootTarget { did_move = true; } } else if (destination is Meta.WindowActor) { - WindowDragProvider.get_instance ().notify_dropped (); + WindowDragProvider.get_instance (display).notify_dropped (); } if (did_move) { diff --git a/src/WindowDragProvider.vala b/src/WindowDragProvider.vala index 0ff25660a..ab11143df 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 (() => new WindowDragProvider ()); + public static WindowDragProvider get_instance (Meta.Display display) { + return instance.once (() => new WindowDragProvider (display)); } public signal void enter (uint64 window_id); @@ -17,6 +17,84 @@ 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_dock_window = null; + private Meta.Window? window_waiting_to_move = null; + + public WindowDragProvider (Meta.Display display) { + Object (display: display); + } + + construct { + display.grab_op_begin.connect ((grabbed_window, grab_op) => { + 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) { + continue; + } + 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; + } + }); + }); + + display.grab_op_end.connect ((grabbed_window, grab_op) => { + if (grab_op != MOVING) { + return; + } + + 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; + + if (previous_dock_window != null) { + notify_dropped (); + notify_leave (); + previous_dock_window = null; + window_waiting_to_move = grabbed_window; + } + } + }); + } + internal void notify_enter (uint64 window_id) { enter (window_id); } @@ -32,4 +110,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; + } }