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
88public 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}
0 commit comments