diff --git a/src/Gestures/GestureTracker.vala b/src/Gestures/GestureTracker.vala index 9ca525bb9..89b684d0d 100644 --- a/src/Gestures/GestureTracker.vala +++ b/src/Gestures/GestureTracker.vala @@ -75,6 +75,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. * This should only be used to determine whether the gesture should be handled. This shouldn't @@ -193,6 +195,23 @@ public class Gala.GestureTracker : Object { } } + /** + * Connects a callback that will only be called if != 0 completions were made. + * If with_gesture is false it will be called immediately, otherwise once {@link on_end} is emitted. + */ + public void add_success_callback (bool with_gesture, owned OnEnd callback) { + if (!with_gesture) { + callback (1, 1, min_animation_duration); + } else { + ulong handler_id = on_end.connect ((percentage, completions, duration) => { + if (completions != 0) { + callback (percentage, completions, duration); + } + }); + handlers.add (handler_id); + } + } + private void disconnect_all_handlers () { foreach (var handler in handlers) { disconnect (handler); @@ -242,6 +261,7 @@ public class Gala.GestureTracker : Object { on_begin (percentage); } + recognizing = true; previous_percentage = percentage; previous_time = elapsed_time; } @@ -283,6 +303,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 092b26c54..59ddef20d 100644 --- a/src/ShellClients/HideTracker.vala +++ b/src/ShellClients/HideTracker.vala @@ -10,11 +10,12 @@ public class Gala.HideTracker : Object { 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; } + public GestureTracker default_gesture_tracker { get; construct; } // Placeholder that will replace pan_action once the pan_backend gets merged public Pantheon.Desktop.HideMode hide_mode { get; set; } @@ -33,8 +34,8 @@ public class Gala.HideTracker : Object { private uint hide_timeout_id = 0; private uint update_timeout_id = 0; - public HideTracker (Meta.Display display, PanelWindow panel) { - Object (display: display, panel: panel); + public HideTracker (Meta.Display display, PanelWindow panel, GestureTracker default_gesture_tracker) { + Object (display: display, panel: panel, default_gesture_tracker: default_gesture_tracker); } ~HideTracker () { @@ -146,13 +147,13 @@ public class Gala.HideTracker : Object { } update_timeout_id = Timeout.add (UPDATE_TIMEOUT, () => { - update_overlap (); + update_overlap (default_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 +186,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 +213,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 +227,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 +246,7 @@ public class Gala.HideTracker : Object { } hide_timeout_id = Timeout.add_once (HIDE_DELAY, () => { - hide (); + hide (default_gesture_tracker, false); hide_timeout_id = 0; }); } @@ -253,9 +258,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 +286,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 (default_gesture_tracker, false); } return false; @@ -325,7 +330,7 @@ public class Gala.HideTracker : Object { int.MAX ); - barrier.trigger.connect (trigger_show); + barrier.trigger.connect (() => trigger_show (default_gesture_tracker, false)); } #if HAS_MUTTER45 @@ -346,6 +351,6 @@ public class Gala.HideTracker : Object { int.MAX ); - barrier.trigger.connect (trigger_show); + barrier.trigger.connect (() => trigger_show (default_gesture_tracker, false)); } } diff --git a/src/ShellClients/PanelClone.vala b/src/ShellClients/PanelClone.vala index 6a32b101f..c3a292363 100644 --- a/src/ShellClients/PanelClone.vala +++ b/src/ShellClients/PanelClone.vala @@ -18,10 +18,10 @@ public class Gala.PanelClone : Object { set { if (value == NEVER) { hide_tracker = null; - show (); + show (default_gesture_tracker, false); return; } else if (hide_tracker == null) { - hide_tracker = new HideTracker (wm.get_display (), panel); + hide_tracker = new HideTracker (wm.get_display (), panel, default_gesture_tracker); hide_tracker.hide.connect (hide); hide_tracker.show.connect (show); } @@ -32,9 +32,11 @@ public class Gala.PanelClone : Object { public bool panel_hidden { get; private set; default = true; } - private SafeWindowClone clone; private Meta.WindowActor actor; + private GestureTracker default_gesture_tracker; + private GestureTracker last_gesture_tracker; + private HideTracker? hide_tracker; public PanelClone (WindowManager wm, PanelWindow panel) { @@ -42,20 +44,11 @@ public class Gala.PanelClone : Object { } construct { - clone = new SafeWindowClone (panel.window, true); - wm.ui_group.add_child (clone); + last_gesture_tracker = default_gesture_tracker = new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION); actor = (Meta.WindowActor) panel.window.get_compositor_private (); - // WindowActor position and Window position aren't necessarily the same. - // The clone needs the actor position - actor.notify["x"].connect (update_clone_position); - actor.notify["y"].connect (update_clone_position); - // Actor visibility might be changed by something else e.g. workspace switch - // but we want to keep it in sync with us - actor.notify["visible"].connect (update_visible); notify["panel-hidden"].connect (() => { - update_visible (); // When hidden changes schedule an update to make sure it's actually // correct since things might have changed during the animation if (hide_tracker != null) { @@ -63,69 +56,32 @@ public class Gala.PanelClone : Object { } }); - // Make sure the actor is visible once it's focused FIXME: better event not only focused - // https://github.com/elementary/gala/issues/2080 - panel.window.focused.connect (update_visible); - - update_visible (); - update_clone_position (); - Idle.add_once (() => { if (hide_mode == NEVER) { - show (); + show (default_gesture_tracker, false); } else { hide_tracker.schedule_update (); } }); } - private void update_visible () { - actor.visible = !panel_hidden; - - if (actor.visible && !wm.get_display ().get_monitor_in_fullscreen (panel.window.get_monitor ())) { - // The actor has just been revealed, make sure it's at the top - // https://github.com/elementary/gala/issues/2080 - actor.get_parent ().set_child_above_sibling (actor, null); - } - } - - private void update_clone_position () { - clone.set_position (calculate_clone_x (panel_hidden), calculate_clone_y (panel_hidden)); - } - - private float calculate_clone_x (bool hidden) { - switch (panel.anchor) { - case TOP: - case BOTTOM: - return actor.x; - default: - return 0; - } - } - - private float calculate_clone_y (bool hidden) { + private float calculate_y (bool hidden) { switch (panel.anchor) { case TOP: - return hidden ? actor.y - actor.height : actor.y; + return hidden ? -actor.height : 0; case BOTTOM: - return hidden ? actor.y + actor.height : actor.y; + return hidden ? actor.height : 0; default: return 0; } } - 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.recognizing) { return; } - panel_hidden = true; + last_gesture_tracker = gesture_tracker; if (!Meta.Util.is_wayland_compositor ()) { Utils.x11_set_window_pass_through (panel.window); @@ -136,39 +92,24 @@ public class Gala.PanelClone : Object { return; } - clone.visible = true; + new GesturePropertyTransition (actor, gesture_tracker, "translation-y", null, calculate_y (true)).start (with_gesture); - 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 (); + gesture_tracker.add_success_callback (with_gesture, () => panel_hidden = true); } - private void show () { - if (!panel_hidden) { + private void show (GestureTracker gesture_tracker, bool with_gesture) { + if (!panel_hidden || 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 (); - - unowned var y_transition = clone.get_transition ("y"); - if (y_transition != null) { - y_transition.completed.connect (() => { - clone.visible = false; - panel_hidden = false; - }); - } else { - clone.visible = false; - panel_hidden = false; - } + new GesturePropertyTransition (actor, gesture_tracker, "translation-y", null, calculate_y (false)).start (with_gesture); + + gesture_tracker.add_success_callback (with_gesture, () => panel_hidden = false); } }