Skip to content

Commit d764099

Browse files
committed
Improve dock reveal animation when switching workspaces
1 parent d11be69 commit d764099

File tree

6 files changed

+334
-263
lines changed

6 files changed

+334
-263
lines changed

lib/Gestures/Gesture.vala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace Gala {
4141
MULTITASKING_VIEW,
4242
ZOOM,
4343
CUSTOM,
44+
CUSTOM_2,
4445
N_ACTIONS
4546
}
4647

src/ShellClients/HideTracker.vala

Lines changed: 19 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,31 @@
11
/*
2-
* Copyright 2024 elementary, Inc. (https://elementary.io)
2+
* Copyright 2024-2025 elementary, Inc. (https://elementary.io)
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*
55
* Authored by: Leonhard Kargl <[email protected]>
66
*/
77

88
public class Gala.HideTracker : Object {
99
private const int BARRIER_OFFSET = 50; // Allow hot corner trigger
10-
private const int UPDATE_TIMEOUT = 200;
1110
private const int HIDE_DELAY = 500;
1211

1312
public signal void hide ();
1413
public signal void show ();
1514

1615
public Meta.Display display { get; construct; }
17-
public unowned PanelWindow panel { get; construct; }
18-
public Pantheon.Desktop.HideMode hide_mode { get; set; }
16+
public unowned ShellWindow panel { get; construct; }
1917

2018
private static GLib.Settings behavior_settings;
2119

2220
private Clutter.PanAction pan_action;
2321

2422
private bool hovered = false;
2523

26-
private bool overlap = false;
27-
private bool focus_overlap = false;
28-
private bool focus_maximized_overlap = false;
29-
private bool fullscreen_overlap = false;
30-
31-
private Meta.Window current_focus_window;
32-
3324
private Barrier? barrier;
3425

3526
private uint hide_timeout_id = 0;
36-
private uint update_timeout_id = 0;
3727

38-
public HideTracker (Meta.Display display, PanelWindow panel) {
28+
public HideTracker (Meta.Display display, ShellWindow panel) {
3929
Object (display: display, panel: panel);
4030
}
4131

@@ -49,22 +39,6 @@ public class Gala.HideTracker : Object {
4939
// access the panel which was already freed. To prevent that make sure we reset
5040
// the timeouts so that we get freed immediately
5141
reset_hide_timeout ();
52-
reset_update_timeout ();
53-
});
54-
55-
// Can't be local otherwise we get a memory leak :(
56-
// See https://gitlab.gnome.org/GNOME/vala/-/issues/1548
57-
current_focus_window = display.focus_window;
58-
track_focus_window (current_focus_window);
59-
display.notify["focus-window"].connect (() => {
60-
untrack_focus_window (current_focus_window);
61-
current_focus_window = display.focus_window;
62-
track_focus_window (current_focus_window);
63-
});
64-
65-
display.window_created.connect ((window) => {
66-
schedule_update ();
67-
window.unmanaged.connect (schedule_update);
6842
});
6943

7044
#if HAS_MUTTER48
@@ -77,12 +51,15 @@ public class Gala.HideTracker : Object {
7751

7852
if (hovered != has_pointer) {
7953
hovered = has_pointer;
80-
schedule_update ();
54+
55+
if (hovered) {
56+
trigger_show ();
57+
} else {
58+
trigger_hide ();
59+
}
8160
}
8261
});
8362

84-
display.get_workspace_manager ().active_workspace_changed.connect (schedule_update);
85-
8663
pan_action = new Clutter.PanAction () {
8764
n_touch_points = 1,
8865
pan_axis = X_AXIS
@@ -101,144 +78,27 @@ public class Gala.HideTracker : Object {
10178
var monitor_manager = display.get_context ().get_backend ().get_monitor_manager ();
10279
monitor_manager.monitors_changed.connect (() => {
10380
setup_barrier (); //Make sure barriers are still on the primary monitor
104-
schedule_update ();
10581
});
10682

10783
setup_barrier ();
10884
}
10985

110-
111-
private void track_focus_window (Meta.Window? window) {
112-
if (window == null) {
113-
return;
114-
}
115-
116-
window.position_changed.connect (schedule_update);
117-
window.size_changed.connect (schedule_update);
118-
schedule_update ();
119-
}
120-
121-
private void untrack_focus_window (Meta.Window? window) {
122-
if (window == null) {
123-
return;
124-
}
125-
126-
window.position_changed.disconnect (schedule_update);
127-
window.size_changed.disconnect (schedule_update);
128-
schedule_update ();
129-
}
130-
131-
public void schedule_update () {
132-
if (update_timeout_id != 0) {
133-
return;
134-
}
135-
136-
update_timeout_id = Timeout.add (UPDATE_TIMEOUT, () => {
137-
update_overlap ();
138-
update_timeout_id = 0;
139-
return Source.REMOVE;
140-
});
141-
}
142-
143-
private void reset_update_timeout () {
144-
if (update_timeout_id != 0) {
145-
Source.remove (update_timeout_id);
146-
update_timeout_id = 0;
147-
}
148-
}
149-
150-
public void update_overlap () {
151-
overlap = false;
152-
focus_overlap = false;
153-
focus_maximized_overlap = false;
154-
fullscreen_overlap = display.get_monitor_in_fullscreen (panel.window.get_monitor ());
155-
156-
unowned var active_workspace = display.get_workspace_manager ().get_active_workspace ();
157-
158-
Meta.Window? normal_mru_window, any_mru_window;
159-
normal_mru_window = InternalUtils.get_mru_window (active_workspace, out any_mru_window);
160-
161-
foreach (var window in active_workspace.list_windows ()) {
162-
if (window == panel.window) {
163-
continue;
164-
}
165-
166-
if (window.minimized) {
167-
continue;
168-
}
169-
170-
var type = window.get_window_type ();
171-
if (type == DESKTOP || type == DOCK || type == MENU || type == SPLASHSCREEN) {
172-
continue;
173-
}
174-
175-
if (!panel.get_custom_window_rect ().overlap (window.get_frame_rect ())) {
176-
continue;
177-
}
178-
179-
overlap = true;
180-
181-
if (window != normal_mru_window && window != any_mru_window) {
182-
continue;
183-
}
184-
185-
focus_overlap = true;
186-
focus_maximized_overlap = window.maximized_vertically;
187-
}
188-
189-
update_hidden ();
190-
}
191-
192-
private void update_hidden () {
193-
switch (hide_mode) {
194-
case MAXIMIZED_FOCUS_WINDOW:
195-
toggle_display (focus_maximized_overlap);
196-
break;
197-
198-
case OVERLAPPING_FOCUS_WINDOW:
199-
toggle_display (focus_overlap);
200-
break;
201-
202-
case OVERLAPPING_WINDOW:
203-
toggle_display (overlap);
204-
break;
205-
206-
case ALWAYS:
207-
toggle_display (true);
208-
break;
209-
210-
case NEVER:
211-
toggle_display (fullscreen_overlap);
212-
break;
213-
}
214-
}
215-
216-
private void toggle_display (bool should_hide) {
217-
hovered = panel.window.has_pointer ();
218-
219-
// Showing panels in fullscreen is broken in X11
220-
if (should_hide && !hovered && !panel.window.has_focus () || InternalUtils.get_x11_in_fullscreen (display)) {
221-
trigger_hide ();
222-
} else {
223-
trigger_show ();
224-
}
225-
}
226-
22786
private void trigger_hide () {
228-
if (hide_timeout_id != 0) {
229-
return;
230-
}
87+
reset_hide_timeout ();
23188

23289
// Don't hide if we have transients, e.g. an open popover, dialog, etc.
90+
// TODO: this is broken, we should monitor transients for has_pointer and use it instead.
23391
var has_transients = false;
234-
panel.window.foreach_transient (() => {
92+
panel.window.foreach_transient ((transient) => {
93+
if (transient.window_type == DROPDOWN_MENU) {
94+
return true;
95+
}
96+
23597
has_transients = true;
23698
return false;
23799
});
238100

239101
if (has_transients) {
240-
reset_hide_timeout ();
241-
242102
return;
243103
}
244104

@@ -349,9 +209,10 @@ public class Gala.HideTracker : Object {
349209
return;
350210
}
351211

352-
if (hide_mode != NEVER || behavior_settings.get_boolean ("enable-hotcorners-in-fullscreen")) {
212+
if (!display.get_monitor_in_fullscreen (panel.window.get_monitor ()) ||
213+
behavior_settings.get_boolean ("enable-hotcorners-in-fullscreen")
214+
) {
353215
trigger_show ();
354-
schedule_update ();
355216
}
356217
}
357218
}

src/ShellClients/PanelWindow.vala

Lines changed: 2 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,16 @@
11
/*
2-
* Copyright 2024 elementary, Inc. (https://elementary.io)
2+
* Copyright 2024-2025 elementary, Inc. (https://elementary.io)
33
* SPDX-License-Identifier: GPL-3.0-or-later
44
*
55
* Authored by: Leonhard Kargl <[email protected]>
66
*/
77

8-
public class Gala.PanelWindow : ShellWindow, RootTarget {
9-
private static HashTable<Meta.Window, Meta.Strut?> window_struts = new HashTable<Meta.Window, Meta.Strut?> (null, null);
10-
11-
public WindowManager wm { get; construct; }
12-
public Pantheon.Desktop.Anchor anchor { get; construct set; }
13-
14-
public Pantheon.Desktop.HideMode hide_mode {
15-
get {
16-
return hide_tracker.hide_mode;
17-
}
18-
set {
19-
hide_tracker.hide_mode = value;
20-
21-
if (value == NEVER) {
22-
make_exclusive ();
23-
} else {
24-
unmake_exclusive ();
25-
}
26-
}
27-
}
28-
29-
private GestureController gesture_controller;
30-
private HideTracker hide_tracker;
31-
8+
public class Gala.PanelWindow : ShellWindow {
329
public PanelWindow (WindowManager wm, Meta.Window window, Pantheon.Desktop.Anchor anchor) {
3310
Object (wm: wm, anchor: anchor, window: window, position: Position.from_anchor (anchor));
3411
}
3512

3613
construct {
37-
window.unmanaging.connect (() => {
38-
if (window_struts.remove (window)) {
39-
update_struts ();
40-
}
41-
});
42-
4314
notify["anchor"].connect (() => position = Position.from_anchor (anchor));
4415

4516
unowned var workspace_manager = window.display.get_workspace_manager ();
@@ -50,81 +21,10 @@ public class Gala.PanelWindow : ShellWindow, RootTarget {
5021
window.position_changed.connect (update_strut);
5122
notify["width"].connect (update_strut);
5223
notify["height"].connect (update_strut);
53-
54-
gesture_controller = new GestureController (CUSTOM, wm);
55-
add_gesture_controller (gesture_controller);
56-
57-
hide_tracker = new HideTracker (wm.get_display (), this);
58-
hide_tracker.hide.connect (hide);
59-
hide_tracker.show.connect (show);
6024
}
6125

6226
public void request_visible_in_multitasking_view () {
6327
visible_in_multitasking_view = true;
6428
actor.add_action (new DragDropAction (DESTINATION, "multitaskingview-window"));
6529
}
66-
67-
private void hide () {
68-
gesture_controller.goto (1);
69-
}
70-
71-
private void show () {
72-
gesture_controller.goto (0);
73-
}
74-
75-
private void make_exclusive () {
76-
update_strut ();
77-
}
78-
79-
private void update_strut () {
80-
if (hide_mode != NEVER) {
81-
return;
82-
}
83-
84-
var rect = get_custom_window_rect ();
85-
86-
Meta.Strut strut = {
87-
rect,
88-
side_from_anchor (anchor)
89-
};
90-
91-
window_struts[window] = strut;
92-
93-
update_struts ();
94-
}
95-
96-
private void update_struts () {
97-
var list = new SList<Meta.Strut?> ();
98-
99-
foreach (var window_strut in window_struts.get_values ()) {
100-
list.append (window_strut);
101-
}
102-
103-
foreach (var workspace in wm.get_display ().get_workspace_manager ().get_workspaces ()) {
104-
workspace.set_builtin_struts (list);
105-
}
106-
}
107-
108-
private void unmake_exclusive () {
109-
if (window in window_struts) {
110-
window_struts.remove (window);
111-
update_struts ();
112-
}
113-
}
114-
115-
private Meta.Side side_from_anchor (Pantheon.Desktop.Anchor anchor) {
116-
switch (anchor) {
117-
case BOTTOM:
118-
return BOTTOM;
119-
120-
case LEFT:
121-
return LEFT;
122-
123-
case RIGHT:
124-
return RIGHT;
125-
126-
default:
127-
return TOP;
128-
}
129-
}
13030
}

0 commit comments

Comments
 (0)