From da33ba4fbbe01f5998fb049fa3c868a9f934c11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 6 Sep 2026 20:57:26 -0700 Subject: [PATCH 1/3] Indicator: add clear-app action --- src/Indicator.vala | 25 +++++++++++++++++++++++-- src/Widgets/ListHeader.vala | 26 ++++++++++++++------------ src/Widgets/NotificationsList.vala | 16 ---------------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/Indicator.vala b/src/Indicator.vala index e802a672..437f6cdc 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -13,6 +13,7 @@ public class Notifications.Indicator : Wingpanel.Indicator { private static GLib.Settings? keybinding_settings; private Gee.HashMap app_settings_cache; private GLib.Settings notify_settings; + private SimpleActionGroup action_group; private GLib.ListStore list_store; private Gtk.SortListModel sort_list_model; @@ -57,6 +58,12 @@ public class Notifications.Indicator : Wingpanel.Indicator { add_entry (notification); } }); + + var clear_app_action = new SimpleAction ("clear-app", VariantType.STRING); + clear_app_action.activate.connect (clear_app); + + action_group = new SimpleActionGroup (); + action_group.add_action (clear_app_action); } public override Gtk.Widget get_display_widget () { @@ -108,6 +115,7 @@ public class Notifications.Indicator : Wingpanel.Indicator { nlist.clear_all.connect (clear_all); nlist.close_popover.connect (() => close ()); nlist.remove_notification.connect (remove_notification); + nlist.insert_action_group (Wingpanel.Indicator.MESSAGES, action_group); } return nlist; @@ -147,14 +155,14 @@ public class Notifications.Indicator : Wingpanel.Indicator { } private void remove_notification (Notification notification) { - var app_id = notification.desktop_id; + Session.get_instance ().remove_notification (notification); uint pos = -1; if (list_store.find (notification, out pos)) { list_store.remove (pos); - Session.get_instance ().remove_notification (notification); } + var app_id = notification.desktop_id; var items_for_appid = new Gtk.FilterListModel ( list_store, new Gtk.CustomFilter ((item) => { return ((Notification) item).desktop_id == app_id; @@ -190,6 +198,19 @@ public class Notifications.Indicator : Wingpanel.Indicator { close (); } + private void clear_app (SimpleAction action, Variant? parameter) { + var app_id = parameter.get_string (); + for (int i = 0; i < list_store.n_items; i++) { + var notification = (Notification) list_store.get_item (i); + if (notification.desktop_id == app_id) { + // Wait so that the header won't be removed before its animation finishes + Timeout.add_once (600, () => { + remove_notification (notification); + }); + } + } + } + private void set_display_icon_name () { if (notify_settings.get_boolean ("do-not-disturb")) { dynamic_icon.state = NotificationsIndicator.SymbolState.DISABLED; diff --git a/src/Widgets/ListHeader.vala b/src/Widgets/ListHeader.vala index cb5e1ca3..8656bd97 100644 --- a/src/Widgets/ListHeader.vala +++ b/src/Widgets/ListHeader.vala @@ -4,8 +4,6 @@ */ public class Notifications.ListHeader : Granite.Bin { - public signal void clear (); - private string _app_id = ""; public string app_id { get { @@ -14,6 +12,11 @@ public class Notifications.ListHeader : Granite.Bin { set { _app_id = value; + if (value != null) { + clear_btn_entry.action_target = new Variant.string (value); + } + + if (value in headers) { expander.active = headers[value]; } @@ -26,6 +29,7 @@ public class Notifications.ListHeader : Granite.Bin { private static Settings settings; private static HashTable headers; + private Gtk.Button clear_btn_entry; private Gtk.ToggleButton expander; static construct { @@ -64,7 +68,8 @@ public class Notifications.ListHeader : Granite.Bin { var clear_btn_image = new Gtk.Image.from_icon_name ("edit-clear-all-symbolic"); clear_btn_image.add_css_class ("sweep-animation"); - var clear_btn_entry = new Gtk.Button () { + clear_btn_entry = new Gtk.Button () { + action_name = Wingpanel.Indicator.MESSAGES + ".clear-app", tooltip_text = _("Clear all %s notifications").printf (app_name), child = clear_btn_image, has_frame = false @@ -80,11 +85,12 @@ public class Notifications.ListHeader : Granite.Bin { bind_property ("app-name", label, "label"); bind_property ("app-name", clear_btn_entry, "tooltip-text", DEFAULT, - (binding, _app_name, ref _tooltip_text) => { - _tooltip_text = _("Clear all %s notifications").printf ((string) _app_name); - return true; - }, - () => { return false; }); + (binding, _app_name, ref _tooltip_text) => { + _tooltip_text = _("Clear all %s notifications").printf ((string) _app_name); + return true; + }, + () => { return false; } + ); expander.toggled.connect (() => { headers[app_id] = expander.active; @@ -93,10 +99,6 @@ public class Notifications.ListHeader : Granite.Bin { clear_btn_entry.clicked.connect (() => { clear_btn_image.add_css_class ("active"); - GLib.Timeout.add (600, () => { - clear (); // Causes notification list to destroy this app entry after clearing its notification entries - return GLib.Source.REMOVE; - }); }); expander.bind_property ("active", image, "tooltip-text", SYNC_CREATE, (binding, srcval, ref targetval) => { diff --git a/src/Widgets/NotificationsList.vala b/src/Widgets/NotificationsList.vala index db205dfd..e21bac82 100644 --- a/src/Widgets/NotificationsList.vala +++ b/src/Widgets/NotificationsList.vala @@ -126,7 +126,6 @@ public class Notifications.NotificationsList : Granite.Bin { private void setup_header_factory (Object item) { var app_entry = new ListHeader (); - app_entry.clear.connect (clear_app_entry); ((Gtk.ListHeader) item).child = app_entry; } @@ -153,21 +152,6 @@ public class Notifications.NotificationsList : Granite.Bin { }); } - private void clear_app_entry (ListHeader app_entry) { - app_entry.clear.disconnect (clear_app_entry); - - Notification[] to_remove = {}; - for (int i = 0; i < list_model.get_n_items (); i++) { - var notification = (Notification) list_model.get_item (i); - if (notification.desktop_id == app_entry.app_id) { - notification.server_id = 0; - to_remove += notification; - } - } - - Session.get_instance ().remove_notifications (to_remove); - } - private void on_items_changed () { if (list_model.get_n_items () == 0) { stack.visible_child_name = "placeholder"; From ade4dc22349dee8d2068af6d7032f96460d17eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 6 Sep 2026 21:00:34 -0700 Subject: [PATCH 2/3] more compact setup header --- src/Widgets/NotificationsList.vala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Widgets/NotificationsList.vala b/src/Widgets/NotificationsList.vala index e21bac82..f9094446 100644 --- a/src/Widgets/NotificationsList.vala +++ b/src/Widgets/NotificationsList.vala @@ -125,9 +125,7 @@ public class Notifications.NotificationsList : Granite.Bin { } private void setup_header_factory (Object item) { - var app_entry = new ListHeader (); - - ((Gtk.ListHeader) item).child = app_entry; + ((Gtk.ListHeader) item).child = new ListHeader (); } private void bind_header_factory (Object item) { From 7512e953cdd0b5ba3f8b0589af7b78a6865c364f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Sun, 6 Sep 2026 21:01:23 -0700 Subject: [PATCH 3/3] Fix weird indent --- src/Widgets/ListHeader.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Widgets/ListHeader.vala b/src/Widgets/ListHeader.vala index 8656bd97..3b24421d 100644 --- a/src/Widgets/ListHeader.vala +++ b/src/Widgets/ListHeader.vala @@ -69,7 +69,7 @@ public class Notifications.ListHeader : Granite.Bin { clear_btn_image.add_css_class ("sweep-animation"); clear_btn_entry = new Gtk.Button () { - action_name = Wingpanel.Indicator.MESSAGES + ".clear-app", + action_name = Wingpanel.Indicator.MESSAGES + ".clear-app", tooltip_text = _("Clear all %s notifications").printf (app_name), child = clear_btn_image, has_frame = false