diff options
author | Gary Kramlich <grim@reaperworld.com> | 2022-06-30 20:24:09 -0500 |
---|---|---|
committer | Gary Kramlich <grim@reaperworld.com> | 2022-06-30 20:24:09 -0500 |
commit | d4a16d165a9def887afc904de644249d15126877 (patch) | |
tree | f28aa7a7217bc8066a752c971a1dd7ca17f369c7 | |
parent | d5ab801a360aad629ab52aacb516bfea5b54346d (diff) | |
download | pidgin-d4a16d165a9def887afc904de644249d15126877.tar.gz |
Create and add notifications for account errors.
Adjust the NotificationManager API a bit to be easier to use and map better to
GListStore which the manager is now using internally.
Testing Done:
Ran the unit tests and forced a connection error and verified no issues (used gdb to verify that item was added).
Bugs closed: PIDGIN-17639
Reviewed at https://reviews.imfreedom.org/r/1509/
-rw-r--r-- | libpurple/account.c | 20 | ||||
-rw-r--r-- | libpurple/purplenotification.c | 23 | ||||
-rw-r--r-- | libpurple/purplenotification.h | 17 | ||||
-rw-r--r-- | libpurple/purplenotificationmanager.c | 53 | ||||
-rw-r--r-- | libpurple/purplenotificationmanager.h | 7 | ||||
-rw-r--r-- | libpurple/tests/test_notification_manager.c | 13 |
6 files changed, 87 insertions, 46 deletions
diff --git a/libpurple/account.c b/libpurple/account.c index 33534e6fef..1a657cfa3b 100644 --- a/libpurple/account.c +++ b/libpurple/account.c @@ -33,6 +33,8 @@ #include "purpleaccountpresence.h" #include "purpleconversationmanager.h" #include "purplecredentialmanager.h" +#include "purplenotification.h" +#include "purplenotificationmanager.h" #include "purpleprivate.h" #include "purpleprotocolclient.h" #include "purpleprotocolmanager.h" @@ -100,6 +102,7 @@ typedef struct void *registration_cb_user_data; PurpleConnectionErrorInfo *current_error; /* Errors */ + PurpleNotification *error_notification; } PurpleAccountPrivate; typedef struct @@ -520,6 +523,7 @@ _purple_account_set_current_error(PurpleAccount *account, { PurpleConnectionErrorInfo *old_err; PurpleAccountPrivate *priv; + PurpleNotificationManager *manager = NULL; g_return_if_fail(PURPLE_IS_ACCOUNT(account)); priv = purple_account_get_instance_private(account); @@ -529,7 +533,19 @@ _purple_account_set_current_error(PurpleAccount *account, if(new_err == old_err) return; - priv->current_error = new_err; + manager = purple_notification_manager_get_default(); + + if(PURPLE_IS_NOTIFICATION(priv->error_notification)) { + purple_notification_manager_remove(manager, priv->error_notification); + g_clear_object(&priv->error_notification); + } + + if(new_err != NULL) { + priv->error_notification = + purple_notification_new(PURPLE_NOTIFICATION_TYPE_CONNECTION_ERROR, + account, new_err, NULL); + purple_notification_manager_add(manager, priv->error_notification); + } purple_signal_emit(purple_accounts_get_handle(), "account-error-changed", @@ -943,6 +959,8 @@ purple_account_finalize(GObject *object) g_free(priv->current_error); } + g_clear_object(&priv->error_notification); + g_free(priv->id); g_free(priv->username); g_free(priv->alias); diff --git a/libpurple/purplenotification.c b/libpurple/purplenotification.c index e84d8810a7..9adcadbf58 100644 --- a/libpurple/purplenotification.c +++ b/libpurple/purplenotification.c @@ -542,3 +542,26 @@ purple_notification_get_data(PurpleNotification *notification) { return notification->data; } + +gint +purple_notification_compare(gconstpointer a, gconstpointer b) { + PurpleNotification *notification_a = NULL, *notification_b = NULL; + + if(a == NULL && b == NULL) { + return 0; + } + + if(a == NULL) { + return -1; + } + + if(b == NULL) { + return 1; + } + + notification_a = (PurpleNotification *)a; + notification_b = (PurpleNotification *)b; + + return g_date_time_compare(notification_a->created_timestamp, + notification_b->created_timestamp); +} diff --git a/libpurple/purplenotification.h b/libpurple/purplenotification.h index b0ba49b2b7..3ec0bdc6f1 100644 --- a/libpurple/purplenotification.h +++ b/libpurple/purplenotification.h @@ -135,6 +135,8 @@ GDateTime *purple_notification_get_created_timestamp(PurpleNotification *notific * Timestamp is internally converted to UTC so you don't need to do that ahead * of time. * + * If @timestamp is %NULL, the current time will be used. + * * Since: 3.0.0 */ void purple_notification_set_created_timestamp(PurpleNotification *notification, GDateTime *timestamp); @@ -243,6 +245,21 @@ void purple_notification_set_interactive(PurpleNotification *notification, gbool */ gpointer purple_notification_get_data(PurpleNotification *notification); +/** + * purple_notification_compare: + * @a: The first notification to compare. + * @b: The second notification to compare. + * + * A comparison function for PurpleNotification that is suitable as a + * GCompareFunc. + * + * Returns: -1 if @a's created timestamp occurred before @b, 0 if they were + * created at the same time, or 1 if @b was created before @a. + * + * Since: 3.0.0 + */ +gint purple_notification_compare(gconstpointer a, gconstpointer b); + G_END_DECLS #endif /* PURPLE_NOTIFICATION */ diff --git a/libpurple/purplenotificationmanager.c b/libpurple/purplenotificationmanager.c index ab0ccf5fe2..37fada2c80 100644 --- a/libpurple/purplenotificationmanager.c +++ b/libpurple/purplenotificationmanager.c @@ -41,7 +41,7 @@ static guint signals[N_SIGNALS] = { 0, }; struct _PurpleNotificationManager { GObject parent; - GHashTable *notifications; + GListStore *notifications; guint unread_count; }; @@ -139,15 +139,14 @@ purple_notification_manager_finalize(GObject *obj) { manager = PURPLE_NOTIFICATION_MANAGER(obj); - g_clear_pointer(&manager->notifications, g_hash_table_destroy); + g_clear_object(&manager->notifications); G_OBJECT_CLASS(purple_notification_manager_parent_class)->finalize(obj); } static void purple_notification_manager_init(PurpleNotificationManager *manager) { - manager->notifications = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, g_object_unref); + manager->notifications = g_list_store_new(PURPLE_TYPE_NOTIFICATION); } static void @@ -288,20 +287,20 @@ void purple_notification_manager_add(PurpleNotificationManager *manager, PurpleNotification *notification) { - const gchar *id = NULL; - g_return_if_fail(PURPLE_IS_NOTIFICATION_MANAGER(manager)); g_return_if_fail(PURPLE_IS_NOTIFICATION(notification)); - id = purple_notification_get_id(notification); + if(g_list_store_find(manager->notifications, notification, NULL)) { + const gchar *id = purple_notification_get_id(notification); - if(g_hash_table_lookup(manager->notifications, (gpointer)id) != NULL) { g_warning("double add detected for notification %s", id); return; } - g_hash_table_insert(manager->notifications, (gpointer)id, notification); + g_list_store_insert_sorted(manager->notifications, notification, + (GCompareDataFunc)purple_notification_compare, + NULL); /* Connect to the notify signal for the read property only so we can * propagate out changes for any notification. @@ -319,49 +318,43 @@ purple_notification_manager_add(PurpleNotificationManager *manager, g_signal_emit(G_OBJECT(manager), signals[SIG_ADDED], 0, notification); } -gboolean +void purple_notification_manager_remove(PurpleNotificationManager *manager, - const gchar *id) + PurpleNotification *notification) { - gpointer data = NULL; - gboolean ret = FALSE; + guint position; - g_return_val_if_fail(PURPLE_IS_NOTIFICATION_MANAGER(manager), FALSE); - g_return_val_if_fail(id != NULL, FALSE); + g_return_if_fail(PURPLE_IS_NOTIFICATION_MANAGER(manager)); + g_return_if_fail(PURPLE_IS_NOTIFICATION(notification)); - data = g_hash_table_lookup(manager->notifications, id); - if(PURPLE_IS_NOTIFICATION(data)) { + if(g_list_store_find(manager->notifications, notification, &position)) { /* Reference the notification so we can emit the signal after it's been * removed from the hash table. */ - g_object_ref(G_OBJECT(data)); - - if(g_hash_table_remove(manager->notifications, id)) { - g_signal_emit(G_OBJECT(manager), signals[SIG_REMOVED], 0, - data); - - ret = TRUE; - } + g_object_ref(notification); /* Remove the notify signal handler for the read state incase someone * else added a reference to the notification which would then mess * with our unread count accounting. */ - g_signal_handlers_disconnect_by_func(data, + g_signal_handlers_disconnect_by_func(notification, G_CALLBACK(purple_notification_manager_notify_cb), manager); /* If the notification is not read, we need to decrement the unread * count. */ - if(!purple_notification_get_read(PURPLE_NOTIFICATION(data))) { + if(!purple_notification_get_read(notification)) { purple_notification_manager_decrement_unread_count(manager); } - g_object_unref(G_OBJECT(data)); - } + g_list_store_remove(manager->notifications, position); + + g_signal_emit(G_OBJECT(manager), signals[SIG_REMOVED], 0, notification); - return ret; + g_object_unref(notification); + + } } guint diff --git a/libpurple/purplenotificationmanager.h b/libpurple/purplenotificationmanager.h index 7349dedeab..e2aace09a8 100644 --- a/libpurple/purplenotificationmanager.h +++ b/libpurple/purplenotificationmanager.h @@ -69,16 +69,13 @@ void purple_notification_manager_add(PurpleNotificationManager *manager, PurpleN /** * purple_notification_manager_remove: * @manager: The instance. - * @id: The identifier of the notification to remove. + * @notification: The notification to remove. * * Removes @notification from @manager. * - * Returns: %TRUE if @notification was successfully removed from @manager, - * %FALSE otherwise. - * * Since: 3.0.0 */ -gboolean purple_notification_manager_remove(PurpleNotificationManager *manager, const gchar *id); +void purple_notification_manager_remove(PurpleNotificationManager *manager, PurpleNotification *notification); /** * purple_notification_manager_get_unread_count: diff --git a/libpurple/tests/test_notification_manager.c b/libpurple/tests/test_notification_manager.c index 11ed1d805c..deede821d5 100644 --- a/libpurple/tests/test_notification_manager.c +++ b/libpurple/tests/test_notification_manager.c @@ -66,8 +66,6 @@ test_purple_notification_manager_add_remove(void) { PurpleNotificationManager *manager = NULL; PurpleNotification *notification = NULL; gint added_called = 0, removed_called = 0; - gboolean removed = FALSE; - const gchar *id = NULL; guint unread_count = 0; manager = g_object_new(PURPLE_TYPE_NOTIFICATION_MANAGER, NULL); @@ -85,7 +83,6 @@ test_purple_notification_manager_add_remove(void) { /* Create the notification and store it's id. */ notification = purple_notification_new(PURPLE_NOTIFICATION_TYPE_GENERIC, NULL, NULL, NULL); - id = purple_notification_get_id(notification); /* Add the notification to the manager. */ purple_notification_manager_add(manager, notification); @@ -98,8 +95,7 @@ test_purple_notification_manager_add_remove(void) { g_assert_cmpint(unread_count, ==, 1); /* Remove the notification. */ - removed = purple_notification_manager_remove(manager, id); - g_assert_true(removed); + purple_notification_manager_remove(manager, notification); g_assert_cmpint(removed_called, ==, 1); /* Verify that the unread count is now 0. */ @@ -139,7 +135,6 @@ static void test_purple_notification_manager_double_remove(void) { PurpleNotificationManager *manager = NULL; PurpleNotification *notification = NULL; - const gchar *id = NULL; gint removed_called = 0; manager = g_object_new(PURPLE_TYPE_NOTIFICATION_MANAGER, NULL); @@ -155,12 +150,10 @@ test_purple_notification_manager_double_remove(void) { */ g_object_ref(notification); - id = purple_notification_get_id(notification); - purple_notification_manager_add(manager, notification); - g_assert_true(purple_notification_manager_remove(manager, id)); - g_assert_false(purple_notification_manager_remove(manager, id)); + purple_notification_manager_remove(manager, notification); + purple_notification_manager_remove(manager, notification); g_assert_cmpint(removed_called, ==, 1); |