Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/controlCenter/controlCenter.vala
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,12 @@ namespace SwayNotificationCenter {
if (this.visible == visibility) {
return;
}
// Destroy the wl_surface to get a new "enter-monitor" signal and
// fixes issues where keyboard shortcuts stop working after clearing
// all notifications.
((Gtk.Widget) this).unrealize ();

// NOTE: We removed the unrealize() call that was here.
// It was causing GPU memory leaks on repeated open/close cycles
// because textures had to be re-uploaded each time.
// If keyboard shortcuts stop working after clearing notifications,
// a different fix may be needed (e.g., reset keyboard mode via layer shell).
Comment on lines +379 to +384
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree. This was a temporary hack to fix keyboard input.

This was needed though to know which output the ControlCenter was opened on as the underlying wl_surface doesn't get destroyed / the wl_surface::leave signal isn't called when unmapped. Without a wl_surface::leave, the ::enter signal is only called once for each output, which makes tracking which monitor the ControlCenter is open on impossible.

So please remove this change as it should be in a separate PR


this.set_visible (visibility);

Expand Down
16 changes: 16 additions & 0 deletions src/controlCenter/widgets/mpris/mpris_player.vala
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,20 @@ namespace SwayNotificationCenter.Widgets.Mpris {
album_art.set_visible (mpris_config.show_album_art == AlbumArtState.ALWAYS);
}

public override void dispose () {
before_destroy ();
base.dispose ();
}

public void before_destroy () {
source.properties_changed.disconnect (properties_changed);

// Cancel any ongoing album art download
album_art_cancellable.cancel ();

// Clear album art textures to release VRAM/GPU memory
album_art.clear ();
background_picture.set_paintable (null);
}

private void properties_changed (string iface,
Expand Down Expand Up @@ -264,6 +276,10 @@ namespace SwayNotificationCenter.Widgets.Mpris {
album_art_cancellable.cancel ();
album_art_cancellable.reset ();

// Clear previous textures before loading new ones to release GPU memory
album_art.clear ();
background_picture.set_paintable (null);

Gdk.Texture ?album_art_texture = null;
try {
Uri uri = Uri.parse (art_data, UriFlags.NONE);
Expand Down
44 changes: 39 additions & 5 deletions src/notification/notification.vala
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@ namespace SwayNotificationCenter {

private Notification () {}

public override void dispose () {
// Clear all image resources to release VRAM/GPU memory
img.clear ();
img_app_icon.clear ();
body_image.set_paintable (null);

// Remove any pending timeout
remove_noti_timeout ();

// Clear gesture/controller references
gesture = null;
motion_controller = null;

base.dispose ();
}

/** Show a non-timed notification */
public Notification.regular (NotifyParams param,
NotificationType notification_type) {
Expand Down Expand Up @@ -309,7 +325,8 @@ namespace SwayNotificationCenter {

this.body.set_lines (this.number_of_body_lines);

// Reset state
// Reset state - clear paintable to release GPU memory
body_image.set_paintable (null);
body_image.hide ();

// Removes all image tags and adds them to an array
Expand Down Expand Up @@ -344,8 +361,23 @@ namespace SwayNotificationCenter {
string img = Functions.uri_to_path (img_paths[0]);
File file = File.new_for_path (img);
if (img.length > 0 && file.query_exists ()) {
Gdk.Texture texture = Gdk.Texture.from_file (file);
body_image.set_paintable (texture);
// Clear previous body image to release GPU memory
body_image.set_paintable (null);
Comment thread
bechampion marked this conversation as resolved.
// Load image scaled to display size to save GPU memory
// Full-res images (e.g., 2560x1440 screenshots) waste VRAM
try {
Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_file_at_scale (
img,
notification_body_image_width * get_scale_factor (),
notification_body_image_height * get_scale_factor (),
true); // preserve aspect ratio
Gdk.Texture texture = Gdk.Texture.for_pixbuf (pixbuf);
body_image.set_paintable (texture);
} catch (Error e) {
// Fallback to full-size load if scaling fails
Gdk.Texture texture = Gdk.Texture.from_file (file);
body_image.set_paintable (texture);
}
body_image.set_can_shrink (true);
body_image.set_content_fit (Gtk.ContentFit.SCALE_DOWN);
body_image.width_request = notification_body_image_width;
Expand Down Expand Up @@ -485,7 +517,8 @@ namespace SwayNotificationCenter {
}

private void set_style_urgency () {
// Reset state
// Reset state - clear paintable to release GPU memory
body_image.set_paintable (null);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the paintable here?

base_box.remove_css_class ("low");
base_box.remove_css_class ("normal");
base_box.remove_css_class ("critical");
Expand All @@ -505,7 +538,8 @@ namespace SwayNotificationCenter {
}

private void set_inline_reply () {
// Reset state
// Reset state - clear paintable to release GPU memory
body_image.set_paintable (null);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

inline_reply_box.hide ();
// Only show inline replies in popup notifications if the compositor
// supports ON_DEMAND layer shell keyboard interactivity
Expand Down
18 changes: 18 additions & 0 deletions src/notificationGroup/notificationGroup.vala
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,24 @@ namespace SwayNotificationCenter {
});
}

public override void dispose () {
// Stop and clean up animation to prevent reference cycles
if (remove_animation != null) {
remove_animation.skip ();
if (remove_animation_done_id > 0) {
remove_animation.disconnect (remove_animation_done_id);
remove_animation_done_id = 0;
}
remove_animation = null;
}

// Clear collections
urgent_notifications.clear ();
notification_ids.clear ();

base.dispose ();
}

private void animation_value_changed (double progress) {
queue_resize ();
}
Expand Down
15 changes: 15 additions & 0 deletions src/underlay/underlay.vala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ public class Underlay : Gtk.Widget {
}
}

public override void dispose () {
// Properly unparent children to release resources
if (_underlay_child != null) {
_underlay_child.unparent ();
_underlay_child = null;
}

if (_child != null) {
_child.unparent ();
_child = null;
}

base.dispose ();
}

/*
* Overrides
*/
Expand Down