diff --git a/src/Widgets/MultitaskingView/MonitorClone.vala b/src/Widgets/MultitaskingView/MonitorClone.vala index 0d562ae15..5bd5afc02 100644 --- a/src/Widgets/MultitaskingView/MonitorClone.vala +++ b/src/Widgets/MultitaskingView/MonitorClone.vala @@ -35,7 +35,7 @@ public class Gala.MonitorClone : ActorTarget { var windows = new WindowListModel (display, STACKING, true, monitor); - window_container = new WindowCloneContainer (wm, windows, monitor_scale); + window_container = new WindowCloneContainer (wm, windows, monitor, monitor_scale); window_container.add_constraint (new Clutter.BindConstraint (this, SIZE, 0.0f)); window_container.window_selected.connect ((w) => { window_selected (w); }); bind_property ("monitor-scale", window_container, "monitor-scale"); diff --git a/src/Widgets/MultitaskingView/WindowCloneContainer.vala b/src/Widgets/MultitaskingView/WindowCloneContainer.vala index 9b1e76a20..e1599be2d 100644 --- a/src/Widgets/MultitaskingView/WindowCloneContainer.vala +++ b/src/Widgets/MultitaskingView/WindowCloneContainer.vala @@ -18,6 +18,7 @@ public class Gala.WindowCloneContainer : ActorTarget { public WindowManager wm { get; construct; } public WindowListModel windows { get; construct; } + public int monitor { get; construct; } public float monitor_scale { get; construct set; } public bool overview_mode { get; construct; } @@ -29,8 +30,8 @@ public class Gala.WindowCloneContainer : ActorTarget { */ private unowned WindowClone? current_window = null; - public WindowCloneContainer (WindowManager wm, WindowListModel windows, float monitor_scale, bool overview_mode = false) { - Object (wm: wm, windows: windows, monitor_scale: monitor_scale, overview_mode: overview_mode); + public WindowCloneContainer (WindowManager wm, WindowListModel windows, int monitor, float monitor_scale, bool overview_mode = false) { + Object (wm: wm, windows: windows, monitor: monitor, monitor_scale: monitor_scale, overview_mode: overview_mode); } construct { @@ -140,14 +141,7 @@ public class Gala.WindowCloneContainer : ActorTarget { return (int) (seq_b - seq_a); }); - Mtk.Rectangle area = { - padding_left, - padding_top, - (int) width - padding_left - padding_right, - (int) height - padding_top - padding_bottom - }; - - foreach (var tilable in calculate_grid_placement (area, windows)) { + foreach (var tilable in calculate_window_clones_placement (windows)) { tilable.clone.take_slot (tilable.rect, !view_toggle); } } @@ -322,10 +316,95 @@ public class Gala.WindowCloneContainer : ActorTarget { Mtk.Rectangle rect; } + private bool windows_overlap (GLib.List windows) { + var checked_rects = new GLib.List (); + foreach (var tilable in windows) { + var window_rect = tilable.clone.window.get_frame_rect (); + foreach (var checked_rect in checked_rects) { + if (window_rect.overlap (checked_rect)) { + return true; + } + } + + checked_rects.append (window_rect); + } + + return false; + } + + private bool window_out_of_screen (GLib.List windows) { + foreach (var tilable in windows) { + unowned var window = tilable.clone.window; + var window_rect = window.get_frame_rect (); + var monitor_geometry = window.display.get_monitor_geometry (window.get_monitor ()); + if (window_rect.x < monitor_geometry.x || + window_rect.y < monitor_geometry.y || + window_rect.x + window_rect.width > monitor_geometry.width || + window_rect.y + window_rect.height > monitor_geometry.height + ) { + return true; + } + } + + return false; + } + + private Mtk.Rectangle get_rectangle_with_padding () { + return { + padding_left, + padding_top, + (int) width - padding_left - padding_right, + (int) height - padding_top - padding_bottom + }; + } + + private GLib.List calculate_window_clones_placement (GLib.List windows) { + if (windows_overlap (windows) || window_out_of_screen (windows)) { + return calculate_grid_placement (windows); + } else { + Mtk.Rectangle area; + if (overview_mode) { + area = { 0, 0, (int) width, (int) height }; + } else { + area = get_rectangle_with_padding (); + } + + var monitor_geometry = wm.get_display ().get_monitor_geometry (monitor); + var scale = (float) area.width / monitor_geometry.width; + + var result = new GLib.List (); + foreach (var tilable in windows) { + Mtk.Rectangle rect; +#if HAS_MUTTER46 + tilable.rect.scale_double (scale, Mtk.RoundingStrategy.ROUND, out rect); +#else + rect = { + 0, + 0, + Utils.scale_to_int (tilable.rect.width, scale), + Utils.scale_to_int (tilable.rect.height, scale) + }; +#endif + + var x_ratio = (float) tilable.rect.x / monitor_geometry.width; + rect.x = area.x + Utils.scale_to_int (area.width, x_ratio); + + var y_ratio = (float) tilable.rect.y / monitor_geometry.height; + rect.y = area.y + Utils.scale_to_int (area.height, y_ratio); + + result.append ({ tilable.clone, rect }); + } + + return result; + } + } + /** * Careful: List windows will be modified in place and shouldn't be used afterwards. */ - private GLib.List calculate_grid_placement (Mtk.Rectangle area, GLib.List windows) { + private GLib.List calculate_grid_placement (GLib.List windows) { + var area = get_rectangle_with_padding (); + uint window_count = windows.length (); int columns = (int) Math.ceil (Math.sqrt (window_count)); int rows = (int) Math.ceil (window_count / (double) columns); diff --git a/src/Widgets/MultitaskingView/WorkspaceClone.vala b/src/Widgets/MultitaskingView/WorkspaceClone.vala index 6d9132a15..5f5839a7d 100644 --- a/src/Widgets/MultitaskingView/WorkspaceClone.vala +++ b/src/Widgets/MultitaskingView/WorkspaceClone.vala @@ -137,16 +137,17 @@ public class Gala.WorkspaceClone : ActorTarget { construct { unowned var display = workspace.get_display (); - var monitor_geometry = display.get_monitor_geometry (display.get_primary_monitor ()); + var primary_monitor = display.get_primary_monitor (); + var monitor_geometry = display.get_monitor_geometry (primary_monitor); var background_click_action = new Clutter.ClickAction (); background_click_action.clicked.connect (() => activate (true)); background = new FramedBackground (display); background.add_action (background_click_action); - windows = new WindowListModel (display, STACKING, true, display.get_primary_monitor (), workspace); + windows = new WindowListModel (display, STACKING, true, primary_monitor, workspace); - window_container = new WindowCloneContainer (wm, windows, monitor_scale) { + window_container = new WindowCloneContainer (wm, windows, primary_monitor, monitor_scale) { width = monitor_geometry.width, height = monitor_geometry.height, }; diff --git a/src/Widgets/WindowOverview.vala b/src/Widgets/WindowOverview.vala index 5f2f09e4e..25eb94d0a 100644 --- a/src/Widgets/WindowOverview.vala +++ b/src/Widgets/WindowOverview.vala @@ -119,7 +119,7 @@ public class Gala.WindowOverview : ActorTarget, RootTarget, ActivatableComponent var model = new WindowListModel (display, STACKING, true, i, null, custom_filter); model.items_changed.connect (on_items_changed); - window_clone_container = new WindowCloneContainer (wm, model, scale, true) { + window_clone_container = new WindowCloneContainer (wm, model, i, scale, true) { padding_top = TOP_GAP, padding_left = BORDER, padding_right = BORDER, @@ -173,7 +173,7 @@ public class Gala.WindowOverview : ActorTarget, RootTarget, ActivatableComponent private void on_items_changed (ListModel model, uint pos, uint removed, uint added) { // Check removed > added to make sure we only close once when the last window is removed - // This avoids an inifinite loop since closing will sort the windows which also triggers this signal + // This avoids an infinite loop since closing will sort the windows which also triggers this signal if (is_opened () && removed > added && model.get_n_items () == 0) { close (); } diff --git a/vapi/mutter-mtk-13.vapi b/vapi/mutter-mtk-13.vapi index dc6416e2c..611c00414 100644 --- a/vapi/mutter-mtk-13.vapi +++ b/vapi/mutter-mtk-13.vapi @@ -80,7 +80,7 @@ namespace Mtk { #endif public bool overlap (Mtk.Rectangle rect2); #if HAS_MUTTER46 - public void scale_double (double scale, Mtk.RoundingStrategy rounding_strategy, Mtk.Rectangle dest); + public void scale_double (double scale, Mtk.RoundingStrategy rounding_strategy, out Mtk.Rectangle dest); #endif public Graphene.Rect? to_graphene_rect (); #if HAS_MUTTER47