From 0f0b50a300691b18021df22185ad51182149237c Mon Sep 17 00:00:00 2001 From: Leonhard Kargl Date: Sun, 8 Dec 2024 15:46:34 +0100 Subject: [PATCH] ShellClients: Allow force hiding all panels This is e.g. used by the multitasking view. It also supports hiding with gesture --- src/Gestures/GesturePropertyTransition.vala | 14 +-- src/Gestures/GestureTracker.vala | 4 + src/ShellClients/HideTracker.vala | 44 +++++--- src/ShellClients/PanelClone.vala | 65 ++++++----- src/ShellClients/PanelWindow.vala | 4 + src/ShellClients/ShellClientsManager.vala | 6 + src/Widgets/MultitaskingView.vala | 118 +------------------- 7 files changed, 87 insertions(+), 168 deletions(-) diff --git a/src/Gestures/GesturePropertyTransition.vala b/src/Gestures/GesturePropertyTransition.vala index e2471c0d..69dc87e2 100644 --- a/src/Gestures/GesturePropertyTransition.vala +++ b/src/Gestures/GesturePropertyTransition.vala @@ -10,7 +10,7 @@ * with easing without a gesture. Respects the enable animation setting. */ public class Gala.GesturePropertyTransition : Object { - public delegate void DoneCallback (); + public delegate void DoneCallback (bool cancel_action); /** * The actor whose property will be animated. @@ -90,13 +90,13 @@ public class Gala.GesturePropertyTransition : Object { if (actual_from_value.type () != current_value.type ()) { warning ("from_value of type %s is not of the same type as the property %s which is %s. Can't animate.", from_value.type_name (), property, current_value.type_name ()); - finish (); + finish (true); return; } if (current_value.type () != to_value.type ()) { warning ("to_value of type %s is not of the same type as the property %s which is %s. Can't animate.", to_value.type_name (), property, current_value.type_name ()); - finish (); + finish (true); return; } @@ -118,9 +118,9 @@ public class Gala.GesturePropertyTransition : Object { unowned var transition = actor.get_transition (property); if (transition == null) { - finish (); + finish (cancel_action); } else { - transition.stopped.connect (finish); + transition.stopped.connect (() => finish (cancel_action)); } }; @@ -147,9 +147,9 @@ public class Gala.GesturePropertyTransition : Object { } } - private void finish () { + private void finish (bool cancel_action) { if (done_callback != null) { - done_callback (); + done_callback (cancel_action); } unref (); diff --git a/src/Gestures/GestureTracker.vala b/src/Gestures/GestureTracker.vala index aba66f64..57f4cf7f 100644 --- a/src/Gestures/GestureTracker.vala +++ b/src/Gestures/GestureTracker.vala @@ -66,6 +66,8 @@ public class Gala.GestureTracker : Object { */ public bool enabled { get; set; default = true; } + public bool recognizing { get; private set; } + /** * Emitted when a new gesture is detected. * If the receiving code needs to handle this gesture, it should call to connect_handlers to @@ -212,6 +214,7 @@ public class Gala.GestureTracker : Object { on_begin (percentage); } + recognizing = true; previous_percentage = percentage; previous_time = elapsed_time; } @@ -248,6 +251,7 @@ public class Gala.GestureTracker : Object { } disconnect_all_handlers (); + recognizing = false; previous_percentage = 0; previous_time = 0; percentage_delta = 0; diff --git a/src/ShellClients/HideTracker.vala b/src/ShellClients/HideTracker.vala index ee6f9cd2..1bd1918a 100644 --- a/src/ShellClients/HideTracker.vala +++ b/src/ShellClients/HideTracker.vala @@ -6,12 +6,13 @@ */ public class Gala.HideTracker : Object { + private const int ANIMATION_DURATION = 250; private const int BARRIER_OFFSET = 50; // Allow hot corner trigger private const int UPDATE_TIMEOUT = 200; private const int HIDE_DELAY = 500; - public signal void hide (); - public signal void show (); + public signal void hide (GestureTracker gesture_tracker, bool with_gesture); + public signal void show (GestureTracker gesture_tracker, bool with_gesture); public Meta.Display display { get; construct; } public unowned PanelWindow panel { get; construct; } @@ -19,6 +20,7 @@ public class Gala.HideTracker : Object { public Pantheon.Desktop.HideMode hide_mode { get; set; } private Clutter.PanAction pan_action; + private GestureTracker gesture_tracker; // Placeholder that will replace pan_action once the pan_backend gets merged private bool hovered = false; @@ -79,6 +81,8 @@ public class Gala.HideTracker : Object { display.get_workspace_manager ().active_workspace_changed.connect (schedule_update); + gesture_tracker = new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION); + pan_action = new Clutter.PanAction () { n_touch_points = 1, pan_axis = X_AXIS @@ -146,13 +150,13 @@ public class Gala.HideTracker : Object { } update_timeout_id = Timeout.add (UPDATE_TIMEOUT, () => { - update_overlap (); + update_overlap (gesture_tracker, false); update_timeout_id = 0; return Source.REMOVE; }); } - private void update_overlap () { + public void update_overlap (GestureTracker gesture_tracker, bool with_gesture) { overlap = false; focus_overlap = false; focus_maximized_overlap = false; @@ -185,25 +189,25 @@ public class Gala.HideTracker : Object { focus_maximized_overlap = VERTICAL in window.get_maximized (); } - update_hidden (); + update_hidden (gesture_tracker, with_gesture); } - private void update_hidden () { + private void update_hidden (GestureTracker gesture_tracker, bool with_gesture) { switch (hide_mode) { case MAXIMIZED_FOCUS_WINDOW: - toggle_display (focus_maximized_overlap); + toggle_display (focus_maximized_overlap, gesture_tracker, with_gesture); break; case OVERLAPPING_FOCUS_WINDOW: - toggle_display (focus_overlap); + toggle_display (focus_overlap, gesture_tracker, with_gesture); break; case OVERLAPPING_WINDOW: - toggle_display (overlap); + toggle_display (overlap, gesture_tracker, with_gesture); break; case ALWAYS: - toggle_display (true); + toggle_display (true, gesture_tracker, with_gesture); break; default: @@ -212,7 +216,11 @@ public class Gala.HideTracker : Object { } } - private void toggle_display (bool should_hide) { + private void toggle_display (bool should_hide, GestureTracker gesture_tracker, bool with_gesture) { + if (display.get_monitor_in_fullscreen (panel.window.get_monitor ())) { + return; + } + #if HAS_MUTTER45 hovered = panel.window.has_pointer (); #else @@ -222,7 +230,7 @@ public class Gala.HideTracker : Object { if (should_hide && !hovered && !panel.window.has_focus ()) { trigger_hide (); } else { - trigger_show (); + trigger_show (gesture_tracker, with_gesture); } } @@ -241,7 +249,7 @@ public class Gala.HideTracker : Object { } hide_timeout_id = Timeout.add_once (HIDE_DELAY, () => { - hide (); + hide (gesture_tracker, false); hide_timeout_id = 0; }); } @@ -253,9 +261,9 @@ public class Gala.HideTracker : Object { } } - private void trigger_show () { + private void trigger_show (GestureTracker gesture_tracker, bool with_gesture) { reset_hide_timeout (); - show (); + show (gesture_tracker, with_gesture); } private bool check_valid_gesture () { @@ -281,7 +289,7 @@ public class Gala.HideTracker : Object { if (delta_y < 0) { // Only allow swipes upwards panel.window.focus (pan_action.get_last_event (0).get_time ()); - trigger_show (); + trigger_show (gesture_tracker, false); } return false; @@ -325,7 +333,7 @@ public class Gala.HideTracker : Object { int.MAX ); - barrier.trigger.connect (trigger_show); + barrier.trigger.connect (() => trigger_show (gesture_tracker, false)); } #if HAS_MUTTER45 @@ -346,6 +354,6 @@ public class Gala.HideTracker : Object { int.MAX ); - barrier.trigger.connect (trigger_show); + barrier.trigger.connect (() => trigger_show (gesture_tracker, false)); } } diff --git a/src/ShellClients/PanelClone.vala b/src/ShellClients/PanelClone.vala index 6a32b101..8840dc4d 100644 --- a/src/ShellClients/PanelClone.vala +++ b/src/ShellClients/PanelClone.vala @@ -18,7 +18,7 @@ public class Gala.PanelClone : Object { set { if (value == NEVER) { hide_tracker = null; - show (); + show (new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION), false); return; } else if (hide_tracker == null) { hide_tracker = new HideTracker (wm.get_display (), panel); @@ -35,6 +35,9 @@ public class Gala.PanelClone : Object { private SafeWindowClone clone; private Meta.WindowActor actor; + private GestureTracker? last_gesture_tracker; + private bool force_hide = false; + private HideTracker? hide_tracker; public PanelClone (WindowManager wm, PanelWindow panel) { @@ -72,7 +75,7 @@ public class Gala.PanelClone : Object { Idle.add_once (() => { if (hide_mode == NEVER) { - show (); + show (new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION), false); } else { hide_tracker.schedule_update (); } @@ -114,17 +117,13 @@ public class Gala.PanelClone : Object { } } - private int get_animation_duration () { - var fullscreen = wm.get_display ().get_monitor_in_fullscreen (panel.window.get_monitor ()); - var should_animate = AnimationsSettings.get_enable_animations () && !wm.workspace_view.is_opened () && !fullscreen; - return should_animate ? ANIMATION_DURATION : 0; - } - - private void hide () { - if (panel_hidden) { + private void hide (GestureTracker gesture_tracker, bool with_gesture) { + if (panel_hidden || last_gesture_tracker != null && last_gesture_tracker.recognizing) { return; } + last_gesture_tracker = gesture_tracker; + panel_hidden = true; if (!Meta.Util.is_wayland_compositor ()) { @@ -138,37 +137,43 @@ public class Gala.PanelClone : Object { clone.visible = true; - clone.save_easing_state (); - clone.set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); - clone.set_easing_duration (get_animation_duration ()); - clone.y = calculate_clone_y (true); - clone.restore_easing_state (); + new GesturePropertyTransition (clone, gesture_tracker, "y", null, calculate_clone_y (true)).start (with_gesture); } - private void show () { - if (!panel_hidden) { + private void show (GestureTracker gesture_tracker, bool with_gesture) { + if (!panel_hidden || force_hide || last_gesture_tracker != null && last_gesture_tracker.recognizing) { return; } + last_gesture_tracker = gesture_tracker; + if (!Meta.Util.is_wayland_compositor ()) { Utils.x11_unset_window_pass_through (panel.window); } - clone.save_easing_state (); - clone.set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); - clone.set_easing_duration (get_animation_duration ()); - clone.y = calculate_clone_y (false); - clone.restore_easing_state (); + new GesturePropertyTransition (clone, gesture_tracker, "y", null, calculate_clone_y (false)).start (with_gesture, (cancel_action) => { + if (!cancel_action) { + // We need the small timeout because in the case that we're showing in sync with the multitasking view + // we have to make sure that we hide the clone after the multitasking view was already hidden otherwise + // it flickers because the actual window actors are hidden by the multitasking view + Timeout.add_once (10, () => { + force_hide = false; + clone.visible = false; + panel_hidden = false; + }); + } + }); + } - unowned var y_transition = clone.get_transition ("y"); - if (y_transition != null) { - y_transition.completed.connect (() => { - clone.visible = false; - panel_hidden = false; - }); + public void set_force_hide (bool force_hide, GestureTracker gesture_tracker, bool with_gesture) { + this.force_hide = force_hide; + + if (force_hide) { + hide (gesture_tracker, with_gesture); + } else if (hide_mode == NEVER) { + show (gesture_tracker, with_gesture); } else { - clone.visible = false; - panel_hidden = false; + hide_tracker.update_overlap (gesture_tracker, with_gesture); } } } diff --git a/src/ShellClients/PanelWindow.vala b/src/ShellClients/PanelWindow.vala index 7e29bd65..e81693ce 100644 --- a/src/ShellClients/PanelWindow.vala +++ b/src/ShellClients/PanelWindow.vala @@ -143,4 +143,8 @@ public class Gala.PanelWindow : Object { return TOP; } } + + public void set_force_hide (bool force_hide, GestureTracker gesture_tracker, bool with_gesture) { + clone.set_force_hide (force_hide, gesture_tracker, with_gesture); + } } diff --git a/src/ShellClients/ShellClientsManager.vala b/src/ShellClients/ShellClientsManager.vala index dfaa8b0f..ceeaef55 100644 --- a/src/ShellClients/ShellClientsManager.vala +++ b/src/ShellClients/ShellClientsManager.vala @@ -207,6 +207,12 @@ public class Gala.ShellClientsManager : Object { return positioned; } + public void set_force_hide_panels (bool force_hide, GestureTracker gesture_tracker, bool with_gesture) { + foreach (var panel in panel_windows.get_values ()) { + panel.set_force_hide (force_hide, gesture_tracker, with_gesture); + } + } + //X11 only private void parse_mutter_hints (Meta.Window window) requires (!Meta.Util.is_wayland_compositor ()) { if (window.mutter_hints == null) { diff --git a/src/Widgets/MultitaskingView.vala b/src/Widgets/MultitaskingView.vala index a6bf15a7..103fd78b 100644 --- a/src/Widgets/MultitaskingView.vala +++ b/src/Widgets/MultitaskingView.vala @@ -39,7 +39,6 @@ namespace Gala { private IconGroupContainer icon_groups; private Clutter.Actor workspaces; - private Clutter.Actor dock_clones; private Clutter.Actor primary_monitor_container; private Clutter.BrightnessContrastEffect brightness_effect; @@ -81,8 +80,6 @@ namespace Gala { icon_groups = new IconGroupContainer (display.get_monitor_scale (display.get_primary_monitor ())); - dock_clones = new Clutter.Actor (); - brightness_effect = new Clutter.BrightnessContrastEffect (); update_brightness_effect (); @@ -99,7 +96,6 @@ namespace Gala { primary_monitor_container.add_child (icon_groups); primary_monitor_container.add_child (workspaces); add_child (primary_monitor_container); - add_child (dock_clones); unowned var manager = display.get_workspace_manager (); manager.workspace_added.connect (add_workspace); @@ -701,14 +697,13 @@ namespace Gala { } if (opening) { - show_docks (with_gesture, is_cancel_animation); + ShellClientsManager.get_instance ().set_force_hide_panels (true, multitasking_gesture_tracker, with_gesture); } else { - hide_docks (with_gesture, is_cancel_animation); + ShellClientsManager.get_instance ().set_force_hide_panels (false, multitasking_gesture_tracker, with_gesture); } - GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => { - var animation_duration = cancel_action ? 0 : ANIMATION_DURATION; - Timeout.add (animation_duration, () => { + GestureTracker.OnEnd on_animation_end = (percentage, cancel_action, calculated_duration) => { + Timeout.add (calculated_duration, () => { if (!opening) { foreach (var container in window_containers_monitors) { container.visible = false; @@ -720,8 +715,6 @@ namespace Gala { wm.window_group.show (); wm.top_window_group.show (); - dock_clones.destroy_all_children (); - wm.pop_modal (modal_proxy); } @@ -736,113 +729,12 @@ namespace Gala { }; if (!with_gesture) { - on_animation_end (1, false, 0); + on_animation_end (1, false, is_cancel_animation ? 0 : ANIMATION_DURATION); } else { multitasking_gesture_tracker.connect_handlers (null, null, (owned) on_animation_end); } } - private void show_docks (bool with_gesture, bool is_cancel_animation) { - unowned GLib.List window_actors = display.get_window_actors (); - foreach (unowned Meta.WindowActor actor in window_actors) { - const int MAX_OFFSET = 200; - - if (actor.is_destroyed () || !actor.visible) { - continue; - } - - unowned Meta.Window window = actor.get_meta_window (); - var monitor = window.get_monitor (); - - if (window.window_type != Meta.WindowType.DOCK) { - continue; - } - - if (NotificationStack.is_notification (window)) { - continue; - } - - if (display.get_monitor_in_fullscreen (monitor)) { - continue; - } - - var monitor_geom = display.get_monitor_geometry (monitor); - - var window_geom = window.get_frame_rect (); - var top = monitor_geom.y + MAX_OFFSET > window_geom.y; - var bottom = monitor_geom.y + monitor_geom.height - MAX_OFFSET < window_geom.y; - - if (!top && !bottom) { - continue; - } - - var initial_x = actor.x; - var initial_y = actor.y; - var target_y = (top) - ? actor.y - actor.height - : actor.y + actor.height; - - var clone = new SafeWindowClone (window, true); - dock_clones.add_child (clone); - - clone.set_position (initial_x, initial_y); - - GestureTracker.OnUpdate on_animation_update = (percentage) => { - var y = GestureTracker.animation_value (initial_y, target_y, percentage); - clone.y = y; - }; - - GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => { - if (cancel_action) { - return; - } - - clone.save_easing_state (); - clone.set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); - clone.set_easing_duration ((!is_cancel_animation && AnimationsSettings.get_enable_animations ()) ? ANIMATION_DURATION : 0); - clone.y = target_y; - clone.restore_easing_state (); - }; - - if (!with_gesture || !AnimationsSettings.get_enable_animations ()) { - on_animation_end (1, false, 0); - } else { - multitasking_gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end); - } - } - } - - private void hide_docks (bool with_gesture, bool is_cancel_animation) { - foreach (unowned var child in dock_clones.get_children ()) { - var dock = (Clutter.Clone) child; - var initial_y = dock.y; - var target_y = dock.source.y; - - GestureTracker.OnUpdate on_animation_update = (percentage) => { - var y = GestureTracker.animation_value (initial_y, target_y, percentage); - dock.y = y; - }; - - GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => { - if (cancel_action) { - return; - } - - dock.save_easing_state (); - dock.set_easing_mode (Clutter.AnimationMode.EASE_OUT_QUAD); - dock.set_easing_duration (AnimationsSettings.get_animation_duration (ANIMATION_DURATION)); - dock.y = target_y; - dock.restore_easing_state (); - }; - - if (!with_gesture || !AnimationsSettings.get_enable_animations ()) { - on_animation_end (1, false, 0); - } else { - multitasking_gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end); - } - } - } - private bool keybinding_filter (Meta.KeyBinding binding) { var action = Meta.Prefs.get_keybinding_action (binding.get_name ());