Mon, 04 Jul 2022 23:24:35 -0500
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>