From f9a39b44803e6347c72c1edd8ba46f633e99dd57 Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Sun, 8 Nov 2020 13:50:13 +0100 Subject: Rewrite to indicator-ng, simplify, drop all GTK references, move to CMake fixes #9, fixes #12 --- src/indicator-notifications.c | 897 ------------------------------------------ 1 file changed, 897 deletions(-) delete mode 100644 src/indicator-notifications.c (limited to 'src/indicator-notifications.c') diff --git a/src/indicator-notifications.c b/src/indicator-notifications.c deleted file mode 100644 index dffa57c..0000000 --- a/src/indicator-notifications.c +++ /dev/null @@ -1,897 +0,0 @@ -/* -An indicator to display recent notifications. - -Adapted from: indicator-datetime/src/indicator-datetime.c by - Ted Gould - -This program is free software: you can redistribute it and/or modify it -under the terms of the GNU General Public License version 3, as published -by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranties of -MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program. If not, see . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* GStuff */ -#include -#include -#include - -/* Indicator Stuff */ -#include -#include -#include - -#include "dbus-spy.h" -#include "notification-menuitem.h" - -#define INDICATOR_NOTIFICATIONS_TYPE (indicator_notifications_get_type ()) -#define INDICATOR_NOTIFICATIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_NOTIFICATIONS_TYPE, IndicatorNotifications)) -#define INDICATOR_NOTIFICATIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_NOTIFICATIONS_TYPE, IndicatorNotificationsClass)) -#define IS_INDICATOR_NOTIFICATIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_NOTIFICATIONS_TYPE)) -#define IS_INDICATOR_NOTIFICATIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_NOTIFICATIONS_TYPE)) -#define INDICATOR_NOTIFICATIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_NOTIFICATIONS_TYPE, IndicatorNotificationsClass)) - -typedef struct _IndicatorNotifications IndicatorNotifications; -typedef struct _IndicatorNotificationsClass IndicatorNotificationsClass; -typedef struct _IndicatorNotificationsPrivate IndicatorNotificationsPrivate; - -struct _IndicatorNotificationsClass { - IndicatorObjectClass parent_class; -}; - -struct _IndicatorNotifications { - IndicatorObject parent; - IndicatorNotificationsPrivate *priv; -}; - -struct _IndicatorNotificationsPrivate { - GtkImage *image; - - GList *visible_items; - GList *hidden_items; - - gboolean clear_on_middle_click; - gboolean do_not_disturb; - gboolean have_unread; - gboolean hide_indicator; - gboolean swap_clear_settings; - - gint max_items; - - GtkMenu *menu; - GtkWidget *clear_item; - GtkWidget *clear_item_label; - GtkWidget *settings_item; - GtkWidget *pSeparator; - - gchar *accessible_desc; - - DBusSpy *spy; - - GHashTable *filter_list; - - GList *filter_list_hints; - - GSettings *settings; -}; - -#include "settings.h" - -#define INDICATOR_ICON_SIZE 22 -#define INDICATOR_ICON_READ "ayatana-indicator-notification-read" -#define INDICATOR_ICON_UNREAD "ayatana-indicator-notification-unread" -#define INDICATOR_ICON_READ_DND "ayatana-indicator-notification-read-dnd" -#define INDICATOR_ICON_UNREAD_DND "ayatana-indicator-notification-unread-dnd" - -#define HINT_MAX 10 - -GType indicator_notifications_get_type(void); - -/* Indicator Class Functions */ -static void indicator_notifications_class_init(IndicatorNotificationsClass *klass); -static void indicator_notifications_init(IndicatorNotifications *self); -static void indicator_notifications_dispose(GObject *object); -static void indicator_notifications_finalize(GObject *object); - -/* Indicator Standard Methods */ -static GtkImage *get_image(IndicatorObject *io); -static GtkMenu *get_menu(IndicatorObject *io); -static const gchar *get_accessible_desc(IndicatorObject *io); -static void indicator_notifications_middle_click(IndicatorObject *io, - IndicatorObjectEntry *entry, - guint time, - gpointer user_data); - -/* Utility Functions */ -static void clear_menuitems(IndicatorNotifications *self); -static void insert_menuitem(IndicatorNotifications *self, GtkWidget *item); -static void remove_menuitem(IndicatorNotifications *self, GtkWidget *item); -static void set_unread(IndicatorNotifications *self, gboolean unread); -static void update_unread(IndicatorNotifications *self); -static void update_filter_list(IndicatorNotifications *self); -static void update_clear_item_markup(IndicatorNotifications *self); -static void update_indicator_visibility(IndicatorNotifications *self); -static void load_filter_list_hints(IndicatorNotifications *self); -static void save_filter_list_hints(IndicatorNotifications *self); -static void update_filter_list_hints(IndicatorNotifications *self, Notification *notification); -static void update_do_not_disturb(IndicatorNotifications *self); -static void settings_try_set_boolean(const gchar *schema, const gchar *key, gboolean value); -static void swap_clear_settings_items(IndicatorNotifications *self); - -/* Callbacks */ -static void clear_item_activated_cb(GtkMenuItem *menuitem, gpointer user_data); -static void menu_visible_notify_cb(GtkWidget *menu, GParamSpec *pspec, gpointer user_data); -static void message_received_cb(DBusSpy *spy, Notification *note, gpointer user_data); -static void notification_clicked_cb(NotificationMenuItem *menuitem, guint button, gpointer user_data); -static void setting_changed_cb(GSettings *settings, gchar *key, gpointer user_data); -static void settings_item_activated_cb(GtkMenuItem *menuitem, gpointer user_data); - -/* Indicator Module Config */ -INDICATOR_SET_VERSION -INDICATOR_SET_TYPE(INDICATOR_NOTIFICATIONS_TYPE) - -G_DEFINE_TYPE_WITH_PRIVATE(IndicatorNotifications, indicator_notifications, INDICATOR_OBJECT_TYPE); - -static void -indicator_notifications_class_init(IndicatorNotificationsClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - setlocale(LC_ALL, ""); - bindtextdomain( GETTEXT_PACKAGE, LOCALEDIR ); - textdomain( GETTEXT_PACKAGE ); - - object_class->dispose = indicator_notifications_dispose; - object_class->finalize = indicator_notifications_finalize; - - IndicatorObjectClass *io_class = INDICATOR_OBJECT_CLASS(klass); - - io_class->get_image = get_image; - io_class->get_menu = get_menu; - io_class->get_accessible_desc = get_accessible_desc; - io_class->secondary_activate = indicator_notifications_middle_click; - - return; -} - -static void -indicator_notifications_init(IndicatorNotifications *self) -{ - self->priv = indicator_notifications_get_instance_private(self); - - self->priv->menu = NULL; - - self->priv->image = NULL; - - self->priv->have_unread = FALSE; - - self->priv->accessible_desc = _("Notifications"); - - self->priv->visible_items = NULL; - self->priv->hidden_items = NULL; - - self->priv->menu = GTK_MENU(gtk_menu_new()); - g_signal_connect(self->priv->menu, "notify::visible", G_CALLBACK(menu_visible_notify_cb), self); - - /* Create the settings menuitem */ - self->priv->settings_item = gtk_menu_item_new_with_label(_("Settingsā€¦")); - g_signal_connect(self->priv->settings_item, "activate", G_CALLBACK(settings_item_activated_cb), NULL); - gtk_widget_show(self->priv->settings_item); - - gtk_menu_shell_prepend(GTK_MENU_SHELL(self->priv->menu), self->priv->settings_item); - - /* Create the clear menuitem */ - self->priv->clear_item_label = gtk_label_new(NULL); - gtk_label_set_xalign(GTK_LABEL(self->priv->clear_item_label), 0); - gtk_label_set_yalign(GTK_LABEL(self->priv->clear_item_label), 0); - gtk_label_set_use_markup(GTK_LABEL(self->priv->clear_item_label), TRUE); - update_clear_item_markup(self); - gtk_widget_show(self->priv->clear_item_label); - - self->priv->clear_item = gtk_menu_item_new(); - g_signal_connect(self->priv->clear_item, "activate", G_CALLBACK(clear_item_activated_cb), self); - gtk_container_add(GTK_CONTAINER(self->priv->clear_item), self->priv->clear_item_label); - gtk_widget_show(self->priv->clear_item); - - gtk_menu_shell_prepend(GTK_MENU_SHELL(self->priv->menu), self->priv->clear_item); - - self->priv->pSeparator = gtk_separator_menu_item_new(); - gtk_menu_shell_prepend(GTK_MENU_SHELL(self->priv->menu), self->priv->pSeparator); - - /* Watch for notifications from dbus */ - self->priv->spy = dbus_spy_new(); - g_signal_connect(self->priv->spy, DBUS_SPY_SIGNAL_MESSAGE_RECEIVED, G_CALLBACK(message_received_cb), self); - - /* Initialize an empty filter list */ - self->priv->filter_list = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - - /* Connect to GSettings */ - self->priv->settings = g_settings_new(NOTIFICATIONS_SCHEMA); - self->priv->clear_on_middle_click = g_settings_get_boolean(self->priv->settings, NOTIFICATIONS_KEY_CLEAR_MC); - self->priv->do_not_disturb = g_settings_get_boolean(self->priv->settings, NOTIFICATIONS_KEY_DND); - self->priv->hide_indicator = g_settings_get_boolean(self->priv->settings, NOTIFICATIONS_KEY_HIDE_INDICATOR); - self->priv->max_items = g_settings_get_int(self->priv->settings, NOTIFICATIONS_KEY_MAX_ITEMS); - update_filter_list(self); - self->priv->swap_clear_settings = g_settings_get_boolean(self->priv->settings, NOTIFICATIONS_KEY_SWAP_CLEAR_SETTINGS); - if(self->priv->swap_clear_settings) - swap_clear_settings_items(self); - g_signal_connect(self->priv->settings, "changed", G_CALLBACK(setting_changed_cb), self); - - /* Set up filter-list hints */ - self->priv->filter_list_hints = NULL; - load_filter_list_hints(self); -} - -static void -indicator_notifications_dispose(GObject *object) -{ - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(object); - - if(self->priv->image != NULL) { - g_object_unref(G_OBJECT(self->priv->image)); - self->priv->image = NULL; - } - - if(self->priv->visible_items != NULL) { - g_list_free_full(self->priv->visible_items, g_object_unref); - self->priv->visible_items = NULL; - } - - if(self->priv->hidden_items != NULL) { - g_list_free_full(self->priv->hidden_items, g_object_unref); - self->priv->hidden_items = NULL; - } - - if(self->priv->menu != NULL) { - g_object_unref(G_OBJECT(self->priv->menu)); - self->priv->menu = NULL; - } - - if(self->priv->spy != NULL) { - g_object_unref(G_OBJECT(self->priv->spy)); - self->priv->spy = NULL; - } - - if(self->priv->settings != NULL) { - g_object_unref(G_OBJECT(self->priv->settings)); - self->priv->settings = NULL; - } - - if(self->priv->filter_list != NULL) { - g_hash_table_unref(self->priv->filter_list); - self->priv->filter_list = NULL; - } - - if(self->priv->filter_list_hints != NULL) { - g_list_free_full(self->priv->filter_list_hints, g_free); - self->priv->filter_list_hints = NULL; - } - - G_OBJECT_CLASS (indicator_notifications_parent_class)->dispose (object); - return; -} - -static void -indicator_notifications_finalize(GObject *object) -{ - G_OBJECT_CLASS (indicator_notifications_parent_class)->finalize (object); - return; -} - -static GtkImage * -get_image(IndicatorObject *io) -{ - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(io); - - if(self->priv->image == NULL) { - self->priv->image = GTK_IMAGE(gtk_image_new()); - /* We have to wait until the image is created to update do-not-disturb the first time */ - update_do_not_disturb(self); - update_indicator_visibility(self); - } - - return self->priv->image; -} - -static GtkMenu * -get_menu(IndicatorObject *io) -{ - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(io); - - return GTK_MENU(self->priv->menu); -} - -static const gchar * -get_accessible_desc(IndicatorObject *io) -{ - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(io); - - return self->priv->accessible_desc; -} - -static void -indicator_notifications_middle_click(IndicatorObject *io, IndicatorObjectEntry *entry, - guint time, gpointer user_data) -{ - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(io); - - /* Clear the notifications */ - if(self->priv->clear_on_middle_click) { - clear_menuitems(self); - set_unread(self, FALSE); - } - /* Otherwise toggle unread status */ - else { - if(g_list_length(self->priv->visible_items) > 0) - set_unread(self, !self->priv->have_unread); - } -} - -/** - * clear_menuitems: - * @self: the indicator - * - * Clear all notification menuitems from the menu and the visible/hidden lists. - **/ -static void -clear_menuitems(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - GList *item; - - /* Remove each visible item from the menu */ - for(item = self->priv->visible_items; item; item = item->next) { - gtk_container_remove(GTK_CONTAINER(self->priv->menu), GTK_WIDGET(item->data)); - } - - /* Clear the lists */ - g_list_free_full(self->priv->visible_items, g_object_unref); - self->priv->visible_items = NULL; - - g_list_free_full(self->priv->hidden_items, g_object_unref); - self->priv->hidden_items = NULL; - - update_clear_item_markup(self); -} - -/** - * insert_menuitem: - * @self: the indicator - * @item: the menuitem to insert - * - * Inserts a menuitem into the indicator's menu and updates the visible and - * hidden lists. - **/ -static void -insert_menuitem(IndicatorNotifications *self, GtkWidget *item) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - g_return_if_fail(GTK_IS_MENU_ITEM(item)); - GList *last_item; - GtkWidget *last_widget; - - /* List holds a ref to the menuitem */ - self->priv->visible_items = g_list_prepend(self->priv->visible_items, g_object_ref(item)); - gtk_menu_shell_prepend(GTK_MENU_SHELL(self->priv->menu), item); - - /* Move items that overflow to the hidden list */ - while(g_list_length(self->priv->visible_items) > self->priv->max_items) { - last_item = g_list_last(self->priv->visible_items); - last_widget = GTK_WIDGET(last_item->data); - /* Steal the ref from the visible list */ - self->priv->visible_items = g_list_delete_link(self->priv->visible_items, last_item); - self->priv->hidden_items = g_list_prepend(self->priv->hidden_items, last_widget); - gtk_container_remove(GTK_CONTAINER(self->priv->menu), last_widget); - last_item = NULL; - last_widget = NULL; - } - - update_clear_item_markup(self); -} - -/** - * remove_menuitem: - * @self: the indicator object - * @item: the menuitem - * - * Removes a menuitem from the indicator menu and the visible list. - **/ -static void -remove_menuitem(IndicatorNotifications *self, GtkWidget *item) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - g_return_if_fail(GTK_IS_MENU_ITEM(item)); - - GList *list_item = g_list_find(self->priv->visible_items, item); - - if(list_item == NULL) { - g_warning("Attempt to remove menuitem not in visible list"); - return; - } - - /* Remove the item */ - gtk_container_remove(GTK_CONTAINER(self->priv->menu), item); - self->priv->visible_items = g_list_delete_link(self->priv->visible_items, list_item); - g_object_unref(item); - - /* Add an item from the hidden list, if available */ - if(g_list_length(self->priv->hidden_items) > 0) { - list_item = g_list_first(self->priv->hidden_items); - GtkWidget *list_widget = GTK_WIDGET(list_item->data); - self->priv->hidden_items = g_list_delete_link(self->priv->hidden_items, list_item); - gtk_menu_shell_insert(GTK_MENU_SHELL(self->priv->menu), list_widget, - g_list_length(self->priv->visible_items)); - /* Steal the ref back from the hidden list */ - self->priv->visible_items = g_list_append(self->priv->visible_items, list_widget); - } - - update_clear_item_markup(self); -} - -/** - * set_unread: - * @self: the indicator object - * @unread: the unread status - * - * Sets the unread status of the indicator and updates the icons. - **/ -static void -set_unread(IndicatorNotifications *self, gboolean unread) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - - self->priv->have_unread = unread; - update_unread(self); -} - -/** - * update_unread: - * @self: the indicator object - * - * Updates the indicator icons. - **/ -static void -update_unread(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - - if(self->priv->have_unread) { - if (self->priv->do_not_disturb) { - gtk_image_set_from_icon_name(self->priv->image, INDICATOR_ICON_UNREAD_DND, GTK_ICON_SIZE_MENU); - } - else { - gtk_image_set_from_icon_name(self->priv->image, INDICATOR_ICON_UNREAD, GTK_ICON_SIZE_MENU); - } - } - else { - if (self->priv->do_not_disturb) { - gtk_image_set_from_icon_name(self->priv->image, INDICATOR_ICON_READ_DND, GTK_ICON_SIZE_MENU); - } - else { - gtk_image_set_from_icon_name(self->priv->image, INDICATOR_ICON_READ, GTK_ICON_SIZE_MENU); - } - } -} - -/** - * update_filter_list: - * @self: the indicator object - * - * Updates the filter list from GSettings. This currently does not filter already - * allowed messages. It only applies to messages received in the future. - **/ -static void -update_filter_list(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - g_return_if_fail(self->priv->filter_list != NULL); - - g_hash_table_remove_all(self->priv->filter_list); - gchar **items = g_settings_get_strv(self->priv->settings, NOTIFICATIONS_KEY_FILTER_LIST); - int i; - - for(i = 0; items[i] != NULL; i++) { - g_hash_table_insert(self->priv->filter_list, g_strdup(items[i]), NULL); - } - - g_strfreev(items); -} - -/** - * update_clear_item_markup: - * @self: the indicator object - * - * Updates the clear menuitem's label markup based on the number of - * notifications available. - **/ -static void -update_clear_item_markup(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - guint visible_length = g_list_length(self->priv->visible_items); - guint hidden_length = g_list_length(self->priv->hidden_items); - guint total_length = visible_length + hidden_length; - - gchar *markup = g_strdup_printf(ngettext( - "Clear (%d Notification)", - "Clear (%d Notifications)", - total_length), - total_length); - - gtk_label_set_markup(GTK_LABEL(self->priv->clear_item_label), markup); - g_free(markup); - - if (total_length == 0) - { - gtk_widget_hide(self->priv->pSeparator); - gtk_menu_shell_deactivate(GTK_MENU_SHELL(self->priv->menu)); - } - else - { - gtk_widget_show(self->priv->pSeparator); - } -} - -/** - * update_indicator_visibility: - * @self: the indicator object - * - * Changes the visibility of the indicator image based on the value - * of hide_indicator. - **/ -static void -update_indicator_visibility(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - - if(self->priv->image != NULL) { - if(self->priv->hide_indicator) - gtk_widget_hide(GTK_WIDGET(self->priv->image)); - else - gtk_widget_show(GTK_WIDGET(self->priv->image)); - } -} - -/** - * load_filter_list_hints: - * @self: the indicator object - * - * Loads the filter list hints from gsettings - **/ -static void -load_filter_list_hints(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - g_return_if_fail(self->priv->filter_list_hints == NULL); - - gchar **items = g_settings_get_strv(self->priv->settings, NOTIFICATIONS_KEY_FILTER_LIST_HINTS); - int i; - - for (i = 0; items[i] != NULL; i++) { - self->priv->filter_list_hints = g_list_prepend(self->priv->filter_list_hints, items[i]); - } - - g_free(items); -} - -/** - * save_filter_list_hints: - * @self: the indicator object - * - * Saves the filter list hints to gsettings - **/ -static void -save_filter_list_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->filter_list_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_FILTER_LIST_HINTS, (const gchar **) hints); -} - -/** - * update_filter_list_hints: - * @self: the indicator object - * - * Adds an application name to the hints - **/ -static void -update_filter_list_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->filter_list_hints; l != NULL; l = l->next) { - if (g_strcmp0(appname, (const gchar *) l->data) == 0) - return; - } - - /* Add the appname */ - self->priv->filter_list_hints = g_list_prepend(self->priv->filter_list_hints, g_strdup(appname)); - - /* Keep only a reasonable number */ - while (g_list_length(self->priv->filter_list_hints) > HINT_MAX) { - GList *last = g_list_last(self->priv->filter_list_hints); - g_free(last->data); - self->priv->filter_list_hints = g_list_delete_link(self->priv->filter_list_hints, last); - } - - /* Save the hints */ - /* FIXME: maybe don't do this every update */ - save_filter_list_hints(self); -} - -/** - * update_do_not_disturb: - * @self: the indicator object - * - * Updates the icon with the do-not-disturb version and sets do-not-disturb options - * on external notification daemons that are supported. - **/ -static void -update_do_not_disturb(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - - update_unread(self); - - /* Mate do-not-disturb support */ - settings_try_set_boolean(MATE_SCHEMA, MATE_KEY_DND, self->priv->do_not_disturb); -} - -/** - * settings_try_set_boolean: - * @schema: the GSettings schema - * @key: the GSettings key - * @value: the boolean value - * - * Checks to see if the schema and key exist before setting the value. - */ -static void -settings_try_set_boolean(const gchar *schema, const gchar *key, gboolean value) -{ - /* Check if we can access the schema */ - GSettingsSchemaSource *source = g_settings_schema_source_get_default(); - if (source == NULL) { - return; - } - - /* Lookup the schema */ - GSettingsSchema *source_schema = g_settings_schema_source_lookup(source, schema, TRUE); - - /* Couldn't find the schema */ - if (source_schema == NULL) { - return; - } - - /* Found the schema, make sure we have the key */ - if (g_settings_schema_has_key(source_schema, key)) { - /* Make sure the key is of boolean type */ - GSettingsSchemaKey *source_key = g_settings_schema_get_key(source_schema, key); - - if (g_variant_type_equal(g_settings_schema_key_get_value_type(source_key), G_VARIANT_TYPE_BOOLEAN)) { - /* Set the value */ - GSettings *settings = g_settings_new(schema); - g_settings_set_boolean(settings, key, value); - g_object_unref(settings); - } - - g_settings_schema_key_unref(source_key); - } - g_settings_schema_unref(source_schema); -} - -/** - * swap_clear_settings_items: - * @self: the indicator object - * - * Swaps the position of the clear and settings items. - **/ -static void -swap_clear_settings_items(IndicatorNotifications *self) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(self)); - - // Pick which widget to move - GtkWidget *widget = self->priv->settings_item; - if(self->priv->swap_clear_settings) - widget = self->priv->clear_item; - - gtk_container_remove(GTK_CONTAINER(self->priv->menu), g_object_ref(widget)); - gtk_menu_shell_append(GTK_MENU_SHELL(self->priv->menu), widget); - g_object_unref(widget); -} - -/** - * clear_item_activated_cb: - * @menuitem: the clear menuitem - * @user_data: the indicator object - * - * Called when the clear menuitem is activated. - **/ -static void -clear_item_activated_cb(GtkMenuItem *menuitem, gpointer user_data) -{ - g_return_if_fail(GTK_IS_MENU_ITEM(menuitem)); - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(user_data)); - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(user_data); - - clear_menuitems(self); -} - -/** - * settings_item_activated_cb: - * @menuitem: the settings menuitem - * @user_data: the indicator object - * - * Called when the settings menuitem is activated. - **/ -static void -settings_item_activated_cb(GtkMenuItem *menuitem, gpointer user_data) -{ - g_return_if_fail(GTK_IS_MENU_ITEM(menuitem)); - - GError *error = NULL; - - gchar *argv[] = { SETTINGS_PATH, NULL }; - - GPid pid; - - g_spawn_async(NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, &pid, &error); - - if (error != NULL) { - g_message("%s", error->message); - g_error_free(error); - } - else { - g_spawn_close_pid(pid); - } -} - -/** - * setting_changed_cb: - * @settings: the GSettings object - * @key: the GSettings key - * @user_data: the indicator object - * - * Called when a GSettings key is changed. - **/ -static void -setting_changed_cb(GSettings *settings, gchar *key, gpointer user_data) -{ - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(user_data)); - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(user_data); - - if(g_strcmp0(key, NOTIFICATIONS_KEY_HIDE_INDICATOR) == 0) { - self->priv->hide_indicator = g_settings_get_boolean(settings, NOTIFICATIONS_KEY_HIDE_INDICATOR); - update_indicator_visibility(self); - } - else if(g_strcmp0(key, NOTIFICATIONS_KEY_DND) == 0) { - self->priv->do_not_disturb = g_settings_get_boolean(settings, NOTIFICATIONS_KEY_DND); - update_do_not_disturb(self); - } - else if(g_strcmp0(key, NOTIFICATIONS_KEY_CLEAR_MC) == 0) { - self->priv->clear_on_middle_click = g_settings_get_boolean(self->priv->settings, NOTIFICATIONS_KEY_CLEAR_MC); - } - else if(g_strcmp0(key, NOTIFICATIONS_KEY_FILTER_LIST) == 0) { - update_filter_list(self); - } - else if(g_strcmp0(key, NOTIFICATIONS_KEY_SWAP_CLEAR_SETTINGS) == 0) { - self->priv->swap_clear_settings = g_settings_get_boolean(self->priv->settings, NOTIFICATIONS_KEY_SWAP_CLEAR_SETTINGS); - swap_clear_settings_items(self); - } - /* TODO: Trim or extend the notifications list based on "max-items" key - * (Currently requires a restart) */ -} - -/** - * menu_visible_notify_cb: - * @menu: the menu - * @pspec: unused - * @user_data: the indicator object - * - * Called when the indicator's menu is shown or hidden. - **/ -static void -menu_visible_notify_cb(GtkWidget *menu, G_GNUC_UNUSED GParamSpec *pspec, gpointer user_data) -{ - g_return_if_fail(GTK_IS_MENU(menu)); - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(user_data)); - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(user_data); - - gboolean visible; - g_object_get(G_OBJECT(menu), "visible", &visible, NULL); - if(!visible) { - set_unread(self, FALSE); - } -} - -/** - * message_received_cb: - * @spy: the dbus notification monitor - * @note: the notification received - * @user_data: the indicator object - * - * Called when a notification arrives on dbus. - **/ -static void -message_received_cb(DBusSpy *spy, Notification *note, gpointer user_data) -{ - g_return_if_fail(IS_DBUS_SPY(spy)); - g_return_if_fail(IS_NOTIFICATION(note)); - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(user_data)); - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(user_data); - - /* Discard notifications if we are hidden */ - if(self->priv->hide_indicator) { - g_object_unref(note); - return; - } - - /* Discard useless notifications */ - if(notification_is_private(note) || notification_is_empty(note)) { - g_object_unref(note); - return; - } - - /* Discard notifications on the filter list */ - if(self->priv->filter_list != NULL && g_hash_table_contains(self->priv->filter_list, - notification_get_app_name(note))) { - g_object_unref(note); - return; - } - - /* Save a hint for the appname */ - update_filter_list_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); - gtk_widget_show(item); - g_object_unref(note); - - insert_menuitem(self, item); - - set_unread(self, TRUE); -} - -/** - * notification_clicked_cb: - * @widget: the menuitem - * @user_data: the indicator object - * - * Remove the menuitem when clicked. - **/ -static void -notification_clicked_cb(NotificationMenuItem *menuitem, guint button, gpointer user_data) -{ - g_return_if_fail(IS_NOTIFICATION_MENUITEM(menuitem)); - g_return_if_fail(IS_INDICATOR_NOTIFICATIONS(user_data)); - IndicatorNotifications *self = INDICATOR_NOTIFICATIONS(user_data); - - remove_menuitem(self, GTK_WIDGET(menuitem)); -} -- cgit v1.2.3