From e4bf77f46267730d5c2e771b5dcef6a338eaf88e Mon Sep 17 00:00:00 2001 From: Jason Conti Date: Thu, 20 Aug 2020 09:32:00 +0200 Subject: Add blacklist hints for recent application names. --- ...atana.indicator.notifications.gschema.xml.in.in | 5 + src/indicator-notifications-settings.c | 43 +++++++++ src/indicator-notifications.c | 102 +++++++++++++++++++++ src/settings.h | 11 ++- 4 files changed, 156 insertions(+), 5 deletions(-) diff --git a/data/org.ayatana.indicator.notifications.gschema.xml.in.in b/data/org.ayatana.indicator.notifications.gschema.xml.in.in index 95eb284..c7b6277 100644 --- a/data/org.ayatana.indicator.notifications.gschema.xml.in.in +++ b/data/org.ayatana.indicator.notifications.gschema.xml.in.in @@ -5,6 +5,11 @@ <_summary>Discard notifications by application name <_description>If an application name is in the blacklist, all notifications matching the application name will be discarded. + + [] + Recent application names to suggest for the blacklist + Keeps track of recent application names so we can suggest them in the settings. + false <_summary>Clear notifications on middle click diff --git a/src/indicator-notifications-settings.c b/src/indicator-notifications-settings.c index 439413e..b01a709 100644 --- a/src/indicator-notifications-settings.c +++ b/src/indicator-notifications-settings.c @@ -44,6 +44,7 @@ static void indicator_notifications_settings_activate(GApplication *app); /* Utility Functions */ static void load_blacklist(IndicatorNotificationsSettings *self); +static void load_blacklist_hints(IndicatorNotificationsSettings *self); static void save_blacklist(IndicatorNotificationsSettings *self); static gboolean foreach_check_duplicates(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data); @@ -55,6 +56,7 @@ static void blacklist_add_clicked_cb(GtkButton *button, gpointer user_data); static void blacklist_remove_clicked_cb(GtkButton *button, gpointer user_data); static void button_toggled_cb(GtkToggleButton *button, gpointer user_data); static void max_items_changed_cb(GtkSpinButton *button, gpointer user_data); +static gboolean blacklist_entry_focus_in_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data); static void load_blacklist(IndicatorNotificationsSettings *self) @@ -75,6 +77,26 @@ load_blacklist(IndicatorNotificationsSettings *self) g_strfreev(items); } +static void +load_blacklist_hints(IndicatorNotificationsSettings *self) +{ + GtkEntryCompletion *completion = gtk_entry_get_completion(GTK_ENTRY(self->blacklist_entry)); + GtkListStore *list = GTK_LIST_STORE(gtk_entry_completion_get_model(completion)); + GtkTreeIter iter; + gchar **items; + + gtk_list_store_clear(list); + + items = g_settings_get_strv(self->settings, NOTIFICATIONS_KEY_BLACKLIST_HINTS); + + for (int i = 0; items[i] != NULL; i++) { + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, 0, items[i], -1); + } + + g_strfreev(items); +} + static void save_blacklist(IndicatorNotificationsSettings *self) { @@ -191,6 +213,15 @@ max_items_changed_cb(GtkSpinButton *button, gpointer user_data) g_settings_set_int(settings, NOTIFICATIONS_KEY_MAX_ITEMS, value); } +static gboolean +blacklist_entry_focus_in_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) +{ + IndicatorNotificationsSettings *self = (IndicatorNotificationsSettings *) user_data; + load_blacklist_hints(self); + g_signal_emit_by_name(widget, "changed", NULL); + return FALSE; +} + static void indicator_notifications_settings_activate(GApplication *app) { @@ -209,6 +240,8 @@ indicator_notifications_settings_activate(GApplication *app) GtkWidget *hbox; GtkWidget *button_3; GtkWidget *button_4; + GtkEntryCompletion *entry_completion; + GtkListStore *entry_list; IndicatorNotificationsSettings *self = (IndicatorNotificationsSettings *) app; @@ -309,6 +342,16 @@ indicator_notifications_settings_activate(GApplication *app) self->blacklist_entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), self->blacklist_entry, TRUE, TRUE, 0); gtk_widget_show(self->blacklist_entry); + + entry_completion = gtk_entry_completion_new(); + entry_list = gtk_list_store_new(1, G_TYPE_STRING); + gtk_entry_completion_set_model(entry_completion, GTK_TREE_MODEL(entry_list)); + gtk_entry_completion_set_text_column(entry_completion, 0); + gtk_entry_completion_set_minimum_key_length(entry_completion, 0); + gtk_entry_set_completion(GTK_ENTRY(self->blacklist_entry), entry_completion); + /* When we focus the entry, emit the changed signal so we get the hints immediately */ + /* also update the blacklist hints from gsettings */ + g_signal_connect(self->blacklist_entry, "focus-in-event", G_CALLBACK(blacklist_entry_focus_in_cb), self); } static void diff --git a/src/indicator-notifications.c b/src/indicator-notifications.c index 07ccd26..ab9e900 100644 --- a/src/indicator-notifications.c +++ b/src/indicator-notifications.c @@ -77,6 +77,8 @@ struct _IndicatorNotificationsPrivate { GHashTable *blacklist; + GList *blacklist_hints; + GSettings *settings; }; @@ -86,6 +88,8 @@ struct _IndicatorNotificationsPrivate { #define INDICATOR_ICON_READ "ayatana-indicator-notification-read" #define INDICATOR_ICON_UNREAD "ayatana-indicator-notification-unread" +#define HINT_MAX 10 + GType indicator_notifications_get_type(void); /* Indicator Class Functions */ @@ -111,6 +115,9 @@ static void set_unread(IndicatorNotifications *self, gboolean unread); static void update_blacklist(IndicatorNotifications *self); static void update_clear_item_markup(IndicatorNotifications *self); static void update_indicator_visibility(IndicatorNotifications *self); +static void load_blacklist_hints(IndicatorNotifications *self); +static void save_blacklist_hints(IndicatorNotifications *self); +static void update_blacklist_hints(IndicatorNotifications *self, Notification *notification); /* Callbacks */ static void clear_item_activated_cb(GtkMenuItem *menuitem, gpointer user_data); @@ -203,6 +210,10 @@ indicator_notifications_init(IndicatorNotifications *self) self->priv->max_items = g_settings_get_int(self->priv->settings, NOTIFICATIONS_KEY_MAX_ITEMS); update_blacklist(self); g_signal_connect(self->priv->settings, "changed", G_CALLBACK(setting_changed_cb), self); + + /* Set up blacklist hints */ + self->priv->blacklist_hints = NULL; + load_blacklist_hints(self); } static void @@ -245,6 +256,11 @@ indicator_notifications_dispose(GObject *object) self->priv->blacklist = NULL; } + if(self->priv->blacklist_hints != NULL) { + g_list_free_full(self->priv->blacklist_hints, g_free); + self->priv->blacklist_hints = NULL; + } + G_OBJECT_CLASS (indicator_notifications_parent_class)->dispose (object); return; } @@ -500,6 +516,88 @@ update_indicator_visibility(IndicatorNotifications *self) } } +/** + * load_blacklist_hints: + * @self: the indicator object + * + * Loads the blacklist hints from gsettings + **/ +static void +load_blacklist_hints(IndicatorNotifications *self) +{ + g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); + g_return_if_fail(self->priv->blacklist_hints == NULL); + + gchar **items = g_settings_get_strv(self->priv->settings, NOTIFICATIONS_KEY_BLACKLIST_HINTS); + int i; + + for (i = 0; items[i] != NULL; i++) { + self->priv->blacklist_hints = g_list_prepend(self->priv->blacklist_hints, items[i]); + } + + g_free(items); +} + +/** + * save_blacklist_hints: + * @self: the indicator object + * + * Saves the blacklist hints to gsettings + **/ +static void +save_blacklist_hints(IndicatorNotifications *self) +{ + g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); + + gchar *hints[HINT_MAX + 1]; + int i = 0; + + GList *l; + for (l = self->priv->blacklist_hints; (l != NULL) && (i < HINT_MAX); l = l->next, i++) { + hints[i] = (gchar *) l->data; + } + + hints[i] = NULL; + + g_settings_set_strv(self->priv->settings, NOTIFICATIONS_KEY_BLACKLIST_HINTS, (const gchar **) hints); +} + +/** + * update_blacklist_hints: + * @self: the indicator object + * + * Adds an application name to the hints + **/ +static void +update_blacklist_hints(IndicatorNotifications *self, Notification *notification) +{ + g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); + g_return_if_fail(IS_NOTIFICATION(notification)); + + const gchar *appname = notification_get_app_name(notification); + + /* Avoid duplicates */ + GList *l; + for (l = self->priv->blacklist_hints; l != NULL; l = l->next) { + if (g_strcmp0(appname, (const gchar *) l->data) == 0) + return; + } + + /* Add the appname */ + self->priv->blacklist_hints = g_list_prepend(self->priv->blacklist_hints, g_strdup(appname)); + + /* Keep only a reasonable number */ + while (g_list_length(self->priv->blacklist_hints) > HINT_MAX) { + GList *last = g_list_last(self->priv->blacklist_hints); + g_free(last->data); + self->priv->blacklist_hints = g_list_delete_link(self->priv->blacklist_hints, last); + } + + /* Save the hints */ + /* FIXME: maybe don't do this every update */ + save_blacklist_hints(self); +} + /** * clear_item_activated_cb: * @menuitem: the clear menuitem @@ -625,6 +723,10 @@ message_received_cb(DBusSpy *spy, Notification *note, gpointer user_data) return; } + /* Save a hint for the appname */ + update_blacklist_hints(self, note); + + /* Create the menuitem */ GtkWidget *item = notification_menuitem_new(); notification_menuitem_set_from_notification(NOTIFICATION_MENUITEM(item), note); g_signal_connect(item, NOTIFICATION_MENUITEM_SIGNAL_CLICKED, G_CALLBACK(notification_clicked_cb), self); diff --git a/src/settings.h b/src/settings.h index 87e341f..53b9780 100644 --- a/src/settings.h +++ b/src/settings.h @@ -5,10 +5,11 @@ #ifndef __SETTINGS_H__ #define __SETTINGS_H__ -#define NOTIFICATIONS_SCHEMA "org.ayatana.indicator.notifications" -#define NOTIFICATIONS_KEY_BLACKLIST "blacklist" -#define NOTIFICATIONS_KEY_CLEAR_MC "clear-on-middle-click" -#define NOTIFICATIONS_KEY_HIDE_INDICATOR "hide-indicator" -#define NOTIFICATIONS_KEY_MAX_ITEMS "max-items" +#define NOTIFICATIONS_SCHEMA "org.ayatana.indicator.notifications" +#define NOTIFICATIONS_KEY_BLACKLIST "blacklist" +#define NOTIFICATIONS_KEY_BLACKLIST_HINTS "blacklist-hints" +#define NOTIFICATIONS_KEY_CLEAR_MC "clear-on-middle-click" +#define NOTIFICATIONS_KEY_HIDE_INDICATOR "hide-indicator" +#define NOTIFICATIONS_KEY_MAX_ITEMS "max-items" #endif -- cgit v1.2.3