From e9d9179775474a81336ef56c3a75c2ca97b02289 Mon Sep 17 00:00:00 2001 From: Leo Date: Sat, 16 May 2026 15:43:28 +0300 Subject: [PATCH 1/2] =?UTF-8?q?Revert=20"Revert=20"WindowClone:=20display?= =?UTF-8?q?=20modal=20dialogs=20on=20top=20of=20parent=20window"=20(?= =?UTF-8?q?=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f317b40112836f09abbb8c800addd6d0cb693466. --- .../MultitaskingView/MonitorClone.vala | 2 +- src/Widgets/MultitaskingView/WindowClone.vala | 113 ++++++++++++++---- .../MultitaskingView/WorkspaceClone.vala | 2 +- src/Widgets/WindowOverview.vala | 2 +- src/WindowListModel.vala | 30 ++++- 5 files changed, 117 insertions(+), 32 deletions(-) diff --git a/src/Widgets/MultitaskingView/MonitorClone.vala b/src/Widgets/MultitaskingView/MonitorClone.vala index 266b56fb2..5fbb068ab 100644 --- a/src/Widgets/MultitaskingView/MonitorClone.vala +++ b/src/Widgets/MultitaskingView/MonitorClone.vala @@ -33,7 +33,7 @@ public class Gala.MonitorClone : Widget { background = new BackgroundManager (display, monitor, false); - var windows = new WindowListModel (display, STACKING, true, monitor); + var windows = new WindowListModel (display, STACKING, true, true, monitor); window_container = new WindowCloneContainer (wm, windows, monitor_scale); window_container.add_constraint (new Clutter.BindConstraint (this, SIZE, 0.0f)); diff --git a/src/Widgets/MultitaskingView/WindowClone.vala b/src/Widgets/MultitaskingView/WindowClone.vala index 952793933..3883df88b 100644 --- a/src/Widgets/MultitaskingView/WindowClone.vala +++ b/src/Widgets/MultitaskingView/WindowClone.vala @@ -67,10 +67,12 @@ public class Gala.WindowClone : Widget, RootTarget { private ulong check_confirm_dialog_cb = 0; private Clutter.Actor clone_container; + private Clutter.Actor child_clone_container; private Gala.CloseButton close_button; private ActiveShape active_shape; private Clutter.Actor window_icon; private Tooltip window_title; + private GLib.ListModel window_list_model; private GestureController gesture_controller; @@ -131,9 +133,14 @@ public class Gala.WindowClone : Widget, RootTarget { }; bind_property ("monitor-scale", active_shape, "monitor-scale"); - clone_container = new Clutter.Actor () { - pivot_point = { 0.5f, 0.5f } - }; + window_list_model = new WindowListModel (wm.get_display (), STACKING, true, false, -1, null, new ChildFilter (window)); + window_list_model.items_changed.connect_after (update_targets); + + child_clone_container = new Clutter.Actor (); + child_clone_container.bind_model (window_list_model, create_child_func); + + clone_container = new Clutter.Actor (); + clone_container.add_child (child_clone_container); window_title = new Tooltip (monitor_scale); bind_property ("monitor-scale", window_title, "monitor-scale"); @@ -176,6 +183,12 @@ public class Gala.WindowClone : Widget, RootTarget { active_shape.restore_easing_state (); } + private Clutter.Actor create_child_func (Object obj) requires (obj is Meta.Window) { + unowned var child_window = (Meta.Window) obj; + + return new Clutter.Clone ((Meta.WindowActor) child_window.get_compositor_private ()); + } + private void reallocate () { window_icon = new WindowIcon (window, WINDOW_ICON_SIZE, (int)Math.round (monitor_scale)) { visible = mode != SINGLE_APP_OVERVIEW @@ -197,7 +210,7 @@ public class Gala.WindowClone : Widget, RootTarget { */ private void load_clone (Meta.WindowActor actor) { clone = new Clutter.Clone (actor); - clone_container.add_child (clone); + clone_container.insert_child_below (clone, null); check_shadow_requirements (); } @@ -276,6 +289,42 @@ public class Gala.WindowClone : Widget, RootTarget { add_target (new PropertyTarget (MULTITASKING_VIEW, window_title, "opacity", typeof (uint8), (uint8) 0u, (uint8) 255u)); add_target (new PropertyTarget (MULTITASKING_VIEW, close_button, "opacity", typeof (uint8), (uint8) 0u, (uint8) 255u)); + + var window_buffer_rect = window.get_buffer_rect (); + var window_shadow_spread_x = window_rect.x - window_buffer_rect.x; + var window_shadow_spread_y = window_rect.y - window_buffer_rect.y; + + var i = 0u; + for (unowned var child_clone = child_clone_container.get_first_child (); + child_clone != null; + child_clone = child_clone.get_next_sibling () + ) { + var child_window = (Meta.Window) window_list_model.get_item (i); + + var child_buffer_rect = child_window.get_buffer_rect (); + var child_frame_rect = child_window.get_frame_rect (); + + var scale = 1.0f; + if (child_frame_rect.width > window_rect.width || child_frame_rect.height > window_rect.height) { + scale = float.min ((float) window_rect.width / child_frame_rect.width, (float) window_rect.height / child_frame_rect.height); + + add_target (new PropertyTarget (MULTITASKING_VIEW, child_clone, "width", typeof (float), (float) child_buffer_rect.width, child_buffer_rect.width * scale)); + add_target (new PropertyTarget (MULTITASKING_VIEW, child_clone, "height", typeof (float), (float) child_buffer_rect.height, child_buffer_rect.height * scale)); + } + + var child_parent_x_diff = child_buffer_rect.x - window_buffer_rect.x; + var child_parent_y_diff = child_buffer_rect.y - window_buffer_rect.y; + // Center the window + var child_shadow_spread_x = (child_frame_rect.x - child_buffer_rect.x) * scale; + var child_shadow_spread_y = (child_frame_rect.y - child_buffer_rect.y) * scale; + var target_x = window_shadow_spread_x - child_shadow_spread_x + (window_rect.width - child_frame_rect.width * scale) / 2.0f; + var target_y = window_shadow_spread_y - child_shadow_spread_y + (window_rect.height - child_frame_rect.height * scale) / 2.0f; + + add_target (new PropertyTarget (MULTITASKING_VIEW, child_clone, "x", typeof (float), (float) child_parent_x_diff, target_x)); + add_target (new PropertyTarget (MULTITASKING_VIEW, child_clone, "y", typeof (float), (float) child_parent_y_diff, target_y)); + + i++; + } } public override void update_progress (Gala.GestureAction action, double progress) { @@ -325,7 +374,7 @@ public class Gala.WindowClone : Widget, RootTarget { unowned var display = wm.get_display (); - clone.set_scale (clone_scale_factor, clone_scale_factor); + clone_container.set_scale (clone_scale_factor, clone_scale_factor); Clutter.ActorBox shape_alloc = { -ACTIVE_SHAPE_SIZE, @@ -418,14 +467,14 @@ public class Gala.WindowClone : Widget, RootTarget { drag_action.cancel (); } - if (clone != null) { - clone.destroy (); - } + clone?.destroy (); if (check_confirm_dialog_cb != 0) { SignalHandler.disconnect (window.get_display (), check_confirm_dialog_cb); check_confirm_dialog_cb = 0; } + + child_clone_container.bind_model (null, (Clutter.ActorCreateChildFunc) null); } private void actor_clicked (uint32 button, Clutter.InputDeviceType device_type = POINTER_DEVICE) { @@ -443,18 +492,21 @@ public class Gala.WindowClone : Widget, RootTarget { private Clutter.Actor drag_begin (float click_x, float click_y) requires (drag_handle == null) { active_shape.hide (); - var scale = window_icon.width / clone.width; + var scale = window_icon.width / clone_container.width; var duration = Utils.get_animation_duration (FADE_ANIMATION_DURATION); float abs_x, abs_y; - clone.get_transformed_position (out abs_x, out abs_y); - clone.save_easing_state (); - clone.set_easing_duration (duration); - clone.set_easing_mode (Clutter.AnimationMode.EASE_IN_CUBIC); - clone.set_pivot_point ((click_x - abs_x) / clone.width, (click_y - abs_y) / clone.height); - clone.set_scale (scale, scale); - clone.opacity = 0; - clone.restore_easing_state (); + clone_container.get_transformed_position (out abs_x, out abs_y); + clone_container.save_easing_state (); + clone_container.set_easing_duration (duration); + clone_container.set_easing_mode (Clutter.AnimationMode.EASE_IN_CUBIC); + clone_container.set_pivot_point ( + (click_x - abs_x) / clone_container.width, + (click_y - abs_y) / clone_container.height + ); + clone_container.set_scale (scale, scale); + clone_container.opacity = 0; + clone_container.restore_easing_state (); get_transformed_position (out abs_x, out abs_y); @@ -565,13 +617,13 @@ public class Gala.WindowClone : Widget, RootTarget { drag_handle.set_position (target_x, target_y); drag_handle.restore_easing_state (); - clone.set_pivot_point (0.0f, 0.0f); - clone.save_easing_state (); - clone.set_easing_duration (duration); - clone.set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); - clone.set_scale (1, 1); - clone.opacity = 255; - clone.restore_easing_state (); + clone_container.set_pivot_point (0.0f, 0.0f); + clone_container.save_easing_state (); + clone_container.set_easing_duration (duration); + clone_container.set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); + clone_container.set_scale (1, 1); + clone_container.opacity = 255; + clone_container.restore_easing_state (); close_button.visible = true; window_title.visible = true; @@ -645,4 +697,17 @@ public class Gala.WindowClone : Widget, RootTarget { }); } } + + private class ChildFilter : Gtk.Filter { + public Meta.Window parent_window { private get; construct; } + + public ChildFilter (Meta.Window parent_window) { + Object (parent_window: parent_window); + } + + public override bool match (GLib.Object? item) requires (item is Meta.Window) { + unowned var window = (Meta.Window) item; + return parent_window.is_ancestor_of_transient (window); + } + } } diff --git a/src/Widgets/MultitaskingView/WorkspaceClone.vala b/src/Widgets/MultitaskingView/WorkspaceClone.vala index 99d6fd74d..8530c53af 100644 --- a/src/Widgets/MultitaskingView/WorkspaceClone.vala +++ b/src/Widgets/MultitaskingView/WorkspaceClone.vala @@ -137,7 +137,7 @@ public class Gala.WorkspaceClone : Widget { 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, true, display.get_primary_monitor (), workspace); window_container = new WindowCloneContainer (wm, windows, monitor_scale) { width = monitor_geometry.width, diff --git a/src/Widgets/WindowOverview.vala b/src/Widgets/WindowOverview.vala index 59b992148..fcb96d409 100644 --- a/src/Widgets/WindowOverview.vala +++ b/src/Widgets/WindowOverview.vala @@ -120,7 +120,7 @@ public class Gala.WindowOverview : Root, RootTarget, ActivatableComponent { var scale = Utils.get_ui_scaling_factor (display, i); var custom_filter = new Gtk.CustomFilter (window_filter_func); - var model = new WindowListModel (display, STACKING, true, i, null, custom_filter); + var model = new WindowListModel (display, STACKING, true, true, i, null, custom_filter); model.items_changed.connect (on_items_changed); var window_clone_container = new WindowCloneContainer (wm, model, scale, mode) { diff --git a/src/WindowListModel.vala b/src/WindowListModel.vala index 9b7cbb5e7..d709ce811 100644 --- a/src/WindowListModel.vala +++ b/src/WindowListModel.vala @@ -25,6 +25,11 @@ public class Gala.WindowListModel : Object, ListModel { */ public bool normal_filter { get; construct set; } + /** + * If true only present windows that are toplevel windows and not transients. + */ + public bool not_transient_filter { get; construct set; } + /** * If >= 0 only present windows that are on this monitor. */ @@ -41,14 +46,21 @@ public class Gala.WindowListModel : Object, ListModel { private Gee.ArrayList windows; public WindowListModel ( - Meta.Display display, SortMode sort_mode = NONE, - bool normal_filter = false, int monitor_filter = -1, + Meta.Display display, + SortMode sort_mode = NONE, + bool normal_filter = false, + bool not_transient_filter = false, + int monitor_filter = -1, Meta.Workspace? workspace_filter = null, Gtk.Filter? custom_filter = null ) { Object ( - display: display, sort_mode: sort_mode, normal_filter: normal_filter, - monitor_filter: monitor_filter, workspace_filter: workspace_filter, + display: display, + sort_mode: sort_mode, + normal_filter: normal_filter, + not_transient_filter: not_transient_filter, + monitor_filter: monitor_filter, + workspace_filter: workspace_filter, custom_filter: custom_filter ); } @@ -70,7 +82,7 @@ public class Gala.WindowListModel : Object, ListModel { private void on_window_created (Meta.Window window) { window.unmanaging.connect (on_window_unmanaging); - InternalUtils.wait_for_window_actor (window, (actor) => check_window (actor.meta_window)); + InternalUtils.wait_for_window_actor_visible (window, (actor) => check_window (actor.meta_window)); } private void on_window_unmanaging (Meta.Window window) { @@ -102,6 +114,10 @@ public class Gala.WindowListModel : Object, ListModel { } private bool should_present_window (Meta.Window window) { + if (window.get_compositor_private () == null) { + return false; + } + if (monitor_filter >= 0 && monitor_filter != window.get_monitor ()) { return false; } @@ -117,6 +133,10 @@ public class Gala.WindowListModel : Object, ListModel { return false; } + if (not_transient_filter && window.find_root_ancestor () != window) { + return false; + } + if (custom_filter != null) { return custom_filter.match (window); } From 877b0f2a935c820f6a8055bdb981ac030d41cb86 Mon Sep 17 00:00:00 2001 From: lenemter Date: Sat, 16 May 2026 16:30:55 +0300 Subject: [PATCH 2/2] Fix(?) crash --- src/Widgets/MultitaskingView/WindowClone.vala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Widgets/MultitaskingView/WindowClone.vala b/src/Widgets/MultitaskingView/WindowClone.vala index 3883df88b..76ade8db8 100644 --- a/src/Widgets/MultitaskingView/WindowClone.vala +++ b/src/Widgets/MultitaskingView/WindowClone.vala @@ -183,10 +183,16 @@ public class Gala.WindowClone : Widget, RootTarget { active_shape.restore_easing_state (); } - private Clutter.Actor create_child_func (Object obj) requires (obj is Meta.Window) { + private static Clutter.Actor create_child_func (Object obj) requires (obj is Meta.Window) { unowned var child_window = (Meta.Window) obj; + unowned var child_window_actor = (Meta.WindowActor) child_window.get_compositor_private (); - return new Clutter.Clone ((Meta.WindowActor) child_window.get_compositor_private ()); + if (child_window_actor == null) { + critical ("WindowClone: WindowListModel gave us a bad window"); + return new Clutter.Actor (); + } + + return new Clutter.Clone (child_window_actor); } private void reallocate () {