From a917b3813ab896d4191369cf4145b1180d111b2f Mon Sep 17 00:00:00 2001 From: lenemter Date: Sat, 2 Aug 2025 11:21:53 +0900 Subject: [PATCH 1/3] Introduce GestureAction.CUSTOM --- lib/Gestures/Gesture.vala | 3 +-- src/ShellClients/PanelWindow.vala | 4 +--- src/ShellClients/ShellWindow.vala | 6 +++--- src/Widgets/MultitaskingView/WindowClone.vala | 6 +++--- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/Gestures/Gesture.vala b/lib/Gestures/Gesture.vala index 066d4244b..2e2a5bcde 100644 --- a/lib/Gestures/Gesture.vala +++ b/lib/Gestures/Gesture.vala @@ -39,9 +39,8 @@ namespace Gala { SWITCH_WORKSPACE, SWITCH_WINDOWS, MULTITASKING_VIEW, - DOCK, ZOOM, - CLOSE_WINDOW, + CUSTOM, N_ACTIONS } diff --git a/src/ShellClients/PanelWindow.vala b/src/ShellClients/PanelWindow.vala index c33373c63..3008fe9a5 100644 --- a/src/ShellClients/PanelWindow.vala +++ b/src/ShellClients/PanelWindow.vala @@ -6,8 +6,6 @@ */ public class Gala.PanelWindow : ShellWindow, RootTarget { - private const int ANIMATION_DURATION = 250; - private static HashTable window_struts = new HashTable (null, null); public WindowManager wm { get; construct; } @@ -53,7 +51,7 @@ public class Gala.PanelWindow : ShellWindow, RootTarget { notify["width"].connect (update_strut); notify["height"].connect (update_strut); - gesture_controller = new GestureController (DOCK, wm); + gesture_controller = new GestureController (CUSTOM, wm); add_gesture_controller (gesture_controller); hide_tracker = new HideTracker (wm.get_display (), this); diff --git a/src/ShellClients/ShellWindow.vala b/src/ShellClients/ShellWindow.vala index 2e2c1d725..586627ade 100644 --- a/src/ShellClients/ShellWindow.vala +++ b/src/ShellClients/ShellWindow.vala @@ -37,7 +37,7 @@ public class Gala.ShellWindow : PositionedWindow, GestureTarget { private void update_target () { property_target = new PropertyTarget ( - DOCK, window_actor, + CUSTOM, window_actor, get_animation_property (), get_property_type (), calculate_value (false), @@ -54,7 +54,7 @@ public class Gala.ShellWindow : PositionedWindow, GestureTarget { } private void update_property () { - property_target.propagate (UPDATE, DOCK, get_hidden_progress ()); + property_target.propagate (UPDATE, CUSTOM, get_hidden_progress ()); } public override void propagate (UpdateType update_type, GestureAction action, double progress) { @@ -84,7 +84,7 @@ public class Gala.ShellWindow : PositionedWindow, GestureTarget { multitasking_view_progress = progress; break; - case DOCK: + case CUSTOM: custom_progress = progress; break; diff --git a/src/Widgets/MultitaskingView/WindowClone.vala b/src/Widgets/MultitaskingView/WindowClone.vala index c65a8e56a..421d7c103 100644 --- a/src/Widgets/MultitaskingView/WindowClone.vala +++ b/src/Widgets/MultitaskingView/WindowClone.vala @@ -95,7 +95,7 @@ public class Gala.WindowClone : ActorTarget, RootTarget { construct { reactive = true; - gesture_controller = new GestureController (CLOSE_WINDOW, wm); + gesture_controller = new GestureController (CUSTOM, wm); gesture_controller.enable_scroll (this, VERTICAL); add_gesture_controller (gesture_controller); @@ -272,7 +272,7 @@ public class Gala.WindowClone : ActorTarget, RootTarget { } public override void update_progress (Gala.GestureAction action, double progress) { - if (action != CLOSE_WINDOW || slot == null || !Meta.Prefs.get_gnome_animations ()) { + if (action != CUSTOM || slot == null || !Meta.Prefs.get_gnome_animations ()) { return; } @@ -295,7 +295,7 @@ public class Gala.WindowClone : ActorTarget, RootTarget { public override void end_progress (GestureAction action) { update_hover_widgets (false); - if (action == CLOSE_WINDOW && get_current_commit (CLOSE_WINDOW) > 0.5 && Meta.Prefs.get_gnome_animations ()) { + if (action == CUSTOM && get_current_commit (CUSTOM) > 0.5 && Meta.Prefs.get_gnome_animations ()) { close_window (Meta.CURRENT_TIME); } } From 1b8bfd343894edd9762494340789f3389e458fa8 Mon Sep 17 00:00:00 2001 From: lenemter Date: Sat, 2 Aug 2025 13:49:13 +0900 Subject: [PATCH 2/3] PiP: control pip opacity using gesture controller --- plugins/pip/Main.vala | 32 ++++++++-------- plugins/pip/PopupWindow.vala | 72 ++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 53 deletions(-) diff --git a/plugins/pip/Main.vala b/plugins/pip/Main.vala index c5976e7e2..b0fedd1ff 100644 --- a/plugins/pip/Main.vala +++ b/plugins/pip/Main.vala @@ -97,33 +97,31 @@ public class Gala.Plugins.PIP.Plugin : Gala.Plugin { return; } - var popup_window = new PopupWindow (wm.get_display (), active); + var popup_window = new PopupWindow (wm, active); popup_window.set_container_clip (rect); - popup_window.show.connect (on_popup_window_show); - popup_window.hide.connect (on_popup_window_hide); add_window (popup_window); } - private void on_popup_window_show (Clutter.Actor popup_window) { - track_actor (popup_window); - update_region (); - } - - private void on_popup_window_hide (Clutter.Actor popup_window) { - untrack_actor (popup_window); - update_region (); - } - private void select_window_at (int x, int y) { var selected = get_window_actor_at (x, y); if (selected != null) { - var popup_window = new PopupWindow (wm.get_display (), selected); - popup_window.show.connect (on_popup_window_show); - popup_window.hide.connect (on_popup_window_hide); + var popup_window = new PopupWindow (wm, selected); add_window (popup_window); } } + private void popup_window_reactive_changed (GLib.Object obj, GLib.ParamSpec pspec) requires (obj is PopupWindow) { + var popup_window = (PopupWindow) obj; + + if (popup_window.reactive) { + track_actor (popup_window); + } else { + untrack_actor (popup_window); + } + + update_region (); + } + private void clear_selection_area () { if (selection_area != null) { untrack_actor (selection_area); @@ -189,6 +187,8 @@ public class Gala.Plugins.PIP.Plugin : Gala.Plugin { } private void add_window (PopupWindow popup_window) { + track_actor (popup_window); + popup_window.notify["reactive"].connect (popup_window_reactive_changed); popup_window.closed.connect (() => remove_window (popup_window)); windows.add (popup_window); wm.ui_group.add_child (popup_window); diff --git a/plugins/pip/PopupWindow.vala b/plugins/pip/PopupWindow.vala index ebb7f8549..ce0e9cc28 100644 --- a/plugins/pip/PopupWindow.vala +++ b/plugins/pip/PopupWindow.vala @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { +public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { private int button_size; private int container_margin; private const uint FADE_OUT_TIMEOUT = 200; @@ -16,7 +16,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { public signal void closed (); - public Meta.Display display { get; construct; } + public WindowManager wm { get; construct; } public Meta.WindowActor window_actor { get; construct; } private Clutter.Clone clone; // clone itself @@ -26,6 +26,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { private Gala.CloseButton close_button; private Clutter.Actor resize_button; private DragDropAction move_action; + private GestureController gesture_controller; private float begin_resize_width = 0.0f; private float begin_resize_height = 0.0f; @@ -46,11 +47,13 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { height = src_height * ratio; } - public PopupWindow (Meta.Display display, Meta.WindowActor window_actor) { - Object (display: display, window_actor: window_actor); + public PopupWindow (WindowManager wm, Meta.WindowActor window_actor) { + Object (wm: wm, window_actor: window_actor); } construct { + unowned var display = wm.get_display (); + var scale = display.get_monitor_scale (display.get_current_monitor ()); button_size = Gala.Utils.scale_to_int (36, scale); @@ -127,37 +130,28 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { unowned var workspace_manager = display.get_workspace_manager (); workspace_manager.active_workspace_changed.connect (update_window_focus); - } - - public override void show () { - base.show (); - - opacity = 0; - save_easing_state (); - set_easing_duration (Utils.get_animation_duration (200)); - opacity = 255; - restore_easing_state (); + gesture_controller = new GestureController (CUSTOM, wm); + add_gesture_controller (gesture_controller); + add_target (new PropertyTarget (CUSTOM, this, "opacity", typeof (uint), 255u, 0u)); } - public override void hide () { - opacity = 255; + public override void start_progress (GestureAction action) { + if (action != CUSTOM) { + return; + } - var duration = Utils.get_animation_duration (200); - save_easing_state (); - set_easing_duration (duration); - opacity = 0; - restore_easing_state (); + reactive = false; + visible = true; + } - if (duration == 0) { - base.hide (); - } else { - ulong completed_id = 0; - completed_id = transitions_completed.connect (() => { - disconnect (completed_id); - base.hide (); - }); + public override void end_progress (GestureAction action) { + if (action != CUSTOM) { + return; } + + reactive = true; + visible = get_current_progress (CUSTOM) < 0.5; } public override bool enter_event (Clutter.Event event) { @@ -200,9 +194,9 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { private Clutter.Actor on_move_begin () { #if HAS_MUTTER48 - display.set_cursor (Meta.Cursor.MOVE); + wm.get_display ().set_cursor (Meta.Cursor.MOVE); #else - display.set_cursor (Meta.Cursor.DND_IN_DRAG); + wm.get_display ().set_cursor (Meta.Cursor.DND_IN_DRAG); #endif return this; @@ -211,7 +205,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { private void on_move_end () { reactive = true; update_screen_position (); - display.set_cursor (Meta.Cursor.DEFAULT); + wm.get_display ().set_cursor (Meta.Cursor.DEFAULT); } private bool on_resize_button_press (Clutter.Event event) { @@ -229,7 +223,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { grab = resize_button.get_stage ().grab (resize_button); resize_button.event.connect (on_resize_event); - display.set_cursor (Meta.Cursor.SE_RESIZE); + wm.get_display ().set_cursor (Meta.Cursor.SE_RESIZE); return Clutter.EVENT_PROPAGATE; } @@ -290,7 +284,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { update_screen_position (); - display.set_cursor (Meta.Cursor.DEFAULT); + wm.get_display ().set_cursor (Meta.Cursor.DEFAULT); } private void on_allocation_changed () { @@ -317,6 +311,8 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { } private void update_window_focus () { + unowned var display = wm.get_display (); + unowned Meta.Window focus_window = display.get_focus_window (); if ((focus_window != null && !Utils.get_window_is_normal (focus_window)) || (previous_focus != null && !Utils.get_window_is_normal (previous_focus))) { @@ -329,9 +325,9 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { unowned var window = window_actor.get_meta_window (); if (window.appears_focused && window.located_on_workspace (active_workspace)) { - hide (); + gesture_controller.goto (1.0); } else if (!window_actor.is_destroyed ()) { - show (); + gesture_controller.goto (0.0); } previous_focus = focus_window; @@ -423,7 +419,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { private void place_window_in_screen () { off_screen = false; - var workarea_rect = display.get_workspace_manager ().get_active_workspace ().get_work_area_all_monitors (); + var workarea_rect = wm.get_display ().get_workspace_manager ().get_active_workspace ().get_work_area_all_monitors (); var screen_limit_start_x = workarea_rect.x + SCREEN_MARGIN; var screen_limit_end_x = workarea_rect.x + workarea_rect.width - SCREEN_MARGIN - width; @@ -449,6 +445,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { set_easing_mode (Clutter.AnimationMode.EASE_OUT_BACK); set_easing_duration (duration); + unowned var display = wm.get_display (); var monitor_rect = display.get_monitor_geometry (display.get_current_monitor ()); int monitor_x = monitor_rect.x; @@ -496,6 +493,7 @@ public class Gala.Plugins.PIP.PopupWindow : Clutter.Actor { } private bool coord_is_in_other_monitor (float coord, Clutter.Orientation axis) { + unowned var display = wm.get_display (); int n_monitors = display.get_n_monitors (); if (n_monitors == 1) { From ca5ad876e1fbd53e79eaae4fa9cc2ed2c28ae969 Mon Sep 17 00:00:00 2001 From: lenemter Date: Sat, 2 Aug 2025 19:41:18 +0900 Subject: [PATCH 3/3] PiP: hide in multitasking view --- lib/DragDropAction.vala | 4 +++ lib/WindowManager.vala | 8 +++++ plugins/pip/PopupWindow.vala | 58 ++++++++++++++++++++++++++++-------- src/WindowManager.vala | 8 +++++ 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/lib/DragDropAction.vala b/lib/DragDropAction.vala index f22e95169..fdf50fc20 100644 --- a/lib/DragDropAction.vala +++ b/lib/DragDropAction.vala @@ -186,6 +186,10 @@ namespace Gala { } public override bool handle_event (Clutter.Event event) { + if (!actor.reactive){ + return Clutter.EVENT_PROPAGATE; + } + if (!(DragDropActionType.SOURCE in drag_type)) { return Clutter.EVENT_PROPAGATE; } diff --git a/lib/WindowManager.vala b/lib/WindowManager.vala index 6c8304a5e..ea1f84064 100644 --- a/lib/WindowManager.vala +++ b/lib/WindowManager.vala @@ -211,5 +211,13 @@ namespace Gala { * @return true if the action should be prohibited, false otherwise */ public abstract bool filter_action (GestureAction action); + + /** + * Adds target to the multitasking view and window overview so the target responds to the multitasking view + * close/open gesture and shortcuts. + * + * @param target Target to add to multitasking view and window overview + */ + public abstract void add_multitasking_view_target (GestureTarget target); } } diff --git a/plugins/pip/PopupWindow.vala b/plugins/pip/PopupWindow.vala index ce0e9cc28..c50b5ade8 100644 --- a/plugins/pip/PopupWindow.vala +++ b/plugins/pip/PopupWindow.vala @@ -26,7 +26,11 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { private Gala.CloseButton close_button; private Clutter.Actor resize_button; private DragDropAction move_action; + private GestureController gesture_controller; + private PropertyTarget opacity_target; + private double custom_progress = 0.0; + private double multitasking_view_progress = 0.0; private float begin_resize_width = 0.0f; private float begin_resize_height = 0.0f; @@ -75,9 +79,7 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { rounded_container.add_child (clone_container); rounded_container.add_effect (new RoundedCornersEffect (6, scale)); - container = new Clutter.Actor () { - reactive = true - }; + container = new Clutter.Actor (); container.add_child (rounded_container); container.add_effect (new ShadowEffect ("window", scale)); @@ -122,7 +124,7 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { window_actor.notify["allocation"].connect (on_allocation_changed); container.set_position (container_margin, container_margin); - update_clone_clip (); + on_allocation_changed (); unowned var window = window_actor.get_meta_window (); window.unmanaged.connect (on_close_click_clicked); @@ -133,25 +135,51 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { gesture_controller = new GestureController (CUSTOM, wm); add_gesture_controller (gesture_controller); - add_target (new PropertyTarget (CUSTOM, this, "opacity", typeof (uint), 255u, 0u)); + + opacity_target = new PropertyTarget (CUSTOM, this, "opacity", typeof (uint), 255u, 0u); + add_target (opacity_target); + + wm.add_multitasking_view_target (this); + } + + private double get_opacity_progress () { + return double.max (custom_progress, multitasking_view_progress); } public override void start_progress (GestureAction action) { - if (action != CUSTOM) { + if (action != CUSTOM && action != MULTITASKING_VIEW) { return; } + move_action.cancel (); + stop_resizing (); + hide_buttons (); reactive = false; - visible = true; } public override void end_progress (GestureAction action) { - if (action != CUSTOM) { + if (action != CUSTOM && action != MULTITASKING_VIEW) { return; } - reactive = true; - visible = get_current_progress (CUSTOM) < 0.5; + reactive = get_current_progress (CUSTOM) == 0.0 && get_current_progress (MULTITASKING_VIEW) == 0.0; + } + + public override void update_progress (GestureAction action, double progress) { + switch (action) { + case MULTITASKING_VIEW: + multitasking_view_progress = progress; + break; + + case CUSTOM: + custom_progress = progress; + break; + + default: + break; + } + + opacity_target.propagate (UPDATE, CUSTOM, get_opacity_progress ()); } public override bool enter_event (Clutter.Event event) { @@ -171,6 +199,11 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { } public override bool leave_event (Clutter.Event event) { + hide_buttons (); + return Clutter.EVENT_PROPAGATE; + } + + private void hide_buttons () { var duration = Utils.get_animation_duration (300); close_button.save_easing_state (); @@ -182,8 +215,6 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { resize_button.set_easing_duration (duration); resize_button.opacity = 0; resize_button.restore_easing_state (); - - return Clutter.EVENT_PROPAGATE; } public void set_container_clip (Graphene.Rect? container_clip) { @@ -203,7 +234,6 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { } private void on_move_end () { - reactive = true; update_screen_position (); wm.get_display ().set_cursor (Meta.Cursor.DEFAULT); } @@ -533,6 +563,8 @@ public class Gala.Plugins.PIP.PopupWindow : RootTarget, ActorTarget { } private void activate () { + warning ("Activate"); + if (off_screen) { place_window_in_screen (); } else { diff --git a/src/WindowManager.vala b/src/WindowManager.vala index 4d7b4b3ab..38ac30a78 100644 --- a/src/WindowManager.vala +++ b/src/WindowManager.vala @@ -1710,6 +1710,14 @@ namespace Gala { return modal_stack.peek_head ().filter_action (action); } + public void add_multitasking_view_target (GestureTarget target) { + multitasking_view.add_target (target); + + if (window_overview is WindowOverview) { + ((WindowOverview) window_overview).add_target (target); + } + } + public override void confirm_display_change () { unowned var monitor_manager = get_display ().get_context ().get_backend ().get_monitor_manager (); var timeout = monitor_manager.get_display_configuration_timeout ();