Skip to content

Commit 2867be1

Browse files
committed
Move notifications out of the way for overlapping dock windows
1 parent 609ea6e commit 2867be1

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

src/NotificationStack.vala

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ public class Gala.NotificationStack : Object {
2828

2929
private const int WIDTH = 300;
3030

31-
private int stack_y;
32-
private int stack_width;
31+
private int offset_stack_y;
32+
33+
private Mtk.Rectangle notification_area = { 0, 0, 0, 0 };
3334

3435
public Meta.Display display { get; construct; }
3536

@@ -46,6 +47,13 @@ public class Gala.NotificationStack : Object {
4647
monitor_manager.monitors_changed_internal.connect (update_stack_allocation);
4748
display.workareas_changed.connect (update_stack_allocation);
4849
update_stack_allocation ();
50+
51+
ShellClientsManager.get_instance ().positioned_window_created.connect ((window) => {
52+
window.size_changed.connect (update_offset_y);
53+
window.position_changed.connect (update_offset_y);
54+
window.unmanaged.connect (update_offset_y);
55+
update_offset_y ();
56+
});
4957
}
5058

5159
public void show_notification (Meta.WindowActor notification, bool animate)
@@ -103,7 +111,7 @@ public class Gala.NotificationStack : Object {
103111
notification_x_pos = 0;
104112
}
105113

106-
move_window (notification, notification_x_pos, stack_y + TOP_OFFSET + InternalUtils.scale_to_int (ADDITIONAL_MARGIN, scale));
114+
move_window (notification, notification_x_pos, offset_stack_y + TOP_OFFSET + InternalUtils.scale_to_int (ADDITIONAL_MARGIN, scale));
107115
notifications.insert (0, notification);
108116
}
109117

@@ -112,13 +120,15 @@ public class Gala.NotificationStack : Object {
112120
var area = display.get_workspace_manager ().get_active_workspace ().get_work_area_for_monitor (primary);
113121

114122
var scale = display.get_monitor_scale (primary);
115-
stack_width = InternalUtils.scale_to_int (WIDTH + MARGIN, scale);
123+
var stack_width = InternalUtils.scale_to_int (WIDTH + MARGIN, scale);
116124

117-
stack_y = area.y;
125+
notification_area.x = area.x + area.width - stack_width;
126+
notification_area.y = area.y;
127+
notification_area.width = stack_width;
118128
}
119129

120130
private void update_positions (bool animate, float scale, float add_y = 0.0f) {
121-
var y = stack_y + TOP_OFFSET + add_y + InternalUtils.scale_to_int (ADDITIONAL_MARGIN, scale);
131+
var y = offset_stack_y + TOP_OFFSET + add_y + InternalUtils.scale_to_int (ADDITIONAL_MARGIN, scale);
122132
var i = notifications.size;
123133
var delay_step = i > 0 ? 150 / i : 0;
124134
var iterator = 0;
@@ -158,6 +168,8 @@ public class Gala.NotificationStack : Object {
158168

159169
y += window.get_frame_rect ().height;
160170
}
171+
172+
notification_area.height = (int) y - notification_area.y;
161173
}
162174

163175
public void destroy_notification (Meta.WindowActor notification, bool animate) {
@@ -167,11 +179,11 @@ public class Gala.NotificationStack : Object {
167179
notification.set_easing_mode (Clutter.AnimationMode.EASE_IN_QUAD);
168180
notification.opacity = 0;
169181

170-
notification.x += stack_width;
182+
notification.x += notification_area.width;
171183
notification.restore_easing_state ();
172184
} else {
173185
notification.opacity = 0;
174-
notification.x += stack_width;
186+
notification.x += notification_area.width;
175187
}
176188

177189
var primary = display.get_primary_monitor ();
@@ -181,6 +193,36 @@ public class Gala.NotificationStack : Object {
181193
update_positions (animate, scale);
182194
}
183195

196+
private void update_offset_y () {
197+
int max_y = notification_area.y;
198+
foreach (var window in display.list_all_windows ()) {
199+
if (!ShellClientsManager.get_instance ().is_positioned_window (window)) {
200+
continue;
201+
}
202+
203+
if (!window.get_frame_rect ().overlap (notification_area)) {
204+
continue;
205+
}
206+
207+
// Ignore windows that are too big to fit even a single notification on screen
208+
// Conveniently this will make us ignore the fullscreen invisible wingpanel window
209+
var primary = display.get_primary_monitor ();
210+
var area = display.get_workspace_manager ().get_active_workspace ().get_work_area_for_monitor (primary);
211+
if (window.get_frame_rect ().height > area.height - notification_area.height / notifications.size) {
212+
continue;
213+
}
214+
215+
max_y = (int) Math.fmax (max_y, window.get_frame_rect ().y + window.get_frame_rect ().height);
216+
}
217+
218+
if (max_y != offset_stack_y) {
219+
offset_stack_y = max_y;
220+
221+
var scale = display.get_monitor_scale (display.get_primary_monitor ());
222+
update_positions (true, scale);
223+
}
224+
}
225+
184226
/**
185227
* This function takes care of properly updating both the actor
186228
* position and the actual window position.

src/ShellClients/ShellClientsManager.vala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ public class Gala.ShellClientsManager : Object {
2020
return instance;
2121
}
2222

23+
/**
24+
* This will be emitted when a window requests to be positioned via the protocol methods
25+
* or if a window that's a transient of a positioned window was created.
26+
*/
27+
public signal void positioned_window_created (Meta.Window window);
28+
2329
public WindowManager wm { get; construct; }
2430

2531
private NotificationsClient notifications_client;
@@ -43,6 +49,12 @@ public class Gala.ShellClientsManager : Object {
4349
parse_mutter_hints (window);
4450
});
4551
}
52+
53+
wm.get_display ().window_created.connect ((window) => {
54+
if (is_positioned_window (window)) {
55+
positioned_window_created (window);
56+
}
57+
});
4658
}
4759

4860
private async void start_clients () {
@@ -156,6 +168,8 @@ public class Gala.ShellClientsManager : Object {
156168

157169
// connect_after so we make sure the PanelWindow can destroy its barriers and struts
158170
window.unmanaging.connect_after (() => windows.remove (window));
171+
172+
positioned_window_created (window);
159173
}
160174

161175
/**
@@ -191,6 +205,8 @@ public class Gala.ShellClientsManager : Object {
191205
centered_windows[window] = new CenteredWindow (wm, window);
192206

193207
window.unmanaging.connect_after (() => centered_windows.remove (window));
208+
209+
positioned_window_created (window);
194210
}
195211

196212
public bool is_positioned_window (Meta.Window window) {

0 commit comments

Comments
 (0)