pidgin/pidgin

e114ed471a1e
Parents 348cc74f084e
Children 80d00b75945c
Implement the UI for the new Notifications API.

This currently only shows connection error notifications which have to be
removed manually since an account with a connection error can not currently
reconnect successfully.

Testing Done:
I used a IRC account with an server name that was unresolvable as well as an XMPP account with a wrong password to cause a fatal connection errors.
I also used a IRC account connecting to a local instance of ZNC where I terminated ZNC to cause a server side connection failure.

Bugs closed: PIDGIN-17634

Reviewed at https://reviews.imfreedom.org/r/1512/
--- a/libpurple/account.c Mon Jul 04 20:29:32 2022 -0500
+++ b/libpurple/account.c Mon Jul 04 23:24:35 2022 -0500
@@ -541,9 +541,22 @@
}
if(new_err != NULL) {
+ PurpleProtocol *protocol = NULL;
+
priv->error_notification =
purple_notification_new(PURPLE_NOTIFICATION_TYPE_CONNECTION_ERROR,
account, new_err, NULL);
+
+ protocol = purple_account_get_protocol(account);
+ if(PURPLE_IS_PROTOCOL(protocol)) {
+ const gchar *icon_name = purple_protocol_get_icon_name(protocol);
+
+ if(icon_name != NULL) {
+ purple_notification_set_icon_name(priv->error_notification,
+ icon_name);
+ }
+ }
+
purple_notification_manager_add(manager, priv->error_notification);
}
--- a/libpurple/purplenotificationmanager.c Mon Jul 04 20:29:32 2022 -0500
+++ b/libpurple/purplenotificationmanager.c Mon Jul 04 23:24:35 2022 -0500
@@ -363,3 +363,14 @@
return manager->unread_count;
}
+
+GListModel *
+purple_notification_manager_get_model(PurpleNotificationManager *manager) {
+ g_return_val_if_fail(PURPLE_IS_NOTIFICATION_MANAGER(manager), NULL);
+
+ if(manager->notifications == NULL) {
+ return NULL;
+ }
+
+ return G_LIST_MODEL(g_object_ref(manager->notifications));
+}
--- a/libpurple/purplenotificationmanager.h Mon Jul 04 20:29:32 2022 -0500
+++ b/libpurple/purplenotificationmanager.h Mon Jul 04 23:24:35 2022 -0500
@@ -89,6 +89,19 @@
*/
guint purple_notification_manager_get_unread_count(PurpleNotificationManager *manager);
+/**
+ * purple_notification_manager_get_model:
+ * @manager: The instance.
+ *
+ * Gets a [iface@Gio.ListModel] of all the [class@Notification]'s in
+ * @manager.
+ *
+ * Returns: (transfer full): The model.
+ *
+ * Since: 3.0.0
+ */
+GListModel *purple_notification_manager_get_model(PurpleNotificationManager *manager);
+
G_END_DECLS
#endif /* PURPLE_NOTIFICATION_MANAGER_H */
--- a/pidgin/glade/pidgin3.xml.in Mon Jul 04 20:29:32 2022 -0500
+++ b/pidgin/glade/pidgin3.xml.in Mon Jul 04 23:24:35 2022 -0500
@@ -13,6 +13,7 @@
<glade-widget-class name="PidginCredentialsPage" generic-name="credentials_page" title="CredentialsPage"/>
<glade-widget-class name="PidginDialog" generic-name="dialog" title="Dialog"/>
<glade-widget-class name="PidginInviteDialog" generic-name="invite_dialog" title="InviteDialog"/>
+ <glade-widget-class name="PidginNotificationList" generic-name="notification_list" title="NotificationList"/>
<glade-widget-class name="PidginPresenceIcon" generic-name="presence_icon" title="PresenceIcon"/>
<glade-widget-class name="PidginProtocolChooser" generic-name="protocol_chooser" title="ProtocolChooser"/>
<glade-widget-class name="PidginProtocolStore" generic-name="protocol_store" title="ProtocolStore"/>
@@ -34,6 +35,7 @@
<glade-widget-class-ref name="PidginCredentialsPage"/>
<glade-widget-class-ref name="PidginDialog"/>
<glade-widget-class-ref name="PidginInviteDialog"/>
+ <glade-widget-class-ref name="PidginNotificationList"/>
<glade-widget-class-ref name="PidginPresenceIcon"/>
<glade-widget-class-ref name="PidginProtocolChooser"/>
<glade-widget-class-ref name="PidginProtocolStore"/>
--- a/pidgin/meson.build Mon Jul 04 20:29:32 2022 -0500
+++ b/pidgin/meson.build Mon Jul 04 23:24:35 2022 -0500
@@ -44,6 +44,8 @@
'pidgininvitedialog.c',
'pidginmessage.c',
'pidginmooddialog.c',
+ 'pidginnotificationconnectionerror.c',
+ 'pidginnotificationlist.c',
'pidginplugininfo.c',
'pidginpluginsdialog.c',
'pidginpluginsmenu.c',
@@ -118,6 +120,8 @@
'pidgininvitedialog.h',
'pidginmessage.h',
'pidginmooddialog.h',
+ 'pidginnotificationconnectionerror.h',
+ 'pidginnotificationlist.h',
'pidginplugininfo.h',
'pidginpluginsdialog.h',
'pidginpluginsmenu.h',
--- a/pidgin/pidginapplication.c Mon Jul 04 20:29:32 2022 -0500
+++ b/pidgin/pidginapplication.c Mon Jul 04 23:24:35 2022 -0500
@@ -263,6 +263,24 @@
}
static void
+pidgin_application_connect_account(GSimpleAction *simple, GVariant *parameter,
+ gpointer data)
+{
+ PurpleAccount *account = NULL;
+ PurpleAccountManager *manager = NULL;
+ const gchar *id = NULL;
+
+ id = g_variant_get_string(parameter, NULL);
+
+ manager = purple_account_manager_get_default();
+
+ account = purple_account_manager_find_by_id(manager, id);
+ if(PURPLE_IS_ACCOUNT(account)) {
+ purple_account_connect(account);
+ }
+}
+
+static void
pidgin_application_debug(GSimpleAction *simple, GVariant *parameter,
gpointer data)
{
@@ -450,6 +468,10 @@
.name = "add-group",
.activate = pidgin_application_add_group,
}, {
+ .name = "connect-account",
+ .activate = pidgin_application_connect_account,
+ .parameter_type = "s",
+ }, {
.name = "debug",
.activate = pidgin_application_debug,
}, {
--- a/pidgin/pidginconversationwindow.c Mon Jul 04 20:29:32 2022 -0500
+++ b/pidgin/pidginconversationwindow.c Mon Jul 04 23:24:35 2022 -0500
@@ -28,6 +28,7 @@
enum {
PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME,
PIDGIN_CONVERSATION_WINDOW_COLUMN_ICON,
PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP,
};
@@ -48,6 +49,8 @@
GtkWidget *stack;
+ GtkWidget *notification_list;
+
GtkTreePath *conversation_path;
};
@@ -69,14 +72,14 @@
gboolean changed = FALSE;
if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
- gchar *markup = NULL;
+ gchar *name = NULL;
gtk_tree_model_get(model, &iter,
- PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, &markup,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, &name,
-1);
- gtk_stack_set_visible_child_name(GTK_STACK(window->stack), markup);
- g_free(markup);
+ gtk_stack_set_visible_child_name(GTK_STACK(window->stack), name);
+ g_free(name);
changed = TRUE;
}
@@ -187,6 +190,13 @@
/* Add our toplevels to the tree store. */
gtk_tree_store_append(window->model, &iter, NULL);
gtk_tree_store_set(window->model, &iter,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, window->notification_list,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, "__notifications__",
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, _("Notifications"),
+ -1);
+
+ gtk_tree_store_append(window->model, &iter, NULL);
+ gtk_tree_store_set(window->model, &iter,
PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, _("Conversations"),
-1);
window->conversation_path = gtk_tree_model_get_path(GTK_TREE_MODEL(window->model),
@@ -228,6 +238,8 @@
gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow,
stack);
+ gtk_widget_class_bind_template_child(widget_class, PidginConversationWindow,
+ notification_list);
gtk_widget_class_bind_template_callback(widget_class,
pidgin_conversation_window_selection_changed);
@@ -299,6 +311,7 @@
gtk_tree_store_prepend(window->model, &iter, &parent);
gtk_tree_store_set(window->model, &iter,
PIDGIN_CONVERSATION_WINDOW_COLUMN_OBJECT, conversation,
+ PIDGIN_CONVERSATION_WINDOW_COLUMN_NAME, markup,
PIDGIN_CONVERSATION_WINDOW_COLUMN_MARKUP, markup,
-1);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginnotificationconnectionerror.c Mon Jul 04 23:24:35 2022 -0500
@@ -0,0 +1,277 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include <purple.h>
+
+#include "pidgin/pidginnotificationconnectionerror.h"
+
+struct _PidginNotificationConnectionError {
+ HdyActionRow parent;
+
+ PurpleNotification *notification;
+
+ GtkWidget *reconnect;
+ GtkWidget *reenable;
+ GtkWidget *modify;
+};
+
+enum {
+ PROP_0,
+ PROP_NOTIFICATION,
+ N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+G_DEFINE_TYPE(PidginNotificationConnectionError,
+ pidgin_notification_connection_error, HDY_TYPE_ACTION_ROW)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+pidgin_notification_connection_error_update(PidginNotificationConnectionError *error) {
+ PurpleAccount *account = NULL;
+ PurpleConnectionErrorInfo *info = NULL;
+ gchar *title = NULL;
+ const gchar *username = NULL, *icon_name = NULL, *account_id = NULL;
+ gboolean enabled = FALSE;
+
+ g_return_if_fail(PIDGIN_IS_NOTIFICATION_CONNECTION_ERROR(error));
+
+ if(!PURPLE_IS_NOTIFICATION(error->notification)) {
+ hdy_preferences_row_set_title(HDY_PREFERENCES_ROW(error),
+ _("Notification missing"));
+
+ hdy_action_row_set_icon_name(HDY_ACTION_ROW(error), NULL);
+ hdy_action_row_set_subtitle(HDY_ACTION_ROW(error), NULL);
+
+ gtk_widget_hide(error->reconnect);
+ gtk_widget_hide(error->reenable);
+ gtk_widget_hide(error->modify);
+
+ return;
+ }
+
+ account = purple_notification_get_account(error->notification);
+ if(!PURPLE_IS_ACCOUNT(account)) {
+ hdy_preferences_row_set_title(HDY_PREFERENCES_ROW(error),
+ _("Notification is missing an account"));
+
+ hdy_action_row_set_icon_name(HDY_ACTION_ROW(error), NULL);
+ hdy_action_row_set_subtitle(HDY_ACTION_ROW(error), NULL);
+
+ gtk_widget_hide(error->reconnect);
+ gtk_widget_hide(error->reenable);
+ gtk_widget_hide(error->modify);
+
+ return;
+ }
+
+ /* Set the target for our actions. */
+ account_id = purple_account_get_id(account);
+ gtk_actionable_set_action_target(GTK_ACTIONABLE(error->reconnect), "s",
+ account_id);
+ gtk_actionable_set_action_target(GTK_ACTIONABLE(error->reenable), "s",
+ account_id);
+ gtk_actionable_set_action_target(GTK_ACTIONABLE(error->modify), "s",
+ account_id);
+
+ /* Set the icon name if one was specified. */
+ icon_name = purple_notification_get_icon_name(error->notification);
+ if(icon_name != NULL) {
+ hdy_action_row_set_icon_name(HDY_ACTION_ROW(error), icon_name);
+ }
+
+ username = purple_account_get_username(account);
+
+ enabled = purple_account_get_enabled(account);
+ if(enabled) {
+ title = g_strdup_printf(_("%s disconnected"), username);
+ } else {
+ title = g_strdup_printf(_("%s disabled"), username);
+ }
+ hdy_preferences_row_set_title(HDY_PREFERENCES_ROW(error), title);
+ g_free(title);
+
+ info = purple_notification_get_data(error->notification);
+ if(info != NULL) {
+ hdy_action_row_set_subtitle(HDY_ACTION_ROW(error), info->description);
+ } else {
+ hdy_action_row_set_subtitle(HDY_ACTION_ROW(error), NULL);
+ }
+
+ /* If the account is still enabled, reconnect should be visible, otherwise
+ * re-enable should be visible.
+ */
+ gtk_widget_set_visible(error->reconnect, enabled);
+ gtk_widget_set_visible(error->reenable, !enabled);
+}
+
+static void
+pidgin_notification_connection_error_set_notification(PidginNotificationConnectionError *error,
+ PurpleNotification *notification)
+{
+ if(g_set_object(&error->notification, notification)) {
+ pidgin_notification_connection_error_update(error);
+
+ g_object_notify_by_pspec(G_OBJECT(error), properties[PROP_NOTIFICATION]);
+ }
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+pidgin_notification_connection_error_remove_cb(G_GNUC_UNUSED GtkButton *button,
+ gpointer data)
+{
+ PidginNotificationConnectionError *error = data;
+ PurpleNotificationManager *manager = NULL;
+
+ manager = purple_notification_manager_get_default();
+ purple_notification_manager_remove(manager, error->notification);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+pidgin_notification_connection_error_get_property(GObject *obj, guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PidginNotificationConnectionError *error = NULL;
+
+ error = PIDGIN_NOTIFICATION_CONNECTION_ERROR(obj);
+
+ switch(param_id) {
+ case PROP_NOTIFICATION:
+ g_value_set_object(value,
+ pidgin_notification_connection_error_get_notification(error));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pidgin_notification_connection_error_set_property(GObject *obj, guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PidginNotificationConnectionError *error = NULL;
+
+ error = PIDGIN_NOTIFICATION_CONNECTION_ERROR(obj);
+
+ switch(param_id) {
+ case PROP_NOTIFICATION:
+ pidgin_notification_connection_error_set_notification(error,
+ g_value_get_object(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+pidgin_notification_connection_error_dispose(GObject *obj) {
+ PidginNotificationConnectionError *error = NULL;
+
+ error = PIDGIN_NOTIFICATION_CONNECTION_ERROR(obj);
+
+ g_clear_object(&error->notification);
+
+ G_OBJECT_CLASS(pidgin_notification_connection_error_parent_class)->dispose(obj);
+}
+
+static void
+pidgin_notification_connection_error_init(PidginNotificationConnectionError *list)
+{
+ gtk_widget_init_template(GTK_WIDGET(list));
+}
+
+static void
+pidgin_notification_connection_error_class_init(PidginNotificationConnectionErrorClass *klass)
+{
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ obj_class->get_property = pidgin_notification_connection_error_get_property;
+ obj_class->set_property = pidgin_notification_connection_error_set_property;
+ obj_class->dispose = pidgin_notification_connection_error_dispose;
+
+ /**
+ * PidginNotificationConnectionError::info:
+ *
+ * The [type@Purple.ConnectionErrorInfo] that this notification is for.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_NOTIFICATION] = g_param_spec_object(
+ "notification", "notification",
+ "The notification to display",
+ PURPLE_TYPE_NOTIFICATION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+
+ gtk_widget_class_set_template_from_resource(
+ widget_class,
+ "/im/pidgin/Pidgin3/Notifications/connectionerror.ui"
+ );
+
+ gtk_widget_class_bind_template_child(widget_class,
+ PidginNotificationConnectionError,
+ reconnect);
+ gtk_widget_class_bind_template_child(widget_class,
+ PidginNotificationConnectionError,
+ reenable);
+ gtk_widget_class_bind_template_child(widget_class,
+ PidginNotificationConnectionError,
+ modify);
+
+ gtk_widget_class_bind_template_callback(widget_class,
+ pidgin_notification_connection_error_remove_cb);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GtkWidget *
+pidgin_notification_connection_error_new(PurpleNotification *notification) {
+ return g_object_new(
+ PIDGIN_TYPE_NOTIFICATION_CONNECTION_ERROR,
+ "notification", notification,
+ NULL);
+}
+
+PurpleNotification *
+pidgin_notification_connection_error_get_notification(PidginNotificationConnectionError *error)
+{
+ g_return_val_if_fail(PIDGIN_IS_NOTIFICATION_CONNECTION_ERROR(error), NULL);
+
+ return error->notification;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginnotificationconnectionerror.h Mon Jul 04 23:24:35 2022 -0500
@@ -0,0 +1,79 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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 <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
+# error "only <pidgin.h> may be included directly"
+#endif
+
+#ifndef PIDGIN_NOTIFICATION_CONNECTION_ERROR_H
+#define PIDGIN_NOTIFICATION_CONNECTION_ERROR_H
+
+#include <glib.h>
+
+#include <gtk/gtk.h>
+
+#include <handy.h>
+
+#include <purple.h>
+
+G_BEGIN_DECLS
+
+/**
+ * PidginNotificationConnectionError:
+ *
+ * #PidginNotificationConnectionError is a widget that displays notifications from
+ * [class@Purple.NotificationManager].
+ *
+ * Since: 3.0.0
+ */
+
+#define PIDGIN_TYPE_NOTIFICATION_CONNECTION_ERROR (pidgin_notification_connection_error_get_type())
+G_DECLARE_FINAL_TYPE(PidginNotificationConnectionError, pidgin_notification_connection_error,
+ PIDGIN, NOTIFICATION_CONNECTION_ERROR, HdyActionRow)
+
+/**
+ * pidgin_notification_connection_error_new:
+ * @notification: A [class@Purple.Notification] to display.
+ *
+ * Creates a new #PidginNotificationConnectionError instance that will display
+ * @notification.
+ *
+ * Returns: (transfer full): The new #PidginNotificationConnectionError
+ * instance.
+ */
+GtkWidget *pidgin_notification_connection_error_new(PurpleNotification *notification);
+
+/**
+ * pidgin_notification_connection_error_get_notification:
+ * @error: The instance.
+ *
+ * Gets the [class@Purple.Notification] that @error is displaying.
+ *
+ * Returns: (transfer none): The notification.
+ *
+ * Since: 3.0.0
+ */
+PurpleNotification *pidgin_notification_connection_error_get_notification(PidginNotificationConnectionError *error);
+
+G_END_DECLS
+
+#endif /* PIDGIN_NOTIFICATION_CONNECTION_ERROR_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginnotificationlist.c Mon Jul 04 23:24:35 2022 -0500
@@ -0,0 +1,123 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n-lib.h>
+
+#include <purple.h>
+
+#include "pidgin/pidginnotificationlist.h"
+
+#include "pidgin/pidginnotificationconnectionerror.h"
+
+struct _PidginNotificationList {
+ GtkBox parent;
+
+ GtkWidget *list_box;
+};
+
+G_DEFINE_TYPE(PidginNotificationList, pidgin_notification_list, GTK_TYPE_BOX)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static GtkWidget *
+pidgin_notification_list_unknown_notification(PurpleNotification *notification) {
+ GtkWidget *widget = NULL;
+ gchar *label = NULL;
+ const gchar *title = NULL;
+
+ title = purple_notification_get_title(notification);
+ if(title != NULL) {
+ label = g_strdup_printf(_("Unknown notification type %d: %s"),
+ purple_notification_get_notification_type(notification),
+ title);
+ } else {
+ label = g_strdup_printf(_("Unknown notification type %d"),
+ purple_notification_get_notification_type(notification));
+ }
+
+ widget = gtk_label_new(label);
+
+ g_free(label);
+
+ return widget;
+}
+
+static GtkWidget *
+pidgin_notification_list_create_widget_func(gpointer item, gpointer data) {
+ PurpleNotification *notification = item;
+ GtkWidget *widget = NULL;
+
+ switch(purple_notification_get_notification_type(notification)) {
+ case PURPLE_NOTIFICATION_TYPE_CONNECTION_ERROR:
+ widget = pidgin_notification_connection_error_new(notification);
+ break;
+ default:
+ widget = pidgin_notification_list_unknown_notification(notification);
+ break;
+ }
+
+ if(!GTK_IS_WIDGET(widget)) {
+ widget = pidgin_notification_list_unknown_notification(notification);
+ }
+
+ return widget;
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+pidgin_notification_list_init(PidginNotificationList *list) {
+ PurpleNotificationManager *manager = NULL;
+ GListModel *model = NULL;
+
+ gtk_widget_init_template(GTK_WIDGET(list));
+
+ manager = purple_notification_manager_get_default();
+ model = purple_notification_manager_get_model(manager);
+
+ gtk_list_box_bind_model(GTK_LIST_BOX(list->list_box), model,
+ pidgin_notification_list_create_widget_func,
+ list, NULL);
+}
+
+static void
+pidgin_notification_list_class_init(PidginNotificationListClass *klass) {
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ gtk_widget_class_set_template_from_resource(
+ widget_class,
+ "/im/pidgin/Pidgin3/Notifications/list.ui"
+ );
+
+ gtk_widget_class_bind_template_child(widget_class, PidginNotificationList,
+ list_box);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GtkWidget *
+pidgin_notification_list_new(void) {
+ return g_object_new(PIDGIN_TYPE_NOTIFICATION_LIST, NULL);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/pidginnotificationlist.h Mon Jul 04 23:24:35 2022 -0500
@@ -0,0 +1,61 @@
+/*
+ * Pidgin - Internet Messenger
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Pidgin is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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 <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PIDGIN_GLOBAL_HEADER_INSIDE) && !defined(PIDGIN_COMPILATION)
+# error "only <pidgin.h> may be included directly"
+#endif
+
+#ifndef PIDGIN_NOTIFICATION_LIST_H
+#define PIDGIN_NOTIFICATION_LIST_H
+
+#include <glib.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/**
+ * PidginNotificationList:
+ *
+ * #PidginNotificationList is a widget that displays notifications from
+ * [class@Purple.NotificationManager].
+ *
+ * Since: 3.0.0
+ */
+
+#define PIDGIN_TYPE_NOTIFICATION_LIST (pidgin_notification_list_get_type())
+G_DECLARE_FINAL_TYPE(PidginNotificationList, pidgin_notification_list, PIDGIN,
+ NOTIFICATION_LIST, GtkBox)
+
+/**
+ * pidgin_notification_list_new:
+ *
+ * Creates a new #PidginNotificationList instance that will display
+ * notifications from the default [class@Purple.NotificationManager].
+ *
+ * Returns: (transfer full): The new #PidginNotificationList instance.
+ */
+GtkWidget *pidgin_notification_list_new(void);
+
+G_END_DECLS
+
+#endif /* PIDGIN_NOTIFICATION_LIST_H */
--- a/pidgin/resources/Conversations/window.ui Mon Jul 04 20:29:32 2022 -0500
+++ b/pidgin/resources/Conversations/window.ui Mon Jul 04 23:24:35 2022 -0500
@@ -30,6 +30,8 @@
<columns>
<!-- column-name conversation -->
<column type="GObject"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
<!-- column-name icon -->
<column type="GdkPixbuf"/>
<!-- column-name markup -->
@@ -79,7 +81,7 @@
<property name="can-focus">True</property>
<property name="model">model</property>
<property name="headers-visible">False</property>
- <property name="search-column">2</property>
+ <property name="search-column">3</property>
<child internal-child="selection">
<object class="GtkTreeSelection">
<signal name="changed" handler="pidgin_conversation_window_selection_changed" object="PidginConversationWindow" swapped="no"/>
@@ -90,13 +92,13 @@
<child>
<object class="GtkCellRendererPixbuf" id="icon"/>
<attributes>
- <attribute name="pixbuf">1</attribute>
+ <attribute name="pixbuf">2</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText" id="name"/>
<attributes>
- <attribute name="markup">2</attribute>
+ <attribute name="markup">3</attribute>
</attributes>
</child>
</object>
@@ -131,6 +133,21 @@
<property name="title" translatable="yes">__empty__</property>
</packing>
</child>
+ <child>
+ <object class="PidginNotificationList" id="notification_list">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">__notifications__</property>
+ <property name="title" translatable="yes">notifications</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="resize">True</property>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/resources/Notifications/connectionerror.ui Mon Jul 04 23:24:35 2022 -0500
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2
+
+Pidgin - Internet Messenger
+Copyright (C) Pidgin Developers <devel@pidgin.im>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY 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 <https://www.gnu.org/licenses/>.
+
+-->
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <requires lib="libhandy" version="0.0"/>
+ <!-- interface-license-type gplv2 -->
+ <!-- interface-name Pidgin -->
+ <!-- interface-description Internet Messenger -->
+ <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
+ <template class="PidginNotificationConnectionError" parent="HdyActionRow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activatable">False</property>
+ <property name="subtitle-lines">3</property>
+ <child>
+ <object class="GtkButton" id="reconnect">
+ <property name="label" translatable="yes">Reconnect</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="action-name">app.connect-account</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="reenable">
+ <property name="label" translatable="yes">Re-enable</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="action-name">app.enable-account</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="modify">
+ <property name="label" translatable="yes">Modify Account</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="action-name">app.edit-account</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="remove">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="relief">none</property>
+ <signal name="clicked" handler="pidgin_notification_connection_error_remove_cb" object="PidginNotificationConnectionError" swapped="no"/>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">edit-delete-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/resources/Notifications/list.ui Mon Jul 04 23:24:35 2022 -0500
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2
+
+Pidgin - Internet Messenger
+Copyright (C) Pidgin Developers <devel@pidgin.im>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY 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 <https://www.gnu.org/licenses/>.
+
+-->
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <!-- interface-license-type gplv2 -->
+ <!-- interface-name Pidgin -->
+ <!-- interface-description Internet Messenger -->
+ <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
+ <template class="PidginNotificationList" parent="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Notifications</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkListBox" id="list_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </template>
+</interface>
--- a/pidgin/resources/pidgin.gresource.xml Mon Jul 04 20:29:32 2022 -0500
+++ b/pidgin/resources/pidgin.gresource.xml Mon Jul 04 23:24:35 2022 -0500
@@ -21,6 +21,8 @@
<file compressed="true">Debug/filter.css</file>
<file compressed="true">Debug/plugininfo.ui</file>
<file compressed="true">Log/log-viewer.ui</file>
+ <file compressed="true">Notifications/connectionerror.ui</file>
+ <file compressed="true">Notifications/list.ui</file>
<file compressed="true">Plugins/dialog.ui</file>
<file compressed="true">Prefs/away.ui</file>
<file compressed="true">Prefs/conversation.ui</file>