# HG changeset patch
# Node ID df4cc3285eff1efbd0cb89aa9898eded5735590e
# Parent  34ac8ac8c7b6b57728ce871f521cd12500b1d239
diff --git a/pidgin/meson.build b/pidgin/meson.build
--- a/pidgin/meson.build
+++ b/pidgin/meson.build
@@ -32,9 +32,8 @@
 	'pidgininfopane.c',
 	'pidginkeypad.c',
 	'pidginnotifiable.c',
+	'pidginnotification.c',
 	'pidginnotificationaddcontact.c',
-	'pidginnotificationauthorizationrequest.c',
-	'pidginnotificationconnectionerror.c',
 	'pidginnotificationlist.c',
 	'pidginpluginsmenu.c',
 	'pidginpresenceicon.c',
@@ -79,9 +78,8 @@
 	'pidgininfopane.h',
 	'pidginkeypad.h',
 	'pidginnotifiable.h',
+	'pidginnotification.h',
 	'pidginnotificationaddcontact.h',
-	'pidginnotificationauthorizationrequest.h',
-	'pidginnotificationconnectionerror.h',
 	'pidginnotificationlist.h',
 	'pidginpluginsmenu.h',
 	'pidginpresenceicon.h',
diff --git a/pidgin/pidginnotification.c b/pidgin/pidginnotification.c
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginnotification.c
@@ -0,0 +1,262 @@
+/*
+ * 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/pidginnotification.h"
+
+typedef struct {
+	PurpleNotification *notification;
+
+	GtkWidget *details;
+	GtkWidget *child;
+} PidginNotificationPrivate;
+
+enum {
+	PROP_0,
+	PROP_NOTIFICATION,
+	PROP_CHILD,
+	N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+G_DEFINE_TYPE_WITH_PRIVATE(PidginNotification, pidgin_notification,
+                           GTK_TYPE_BOX)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+pidgin_notification_set_notification(PidginNotification *pidgin_notification,
+                                     PurpleNotification *purple_notification)
+{
+	PidginNotificationPrivate *priv = NULL;
+
+	priv = pidgin_notification_get_instance_private(pidgin_notification);
+
+	if(g_set_object(&priv->notification, purple_notification)) {
+		g_object_notify_by_pspec(G_OBJECT(pidgin_notification),
+		                         properties[PROP_NOTIFICATION]);
+	}
+}
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static gboolean
+pidgin_notification_show_subtitle(G_GNUC_UNUSED PidginNotification *notification,
+                                  const char *subtitle)
+{
+	return !purple_strempty(subtitle);
+}
+
+/******************************************************************************
+ * Widget Actions
+ *****************************************************************************/
+static void
+pidgin_notification_close(GtkWidget *self,
+                          G_GNUC_UNUSED const char *action_name,
+                          G_GNUC_UNUSED GVariant *parameter)
+{
+	PidginNotification *notification = PIDGIN_NOTIFICATION(self);
+	PidginNotificationPrivate *priv = NULL;
+	PurpleNotificationManager *manager = NULL;
+
+	priv = pidgin_notification_get_instance_private(notification);
+	purple_notification_delete(priv->notification);
+
+	manager = purple_notification_manager_get_default();
+	purple_notification_manager_remove(manager, priv->notification);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+pidgin_notification_get_property(GObject *obj, guint param_id, GValue *value,
+                                 GParamSpec *pspec)
+{
+	PidginNotification *notification = PIDGIN_NOTIFICATION(obj);
+
+	switch(param_id) {
+	case PROP_NOTIFICATION:
+		g_value_set_object(value,
+		                   pidgin_notification_get_notification(notification));
+		break;
+	case PROP_CHILD:
+		g_value_set_object(value,
+		                   pidgin_notification_get_child(notification));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+pidgin_notification_set_property(GObject *obj, guint param_id,
+                                 const GValue *value, GParamSpec *pspec)
+{
+	PidginNotification *notification = PIDGIN_NOTIFICATION(obj);
+
+	switch(param_id) {
+	case PROP_NOTIFICATION:
+		pidgin_notification_set_notification(notification,
+		                                     g_value_get_object(value));
+		break;
+	case PROP_CHILD:
+		pidgin_notification_set_child(notification, g_value_get_object(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+pidgin_notification_dispose(GObject *obj) {
+	PidginNotification *notification = PIDGIN_NOTIFICATION(obj);
+	PidginNotificationPrivate *priv = NULL;
+
+	priv = pidgin_notification_get_instance_private(notification);
+
+	g_clear_object(&priv->notification);
+	g_clear_pointer(&priv->child, gtk_widget_unparent);
+
+	G_OBJECT_CLASS(pidgin_notification_parent_class)->dispose(obj);
+}
+
+static void
+pidgin_notification_init(PidginNotification *notification) {
+	gtk_widget_init_template(GTK_WIDGET(notification));
+}
+
+static void
+pidgin_notification_class_init(PidginNotificationClass *klass) {
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+	obj_class->get_property = pidgin_notification_get_property;
+	obj_class->set_property = pidgin_notification_set_property;
+	obj_class->dispose = pidgin_notification_dispose;
+
+	/**
+	 * PidginNotification:notification:
+	 *
+	 * The [type@Purple.Notification] that is being displayed.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_NOTIFICATION] = g_param_spec_object(
+		"notification", NULL, NULL,
+		PURPLE_TYPE_NOTIFICATION,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PidginNotification:child:
+	 *
+	 * Child widgets to show between the details and the close button.
+	 *
+	 * This is typically actions like message, add contact, etc.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_CHILD] = g_param_spec_object(
+		"child", NULL, NULL,
+		GTK_TYPE_WIDGET,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+
+	/* Actions */
+	gtk_widget_class_install_action(widget_class, "notification.close",
+	                                NULL, pidgin_notification_close);
+
+	/* Bindings */
+	gtk_widget_class_set_template_from_resource(widget_class,
+	                                            "/im/pidgin/Pidgin3/notification.ui");
+
+	gtk_widget_class_bind_template_child_private(widget_class,
+	                                             PidginNotification, details);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_notification_show_subtitle);
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+GtkWidget *
+pidgin_notification_new(PurpleNotification *notification) {
+	return g_object_new(
+		PIDGIN_TYPE_NOTIFICATION,
+		"notification", notification,
+		NULL);
+}
+
+PurpleNotification *
+pidgin_notification_get_notification(PidginNotification *notification)
+{
+	PidginNotificationPrivate *priv = NULL;
+
+	g_return_val_if_fail(PIDGIN_IS_NOTIFICATION(notification), NULL);
+
+	priv = pidgin_notification_get_instance_private(notification);
+
+	return priv->notification;
+}
+
+GtkWidget *
+pidgin_notification_get_child(PidginNotification *notification) {
+	PidginNotificationPrivate *priv = NULL;
+
+	g_return_val_if_fail(PIDGIN_IS_NOTIFICATION(notification), NULL);
+
+	priv = pidgin_notification_get_instance_private(notification);
+
+	return priv->child;
+}
+
+void
+pidgin_notification_set_child(PidginNotification *notification,
+                              GtkWidget *child)
+{
+	PidginNotificationPrivate *priv = NULL;
+
+	g_return_if_fail(PIDGIN_IS_NOTIFICATION(notification));
+
+	priv = pidgin_notification_get_instance_private(notification);
+
+	if(child == priv->child) {
+		return;
+	}
+
+	g_clear_pointer(&priv->child, gtk_widget_unparent);
+	if(GTK_IS_WIDGET(child)) {
+		priv->child = child;
+		gtk_box_insert_child_after(GTK_BOX(notification), child,
+		                           priv->details);
+	}
+
+	g_object_notify_by_pspec(G_OBJECT(notification), properties[PROP_CHILD]);
+}
diff --git a/pidgin/pidginnotification.h b/pidgin/pidginnotification.h
new file mode 100644
--- /dev/null
+++ b/pidgin/pidginnotification.h
@@ -0,0 +1,125 @@
+/*
+ * 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_H
+#define PIDGIN_NOTIFICATION_H
+
+#include <glib.h>
+
+#include <gtk/gtk.h>
+
+#include <adwaita.h>
+
+#include <purple.h>
+
+#include "pidginversion.h"
+
+G_BEGIN_DECLS
+
+/**
+ * PidginNotification:
+ *
+ * #PidginNotification is a widget that displays [class@Purple.Notification]'s
+ * from [class@Purple.NotificationManager].
+ *
+ * Depending on the [class@Purple.Notification] that this is created for,
+ * different actions will be displayed.
+ *
+ * Since: 3.0
+ */
+
+#define PIDGIN_TYPE_NOTIFICATION (pidgin_notification_get_type())
+
+PIDGIN_AVAILABLE_IN_3_0
+G_DECLARE_DERIVABLE_TYPE(PidginNotification, pidgin_notification, PIDGIN,
+                         NOTIFICATION, GtkBox)
+
+struct _PidginNotificationClass {
+    /*< private >*/
+    GtkBoxClass parent;
+
+    /*< private >*/
+    gpointer reserved[4];
+};
+
+/**
+ * pidgin_notification_new:
+ * @notification: A [class@Purple.Notification] to display.
+ *
+ * Creates a new widget that will display @notification.
+ *
+ * Returns: (transfer full): The new instance.
+ *
+ * Since: 3.0
+ */
+PIDGIN_AVAILABLE_IN_3_0
+GtkWidget *pidgin_notification_new(PurpleNotification *notification);
+
+/**
+ * pidgin_notification_get_notification:
+ * @notification: The instance.
+ *
+ * Gets the [class@Purple.Notification] that @notification is displaying.
+ *
+ * Returns: (transfer none): The notification.
+ *
+ * Since: 3.0
+ */
+PIDGIN_AVAILABLE_IN_3_0
+PurpleNotification *pidgin_notification_get_notification(PidginNotification *notification);
+
+/**
+ * pidgin_notification_get_child:
+ * @notification: The instance.
+ *
+ * Gets the child widget from @notification.
+ *
+ * This child is meant to hold actions that can be performed for this
+ * notification.
+ *
+ * Returns: (transfer none) (nullable): The child widget if set, otherwise
+ *          %NULL.
+ *
+ * Since: 3.0
+ */
+PIDGIN_AVAILABLE_IN_3_0
+GtkWidget *pidgin_notification_get_child(PidginNotification *notification);
+
+/**
+ * pidgin_notification_set_child:
+ * @notification: The instance.
+ * @child: (nullable): The new child widget.
+ *
+ * Sets the child of @notification to @child.
+ *
+ * Since: 3.0
+ */
+PIDGIN_AVAILABLE_IN_3_0
+void pidgin_notification_set_child(PidginNotification *notification, GtkWidget *child);
+
+G_END_DECLS
+
+#endif /* PIDGIN_NOTIFICATION_H */
diff --git a/pidgin/pidginnotificationaddcontact.c b/pidgin/pidginnotificationaddcontact.c
--- a/pidgin/pidginnotificationaddcontact.c
+++ b/pidgin/pidginnotificationaddcontact.c
@@ -27,264 +27,101 @@
 #include "pidgin/pidginnotificationaddcontact.h"
 
 struct _PidginNotificationAddContact {
-	AdwActionRow parent;
-
-	PurpleNotification *notification;
-
-	GtkWidget *icon;
-	GtkWidget *add;
-	GtkWidget *message;
+	PidginNotification parent;
 };
 
-enum {
-	PROP_0,
-	PROP_NOTIFICATION,
-	N_PROPERTIES,
-};
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
 G_DEFINE_FINAL_TYPE(PidginNotificationAddContact,
-                    pidgin_notification_add_contact, ADW_TYPE_ACTION_ROW)
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-pidgin_notification_add_contact_update(PidginNotificationAddContact *add_contact)
-{
-	PurpleAccount *account = NULL;
-	PurpleAddContactRequest *request = NULL;
-	const gchar *title = NULL;
-	const gchar *icon_name = NULL, *message = NULL;
-
-	g_return_if_fail(PIDGIN_IS_NOTIFICATION_ADD_CONTACT(add_contact));
-
-	if(!PURPLE_IS_NOTIFICATION(add_contact->notification)) {
-		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(add_contact),
-		                              _("Notification missing"));
-
-		gtk_image_set_from_icon_name(GTK_IMAGE(add_contact->icon), NULL);
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(add_contact), NULL);
-
-		gtk_widget_set_visible(add_contact->add, FALSE);
-		gtk_widget_set_visible(add_contact->message, FALSE);
-
-		return;
-	}
-
-	account = purple_notification_get_account(add_contact->notification);
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(add_contact),
-		                              _("Notification is missing an account"));
-
-		gtk_image_set_from_icon_name(GTK_IMAGE(add_contact->icon), NULL);
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(add_contact), NULL);
-
-		gtk_widget_set_visible(add_contact->add, FALSE);
-		gtk_widget_set_visible(add_contact->message, FALSE);
-
-		return;
-	}
-
-	request = purple_notification_get_data(add_contact->notification);
-
-	/* Set the icon name if one was specified. */
-	icon_name = purple_notification_get_icon_name(add_contact->notification);
-	if(icon_name == NULL) {
-		PurpleProtocol *protocol = NULL;
-
-		protocol = purple_account_get_protocol(account);
-		icon_name = purple_protocol_get_icon_name(protocol);
-
-		if(icon_name == NULL) {
-			icon_name = "dialog-question";
-		}
-	}
-	gtk_image_set_from_icon_name(GTK_IMAGE(add_contact->icon), icon_name);
-
-	title = purple_notification_get_title(add_contact->notification);
-	adw_preferences_row_set_title(ADW_PREFERENCES_ROW(add_contact), title);
-
-	message = purple_add_contact_request_get_message(request);
-	adw_action_row_set_subtitle(ADW_ACTION_ROW(add_contact), message);
-
-	gtk_widget_set_visible(add_contact->add, TRUE);
-	gtk_widget_set_visible(add_contact->message, TRUE);
-}
-
-static void
-pidgin_notification_add_contact_set_notification(PidginNotificationAddContact *add_contact,
-                                                 PurpleNotification *notification)
-{
-	if(g_set_object(&add_contact->notification, notification)) {
-		pidgin_notification_add_contact_update(add_contact);
-
-		g_object_notify_by_pspec(G_OBJECT(add_contact),
-		                         properties[PROP_NOTIFICATION]);
-	}
-}
-
-static void
-pidgin_notification_add_contact_close(PidginNotificationAddContact *add_contact)
-{
-	PurpleNotificationManager *manager = NULL;
-
-	purple_notification_delete(add_contact->notification);
-
-	manager = purple_notification_manager_get_default();
-	purple_notification_manager_remove(manager, add_contact->notification);
-}
+                    pidgin_notification_add_contact, PIDGIN_TYPE_NOTIFICATION)
 
 /******************************************************************************
  * Callbacks
  *****************************************************************************/
 static void
-pidgin_notification_add_contact_add_cb(G_GNUC_UNUSED GtkButton *button,
-                                       gpointer data)
+pidgin_notification_add_contact_create_dm_cb(GObject *self,
+                                             GAsyncResult *result,
+                                             G_GNUC_UNUSED gpointer data)
 {
-	PidginNotificationAddContact *pidgin_request = data;
-	PurpleAddContactRequest *request = NULL;
+	PurpleContact *contact = PURPLE_CONTACT(self);
+	PurpleConversation *conversation = NULL;
+	GError *error = NULL;
 
-	request = purple_notification_get_data(pidgin_request->notification);
+	conversation = purple_contact_create_dm_finish(contact, result, &error);
+	if(error != NULL) {
+		g_warning("failed to create dm for %s: %s",
+		          purple_contact_info_get_name_for_display(PURPLE_CONTACT_INFO(contact)),
+		          error->message);
+
+		g_clear_error(&error);
+		g_clear_object(&conversation);
 
-	purple_add_contact_request_add(request);
+		return;
+	}
 
-	pidgin_notification_add_contact_close(pidgin_request);
+	if(PURPLE_IS_CONVERSATION(conversation)) {
+		purple_conversation_present(conversation);
+	}
+
+	g_clear_object(&conversation);
 }
 
+/******************************************************************************
+ * Actions
+ *****************************************************************************/
 static void
-pidgin_notification_add_contact_message_cb(G_GNUC_UNUSED GtkButton *button,
-                                           gpointer data)
+pidgin_notification_add_contact_message(GtkWidget *self,
+                                        G_GNUC_UNUSED const char *action_name,
+                                        G_GNUC_UNUSED GVariant *parameter)
 {
-	PidginNotificationAddContact *pidgin_request = data;
+	PidginNotification *pidgin_notification = PIDGIN_NOTIFICATION(self);
+	PurpleNotification *purple_notification = NULL;
 	PurpleAddContactRequest *request = NULL;
 	PurpleContact *contact = NULL;
 	PurpleConversation *conversation = NULL;
 
-	request = purple_notification_get_data(pidgin_request->notification);
+	purple_notification = pidgin_notification_get_notification(pidgin_notification);
+	request = purple_notification_add_contact_get_request(PURPLE_NOTIFICATION_ADD_CONTACT(purple_notification));
 	contact = purple_add_contact_request_get_contact(request);
 
 	conversation = purple_contact_find_dm(contact);
 	if(PURPLE_IS_CONVERSATION(conversation)) {
 		purple_conversation_present(conversation);
 	} else {
-		purple_contact_create_dm_async(contact, NULL, NULL, NULL);
+		purple_contact_create_dm_async(contact, NULL,
+		                               pidgin_notification_add_contact_create_dm_cb,
+		                               NULL);
 	}
 }
 
-static void
-pidgin_notification_add_contact_remove_cb(G_GNUC_UNUSED GtkButton *button,
-                                          gpointer data)
-{
-	PidginNotificationAddContact *request = data;
-
-	pidgin_notification_add_contact_close(request);
-}
-
 /******************************************************************************
  * GObject Implementation
  *****************************************************************************/
 static void
-pidgin_notification_add_contact_get_property(GObject *obj, guint param_id,
-                                             GValue *value, GParamSpec *pspec)
-{
-	PidginNotificationAddContact *request = NULL;
-
-	request = PIDGIN_NOTIFICATION_ADD_CONTACT(obj);
-
-	switch(param_id) {
-		case PROP_NOTIFICATION:
-			g_value_set_object(value,
-			                   pidgin_notification_add_contact_get_notification(request));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-pidgin_notification_add_contact_set_property(GObject *obj, guint param_id,
-                                             const GValue *value,
-                                             GParamSpec *pspec)
+pidgin_notification_add_contact_init(PidginNotificationAddContact *notification)
 {
-	PidginNotificationAddContact *request = NULL;
-
-	request = PIDGIN_NOTIFICATION_ADD_CONTACT(obj);
-
-	switch(param_id) {
-		case PROP_NOTIFICATION:
-			pidgin_notification_add_contact_set_notification(request,
-			                                                 g_value_get_object(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-pidgin_notification_add_contact_dispose(GObject *obj) {
-	PidginNotificationAddContact *request = NULL;
-
-	request = PIDGIN_NOTIFICATION_ADD_CONTACT(obj);
-
-	g_clear_object(&request->notification);
-
-	G_OBJECT_CLASS(pidgin_notification_add_contact_parent_class)->dispose(obj);
-}
-
-static void
-pidgin_notification_add_contact_init(PidginNotificationAddContact *list) {
-	gtk_widget_init_template(GTK_WIDGET(list));
+	gtk_widget_init_template(GTK_WIDGET(notification));
 }
 
 static void
 pidgin_notification_add_contact_class_init(PidginNotificationAddContactClass *klass)
 {
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
 
-	obj_class->get_property = pidgin_notification_add_contact_get_property;
-	obj_class->set_property = pidgin_notification_add_contact_set_property;
-	obj_class->dispose = pidgin_notification_add_contact_dispose;
-
-	/**
-	 * PidginNotificationAddContact:notification:
-	 *
-	 * The [type@Purple.Notification] that is being displayed.
-	 *
-	 * Since: 3.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/addcontact.ui"
+	    "/im/pidgin/Pidgin3/notificationaddcontact.ui"
 	);
 
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAddContact,
-	                                     icon);
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAddContact,
-	                                     add);
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAddContact,
-	                                     message);
-
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_add_contact_add_cb);
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_add_contact_message_cb);
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_add_contact_remove_cb);
+#if 0
+	/* This is disabled because it uses the request API and we really need to
+	 * create a real dialog for this instead.
+	 */
+	gtk_widget_class_install_action(widget_class, "notification.add-contact",
+	                                NULL,
+	                                pidgin_notification_add_contact_add_contact);
+#endif
+	gtk_widget_class_install_action(widget_class, "notification.message",
+	                                NULL,
+	                                pidgin_notification_add_contact_message);
 }
 
 /******************************************************************************
@@ -292,16 +129,11 @@
  *****************************************************************************/
 GtkWidget *
 pidgin_notification_add_contact_new(PurpleNotification *notification) {
+	g_return_val_if_fail(PURPLE_IS_NOTIFICATION_ADD_CONTACT(notification),
+	                     NULL);
+
 	return g_object_new(
 		PIDGIN_TYPE_NOTIFICATION_ADD_CONTACT,
 		"notification", notification,
 		NULL);
 }
-
-PurpleNotification *
-pidgin_notification_add_contact_get_notification(PidginNotificationAddContact *add_contact)
-{
-	g_return_val_if_fail(PIDGIN_IS_NOTIFICATION_ADD_CONTACT(add_contact), NULL);
-
-	return add_contact->notification;
-}
diff --git a/pidgin/pidginnotificationaddcontact.h b/pidgin/pidginnotificationaddcontact.h
--- a/pidgin/pidginnotificationaddcontact.h
+++ b/pidgin/pidginnotificationaddcontact.h
@@ -35,6 +35,7 @@
 
 #include <purple.h>
 
+#include "pidginnotification.h"
 #include "pidginversion.h"
 
 G_BEGIN_DECLS
@@ -53,7 +54,7 @@
 
 PIDGIN_AVAILABLE_IN_3_0
 G_DECLARE_FINAL_TYPE(PidginNotificationAddContact, pidgin_notification_add_contact,
-                     PIDGIN, NOTIFICATION_ADD_CONTACT, AdwActionRow)
+                     PIDGIN, NOTIFICATION_ADD_CONTACT, PidginNotification)
 
 /**
  * pidgin_notification_add_contact_new:
@@ -70,19 +71,6 @@
 PIDGIN_AVAILABLE_IN_3_0
 GtkWidget *pidgin_notification_add_contact_new(PurpleNotification *notification);
 
-/**
- * pidgin_notification_add_contact_get_notification:
- * @request: The instance.
- *
- * Gets the [class@Purple.Notification] that @request is displaying.
- *
- * Returns: (transfer none): The notification.
- *
- * Since: 3.0
- */
-PIDGIN_AVAILABLE_IN_3_0
-PurpleNotification *pidgin_notification_add_contact_get_notification(PidginNotificationAddContact *request);
-
 G_END_DECLS
 
 #endif /* PIDGIN_NOTIFICATION_ADD_CONTACT_H */
diff --git a/pidgin/pidginnotificationauthorizationrequest.c b/pidgin/pidginnotificationauthorizationrequest.c
deleted file mode 100644
--- a/pidgin/pidginnotificationauthorizationrequest.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * 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/pidginnotificationauthorizationrequest.h"
-
-struct _PidginNotificationAuthorizationRequest {
-	AdwActionRow parent;
-
-	PurpleNotification *notification;
-
-	GtkWidget *icon;
-	GtkWidget *accept;
-	GtkWidget *deny;
-	GtkWidget *message;
-};
-
-enum {
-	PROP_0,
-	PROP_NOTIFICATION,
-	N_PROPERTIES,
-};
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_FINAL_TYPE(PidginNotificationAuthorizationRequest,
-                    pidgin_notification_authorization_request,
-                    ADW_TYPE_ACTION_ROW)
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-pidgin_notification_authorization_request_update(PidginNotificationAuthorizationRequest *request) {
-	PurpleAccount *account = NULL;
-	PurpleAuthorizationRequest *purple_request = NULL;
-	const gchar *title = NULL;
-	const gchar *icon_name = NULL, *message = NULL;
-
-	g_return_if_fail(PIDGIN_IS_NOTIFICATION_AUTHORIZATION_REQUEST(request));
-
-	if(!PURPLE_IS_NOTIFICATION(request->notification)) {
-		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(request),
-		                              _("Notification missing"));
-
-		gtk_image_set_from_icon_name(GTK_IMAGE(request->icon), NULL);
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(request), NULL);
-
-		gtk_widget_set_visible(request->accept, FALSE);
-		gtk_widget_set_visible(request->deny, FALSE);
-		gtk_widget_set_visible(request->message, FALSE);
-
-		return;
-	}
-
-	account = purple_notification_get_account(request->notification);
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(request),
-		                              _("Notification is missing an account"));
-
-		gtk_image_set_from_icon_name(GTK_IMAGE(request->icon), NULL);
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(request), NULL);
-
-		gtk_widget_set_visible(request->accept, FALSE);
-		gtk_widget_set_visible(request->deny, FALSE);
-		gtk_widget_set_visible(request->message, FALSE);
-
-		return;
-	}
-
-	purple_request = purple_notification_get_data(request->notification);
-
-	/* Set the icon name if one was specified. */
-	icon_name = purple_notification_get_icon_name(request->notification);
-	if(icon_name == NULL) {
-		PurpleProtocol *protocol = NULL;
-
-		protocol = purple_account_get_protocol(account);
-		icon_name = purple_protocol_get_icon_name(protocol);
-
-		if(icon_name == NULL) {
-			icon_name = "dialog-question";
-		}
-	}
-	gtk_image_set_from_icon_name(GTK_IMAGE(request->icon), icon_name);
-
-	title = purple_notification_get_title(request->notification);
-	adw_preferences_row_set_title(ADW_PREFERENCES_ROW(request), title);
-
-	message = purple_authorization_request_get_message(purple_request);
-	adw_action_row_set_subtitle(ADW_ACTION_ROW(request), message);
-
-	gtk_widget_set_visible(request->accept, TRUE);
-	gtk_widget_set_visible(request->deny, TRUE);
-	gtk_widget_set_visible(request->message, TRUE);
-}
-
-static void
-pidgin_notification_authorization_request_set_notification(PidginNotificationAuthorizationRequest *request,
-                                                           PurpleNotification *notification)
-{
-	if(g_set_object(&request->notification, notification)) {
-		pidgin_notification_authorization_request_update(request);
-
-		g_object_notify_by_pspec(G_OBJECT(request), properties[PROP_NOTIFICATION]);
-	}
-}
-
-static void
-pidgin_notification_authorization_request_close(PidginNotificationAuthorizationRequest *request)
-{
-	PurpleNotificationManager *manager = NULL;
-
-	purple_notification_delete(request->notification);
-
-	manager = purple_notification_manager_get_default();
-	purple_notification_manager_remove(manager, request->notification);
-}
-
-/******************************************************************************
- * Callbacks
- *****************************************************************************/
-static void
-pidgin_notification_authorization_request_accept_cb(G_GNUC_UNUSED GtkButton *button,
-                                                    gpointer data)
-{
-	PidginNotificationAuthorizationRequest *pidgin_request = data;
-	PurpleAuthorizationRequest *request = NULL;
-
-	request = purple_notification_get_data(pidgin_request->notification);
-
-	purple_authorization_request_accept(request);
-
-#if 0
-	if(purple_authorization_request_get_add(request)) {
-		PurpleAccount *account = NULL;
-		const gchar *username = NULL, *alias = NULL;
-
-		account = purple_authorization_request_get_account(request);
-		username = purple_authorization_request_get_username(request);
-		alias = purple_authorization_request_get_alias(request);
-	}
-#endif
-
-	pidgin_notification_authorization_request_close(pidgin_request);
-}
-
-static void
-pidgin_notification_authorization_request_deny_cb(G_GNUC_UNUSED GtkButton *button,
-                                                  gpointer data)
-{
-	PidginNotificationAuthorizationRequest *pidgin_request = data;
-	PurpleAuthorizationRequest *request = NULL;
-
-	request = purple_notification_get_data(pidgin_request->notification);
-
-	purple_authorization_request_deny(request, NULL);
-
-	pidgin_notification_authorization_request_close(pidgin_request);
-}
-
-static void
-pidgin_notification_authorization_request_message_cb(G_GNUC_UNUSED GtkButton *button,
-                                                     gpointer data)
-{
-	PidginNotificationAuthorizationRequest *pidgin_request = data;
-	PurpleAuthorizationRequest *request = NULL;
-	PurpleAccount *account = NULL;
-	PurpleContact *contact = NULL;
-	PurpleContactManager *manager = NULL;
-	PurpleConversation *conversation = NULL;
-	const char *username = NULL;
-
-	request = purple_notification_get_data(pidgin_request->notification);
-
-	account = purple_authorization_request_get_account(request);
-	username = purple_authorization_request_get_username(request);
-
-	manager = purple_contact_manager_get_default();
-	contact = purple_contact_manager_find_with_username(manager, account,
-	                                                    username);
-
-	if(!PURPLE_IS_CONTACT(contact)) {
-		g_warning("failed to find a user named '%s' on account %s",
-		          username,
-		          purple_account_get_username(account));
-
-		return;
-	}
-
-	conversation = purple_contact_find_dm(contact);
-	if(PURPLE_IS_CONVERSATION(conversation)) {
-		purple_conversation_present(conversation);
-	} else {
-		purple_contact_create_dm_async(contact, NULL, NULL, NULL);
-	}
-}
-
-static void
-pidgin_notification_authorization_request_remove_cb(G_GNUC_UNUSED GtkButton *button,
-                                                    gpointer data)
-{
-	PidginNotificationAuthorizationRequest *request = data;
-
-	pidgin_notification_authorization_request_close(request);
-}
-
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-static void
-pidgin_notification_authorization_request_get_property(GObject *obj,
-                                                       guint param_id,
-                                                       GValue *value,
-                                                       GParamSpec *pspec)
-{
-	PidginNotificationAuthorizationRequest *request = NULL;
-
-	request = PIDGIN_NOTIFICATION_AUTHORIZATION_REQUEST(obj);
-
-	switch(param_id) {
-		case PROP_NOTIFICATION:
-			g_value_set_object(value,
-			                   pidgin_notification_authorization_request_get_notification(request));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-pidgin_notification_authorization_request_set_property(GObject *obj,
-                                                       guint param_id,
-                                                       const GValue *value,
-                                                       GParamSpec *pspec)
-{
-	PidginNotificationAuthorizationRequest *request = NULL;
-
-	request = PIDGIN_NOTIFICATION_AUTHORIZATION_REQUEST(obj);
-
-	switch(param_id) {
-		case PROP_NOTIFICATION:
-			pidgin_notification_authorization_request_set_notification(request,
-			                                                           g_value_get_object(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-pidgin_notification_authorization_request_dispose(GObject *obj) {
-	PidginNotificationAuthorizationRequest *request = NULL;
-
-	request = PIDGIN_NOTIFICATION_AUTHORIZATION_REQUEST(obj);
-
-	g_clear_object(&request->notification);
-
-	G_OBJECT_CLASS(pidgin_notification_authorization_request_parent_class)->dispose(obj);
-}
-
-static void
-pidgin_notification_authorization_request_init(PidginNotificationAuthorizationRequest *list)
-{
-	gtk_widget_init_template(GTK_WIDGET(list));
-}
-
-static void
-pidgin_notification_authorization_request_class_init(PidginNotificationAuthorizationRequestClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
-
-	obj_class->get_property = pidgin_notification_authorization_request_get_property;
-	obj_class->set_property = pidgin_notification_authorization_request_set_property;
-	obj_class->dispose = pidgin_notification_authorization_request_dispose;
-
-	/**
-	 * PidginNotificationAuthorizationRequest:notification:
-	 *
-	 * The [class@Purple.Notification] that this notification is for.
-	 *
-	 * Since: 3.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/authorizationrequest.ui"
-	);
-
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAuthorizationRequest,
-	                                     icon);
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAuthorizationRequest,
-	                                     accept);
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAuthorizationRequest,
-	                                     deny);
-	gtk_widget_class_bind_template_child(widget_class,
-	                                     PidginNotificationAuthorizationRequest,
-	                                     message);
-
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_authorization_request_accept_cb);
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_authorization_request_deny_cb);
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_authorization_request_message_cb);
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        pidgin_notification_authorization_request_remove_cb);
-}
-
-/******************************************************************************
- * API
- *****************************************************************************/
-GtkWidget *
-pidgin_notification_authorization_request_new(PurpleNotification *notification) {
-	return g_object_new(
-		PIDGIN_TYPE_NOTIFICATION_AUTHORIZATION_REQUEST,
-		"notification", notification,
-		NULL);
-}
-
-PurpleNotification *
-pidgin_notification_authorization_request_get_notification(PidginNotificationAuthorizationRequest *request)
-{
-	g_return_val_if_fail(PIDGIN_IS_NOTIFICATION_AUTHORIZATION_REQUEST(request),
-	                     NULL);
-
-	return request->notification;
-}
diff --git a/pidgin/pidginnotificationauthorizationrequest.h b/pidgin/pidginnotificationauthorizationrequest.h
deleted file mode 100644
--- a/pidgin/pidginnotificationauthorizationrequest.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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_AUTHORIZATION_REQUEST_H
-#define PIDGIN_NOTIFICATION_AUTHORIZATION_REQUEST_H
-
-#include <glib.h>
-
-#include <gtk/gtk.h>
-
-#include <adwaita.h>
-
-#include <purple.h>
-
-#include "pidginversion.h"
-
-G_BEGIN_DECLS
-
-/**
- * PidginNotificationAuthorizationRequest:
- *
- * #PidginNotificationAuthorizationRequest is a widget that displays
- * notifications from [class@Purple.NotificationManager] for authorization
- * requests.
- *
- * Since: 3.0
- */
-
-#define PIDGIN_TYPE_NOTIFICATION_AUTHORIZATION_REQUEST (pidgin_notification_authorization_request_get_type())
-
-PIDGIN_AVAILABLE_IN_3_0
-G_DECLARE_FINAL_TYPE(PidginNotificationAuthorizationRequest, pidgin_notification_authorization_request,
-                     PIDGIN, NOTIFICATION_AUTHORIZATION_REQUEST, AdwActionRow)
-
-/**
- * pidgin_notification_authorization_request_new:
- * @notification: A [class@Purple.Notification] to display.
- *
- * Creates a new #PidginNotificationAuthorizationRequest instance that will
- * display @notification.
- *
- * Returns: (transfer full): The new #PidginNotificationAuthorizationRequest
- *          instance.
- *
- * Since: 3.0
- */
-PIDGIN_AVAILABLE_IN_3_0
-GtkWidget *pidgin_notification_authorization_request_new(PurpleNotification *notification);
-
-/**
- * pidgin_notification_authorization_request_get_notification:
- * @request: The instance.
- *
- * Gets the [class@Purple.Notification] that @request is displaying.
- *
- * Returns: (transfer none): The notification.
- *
- * Since: 3.0
- */
-PIDGIN_AVAILABLE_IN_3_0
-PurpleNotification *pidgin_notification_authorization_request_get_notification(PidginNotificationAuthorizationRequest *request);
-
-G_END_DECLS
-
-#endif /* PIDGIN_NOTIFICATION_AUTHORIZATION_REQUEST_H */
diff --git a/pidgin/pidginnotificationconnectionerror.c b/pidgin/pidginnotificationconnectionerror.c
deleted file mode 100644
--- a/pidgin/pidginnotificationconnectionerror.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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 {
-	AdwActionRow parent;
-
-	PurpleNotification *notification;
-
-	GtkWidget *icon;
-	GtkWidget *reconnect;
-	GtkWidget *reenable;
-	GtkWidget *modify;
-};
-
-enum {
-	PROP_0,
-	PROP_NOTIFICATION,
-	N_PROPERTIES,
-};
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-G_DEFINE_FINAL_TYPE(PidginNotificationConnectionError,
-                    pidgin_notification_connection_error, ADW_TYPE_ACTION_ROW)
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static void
-pidgin_notification_connection_error_update(PidginNotificationConnectionError *error) {
-	PurpleAccount *account = NULL;
-	PurpleConnectionErrorInfo *info = NULL;
-	const gchar *icon_name = NULL, *account_id = NULL, *title = NULL;
-	gboolean enabled = FALSE;
-
-	g_return_if_fail(PIDGIN_IS_NOTIFICATION_CONNECTION_ERROR(error));
-
-	if(!PURPLE_IS_NOTIFICATION(error->notification)) {
-		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(error),
-		                              _("Notification missing"));
-
-		gtk_image_set_from_icon_name(GTK_IMAGE(error->icon), NULL);
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(error), NULL);
-
-		gtk_widget_set_visible(error->reconnect, FALSE);
-		gtk_widget_set_visible(error->reenable, FALSE);
-		gtk_widget_set_visible(error->modify, FALSE);
-
-		return;
-	}
-
-	account = purple_notification_get_account(error->notification);
-	if(!PURPLE_IS_ACCOUNT(account)) {
-		adw_preferences_row_set_title(ADW_PREFERENCES_ROW(error),
-		                              _("Notification is missing an account"));
-
-		gtk_image_set_from_icon_name(GTK_IMAGE(error->icon), NULL);
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(error), NULL);
-
-		gtk_widget_set_visible(error->reconnect, FALSE);
-		gtk_widget_set_visible(error->reenable, FALSE);
-		gtk_widget_set_visible(error->modify, FALSE);
-
-		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) {
-		gtk_image_set_from_icon_name(GTK_IMAGE(error->icon), icon_name);
-	}
-
-	enabled = purple_account_get_enabled(account);
-
-	title = purple_notification_get_title(error->notification);
-	adw_preferences_row_set_title(ADW_PREFERENCES_ROW(error), title);
-
-	info = purple_notification_get_data(error->notification);
-	if(info != NULL) {
-		adw_action_row_set_subtitle(ADW_ACTION_ROW(error), info->description);
-	} else {
-		adw_action_row_set_subtitle(ADW_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;
-
-	purple_notification_delete(error->notification);
-
-	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:notification:
-	 *
-	 * The [type@Purple.ConnectionErrorInfo] that this notification is for.
-	 *
-	 * Since: 3.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,
-	                                     icon);
-	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;
-}
diff --git a/pidgin/pidginnotificationconnectionerror.h b/pidgin/pidginnotificationconnectionerror.h
deleted file mode 100644
--- a/pidgin/pidginnotificationconnectionerror.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 <adwaita.h>
-
-#include <purple.h>
-
-#include "pidginversion.h"
-
-G_BEGIN_DECLS
-
-/**
- * PidginNotificationConnectionError:
- *
- * #PidginNotificationConnectionError is a widget that displays notifications from
- * [class@Purple.NotificationManager].
- *
- * Since: 3.0
- */
-
-#define PIDGIN_TYPE_NOTIFICATION_CONNECTION_ERROR (pidgin_notification_connection_error_get_type())
-
-PIDGIN_AVAILABLE_IN_3_0
-G_DECLARE_FINAL_TYPE(PidginNotificationConnectionError, pidgin_notification_connection_error,
-                     PIDGIN, NOTIFICATION_CONNECTION_ERROR, AdwActionRow)
-
-/**
- * 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.
- *
- * Since: 3.0
- */
-PIDGIN_AVAILABLE_IN_3_0
-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
- */
-PIDGIN_AVAILABLE_IN_3_0
-PurpleNotification *pidgin_notification_connection_error_get_notification(PidginNotificationConnectionError *error);
-
-G_END_DECLS
-
-#endif /* PIDGIN_NOTIFICATION_CONNECTION_ERROR_H */
diff --git a/pidgin/pidginnotificationlist.c b/pidgin/pidginnotificationlist.c
--- a/pidgin/pidginnotificationlist.c
+++ b/pidgin/pidginnotificationlist.c
@@ -24,12 +24,11 @@
 
 #include <purple.h>
 
-#include "pidgin/pidginnotificationlist.h"
+#include "pidginnotificationlist.h"
 
-#include "pidgin/pidginnotifiable.h"
-#include "pidgin/pidginnotificationaddcontact.h"
-#include "pidgin/pidginnotificationauthorizationrequest.h"
-#include "pidgin/pidginnotificationconnectionerror.h"
+#include "pidginnotifiable.h"
+#include "pidginnotification.h"
+#include "pidginnotificationaddcontact.h"
 
 enum {
 	PROP_0,
@@ -50,27 +49,6 @@
 /******************************************************************************
  * Helpers
  *****************************************************************************/
-static GtkWidget *
-pidgin_notification_generic_new(PurpleNotification *notification) {
-	GtkWidget *row = NULL;
-	GtkWidget *icon = NULL;
-
-	icon = gtk_image_new();
-	gtk_image_set_icon_size(GTK_IMAGE(icon), GTK_ICON_SIZE_LARGE);
-	g_object_bind_property(notification, "icon-name", icon, "icon-name",
-	                       G_BINDING_SYNC_CREATE);
-
-	row = adw_action_row_new();
-	adw_action_row_add_prefix(ADW_ACTION_ROW(row), icon);
-
-	g_object_bind_property(notification, "title", row, "title",
-	                       G_BINDING_SYNC_CREATE);
-	g_object_bind_property(notification, "subtitle", row, "subtitle",
-	                       G_BINDING_SYNC_CREATE);
-
-	return row;
-}
-
 static guint
 pidgin_notification_list_get_count(PidginNotificationList *list) {
 	g_return_val_if_fail(PIDGIN_IS_NOTIFICATION_LIST(list), 0);
@@ -125,20 +103,10 @@
 
 	notification = gtk_list_item_get_item(item);
 
-	switch(purple_notification_get_notification_type(notification)) {
-		case PURPLE_NOTIFICATION_TYPE_CONNECTION_ERROR:
-			widget = pidgin_notification_connection_error_new(notification);
-			break;
-		case PURPLE_NOTIFICATION_TYPE_AUTHORIZATION_REQUEST:
-			widget = pidgin_notification_authorization_request_new(notification);
-			break;
-		case PURPLE_NOTIFICATION_TYPE_ADD_CONTACT:
-			widget = pidgin_notification_add_contact_new(notification);
-			break;
-		case PURPLE_NOTIFICATION_TYPE_GENERIC:
-		default:
-			widget = pidgin_notification_generic_new(notification);
-			break;
+	if(PURPLE_IS_NOTIFICATION_ADD_CONTACT(notification)) {
+		widget = pidgin_notification_add_contact_new(notification);
+	} else {
+		widget = pidgin_notification_new(notification);
 	}
 
 	gtk_list_item_set_child(item, widget);
diff --git a/pidgin/resources/Notifications/authorizationrequest.ui b/pidgin/resources/Notifications/authorizationrequest.ui
deleted file mode 100644
--- a/pidgin/resources/Notifications/authorizationrequest.ui
+++ /dev/null
@@ -1,90 +0,0 @@
-<?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="4.0"/>
-  <requires lib="Adw" version="1.0"/>
-  <!-- interface-license-type gplv2 -->
-  <!-- interface-name Pidgin -->
-  <!-- interface-description Internet Messenger -->
-  <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <template class="PidginNotificationAuthorizationRequest" parent="AdwActionRow">
-    <property name="focusable">1</property>
-    <property name="activatable">0</property>
-    <property name="title-lines">3</property>
-    <property name="subtitle-lines">3</property>
-    <child type="prefix">
-      <object class="GtkImage" id="icon">
-        <property name="icon-size">large</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="accept">
-        <property name="label" translatable="1">Accept</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_authorization_request_accept_cb" object="PidginNotificationAuthorizationRequest" swapped="no"/>
-        <style>
-          <class name="suggested-action"/>
-        </style>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="deny">
-        <property name="label" translatable="1">Deny</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_authorization_request_deny_cb" object="PidginNotificationAuthorizationRequest" swapped="no"/>
-        <style>
-          <class name="destructive-action"/>
-        </style>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="message">
-        <property name="label" translatable="1">Message</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_authorization_request_message_cb" object="PidginNotificationAuthorizationRequest" swapped="no"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="remove">
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="icon-name">edit-delete-symbolic</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_authorization_request_remove_cb" object="PidginNotificationAuthorizationRequest" swapped="no"/>
-        <style>
-          <class name="flat"/>
-        </style>
-      </object>
-    </child>
-  </template>
-</interface>
diff --git a/pidgin/resources/Notifications/connectionerror.ui b/pidgin/resources/Notifications/connectionerror.ui
deleted file mode 100644
--- a/pidgin/resources/Notifications/connectionerror.ui
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-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 library; if not, see <https://www.gnu.org/licenses/>.
--->
-<interface>
-  <requires lib="gtk" version="4.0"/>
-  <requires lib="Adw" version="1.0"/>
-  <!-- interface-license-type gplv2 -->
-  <!-- interface-name Pidgin -->
-  <!-- interface-description Internet Messenger -->
-  <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <template class="PidginNotificationConnectionError" parent="AdwActionRow">
-    <property name="focusable">1</property>
-    <property name="activatable">0</property>
-    <property name="subtitle-lines">3</property>
-    <child type="prefix">
-      <object class="GtkImage" id="icon">
-        <property name="icon-size">large</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="reconnect">
-        <property name="label" translatable="1">Reconnect</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</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="1">Re-enable</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</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="1">Modify Account</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</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="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="icon-name">edit-delete-symbolic</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_connection_error_remove_cb" object="PidginNotificationConnectionError" swapped="no"/>
-        <style>
-          <class name="flat"/>
-        </style>
-      </object>
-    </child>
-  </template>
-</interface>
diff --git a/pidgin/resources/notification.ui b/pidgin/resources/notification.ui
new file mode 100644
--- /dev/null
+++ b/pidgin/resources/notification.ui
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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="4.0"/>
+  <requires lib="Adw" version="1.0"/>
+  <!-- interface-license-type gplv2 -->
+  <!-- interface-name Pidgin -->
+  <!-- interface-description Internet Messenger -->
+  <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
+  <template class="PidginNotification" parent="GtkBox">
+    <property name="orientation">horizontal</property>
+    <property name="spacing">6</property>
+    <property name="margin-start">2</property>
+    <property name="margin-end">2</property>
+    <property name="margin-top">2</property>
+    <property name="margin-bottom">2</property>
+    <child>
+      <object class="GtkImage" id="icon">
+        <property name="icon-size">large</property>
+        <property name="halign">center</property>
+        <property name="valign">center</property>
+        <binding name="icon-name">
+          <lookup name="icon-name" type="PurpleNotification">
+            <lookup name="notification">PidginNotification</lookup>
+          </lookup>
+        </binding>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox" id="details">
+        <property name="halign">fill</property>
+        <property name="hexpand">true</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">0</property>
+        <property name="valign">center</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="ellipsize">end</property>
+            <property name="lines">3</property>
+            <property name="xalign">0</property>
+            <binding name="label">
+              <lookup name="title" type="PurpleNotification">
+                <lookup name="notification">PidginNotification</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="ellipsize">end</property>
+            <property name="lines">3</property>
+            <property name="xalign">0</property>
+            <binding name="label">
+              <lookup name="subtitle" type="PurpleNotification">
+                <lookup name="notification">PidginNotification</lookup>
+              </lookup>
+            </binding>
+            <binding name="visible">
+              <closure type="gboolean" function="pidgin_notification_show_subtitle">
+                <lookup name="subtitle" type="PurpleNotification">
+                  <lookup name="notification">PidginNotification</lookup>
+                </lookup>
+              </closure>
+            </binding>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkButton">
+        <property name="focusable">1</property>
+        <property name="receives-default">1</property>
+        <property name="icon-name">edit-delete-symbolic</property>
+        <property name="halign">center</property>
+        <property name="valign">center</property>
+        <property name="action-name">notification.close</property>
+        <style>
+          <class name="flat"/>
+        </style>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/pidgin/resources/Notifications/addcontact.ui b/pidgin/resources/notificationaddcontact.ui
rename from pidgin/resources/Notifications/addcontact.ui
rename to pidgin/resources/notificationaddcontact.ui
--- a/pidgin/resources/Notifications/addcontact.ui
+++ b/pidgin/resources/notificationaddcontact.ui
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.38.2 
-
+<!--
 Pidgin - Internet Messenger
 Copyright (C) Pidgin Developers <devel@pidgin.im>
 
@@ -20,58 +19,39 @@
 -->
 <interface>
   <requires lib="gtk" version="4.0"/>
-  <requires lib="Adw" version="1.0"/>
   <!-- interface-license-type gplv2 -->
   <!-- interface-name Pidgin -->
   <!-- interface-description Internet Messenger -->
   <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
-  <template class="PidginNotificationAddContact" parent="AdwActionRow">
-    <property name="focusable">1</property>
-    <property name="activatable">0</property>
-    <property name="title-lines">3</property>
-    <property name="subtitle-lines">3</property>
-    <child type="prefix">
-      <object class="GtkImage" id="icon">
-        <property name="icon-size">large</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="add">
-        <property name="label" translatable="1">Add</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_add_contact_add_cb" object="PidginNotificationAddContact" swapped="no"/>
-        <style>
-          <class name="suggested-action"/>
-        </style>
+  <template class="PidginNotificationAddContact" parent="PidginNotification">
+    <property name="child">
+      <object class="GtkBox">
+        <property name="orientation">horizontal</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkButton" id="add">
+            <property name="label" translatable="1">Add</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="action-name">notification.add-contact</property>
+            <style>
+              <class name="suggested-action"/>
+            </style>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="message">
+            <property name="label" translatable="1">Message</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="action-name">notification.message</property>
+          </object>
+        </child>
       </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="message">
-        <property name="label" translatable="1">Message</property>
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_add_contact_message_cb" object="PidginNotificationAddContact" swapped="no"/>
-      </object>
-    </child>
-    <child>
-      <object class="GtkButton" id="remove">
-        <property name="focusable">1</property>
-        <property name="receives-default">1</property>
-        <property name="icon-name">edit-delete-symbolic</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <signal name="clicked" handler="pidgin_notification_add_contact_remove_cb" object="PidginNotificationAddContact" swapped="no"/>
-        <style>
-          <class name="flat"/>
-        </style>
-      </object>
-    </child>
+    </property>
   </template>
 </interface>
diff --git a/pidgin/resources/pidgin.gresource.xml b/pidgin/resources/pidgin.gresource.xml
--- a/pidgin/resources/pidgin.gresource.xml
+++ b/pidgin/resources/pidgin.gresource.xml
@@ -14,9 +14,6 @@
     <file compressed="true" preprocess="xml-stripblanks">Debug/debug.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">Keypad/keypad.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">Media/window.ui</file>
-    <file compressed="true" preprocess="xml-stripblanks">Notifications/addcontact.ui</file>
-    <file compressed="true" preprocess="xml-stripblanks">Notifications/authorizationrequest.ui</file>
-    <file compressed="true" preprocess="xml-stripblanks">Notifications/connectionerror.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">Prefs/away.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">Prefs/conversation.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">Prefs/credentials.ui</file>
@@ -38,6 +35,8 @@
     <file compressed="true" preprocess="xml-stripblanks">display-item.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">display-window.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">infopane.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">notification.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">notificationaddcontact.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">notificationlist.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">presenceicon.ui</file>
     <file compressed="true">style.css</file>
