changeset 21402:9fef5d307a27

Create a PidginMiniDialog widget; make pidgin_make_mini_dialog() in gtkutils.c a relatively thin wrapper around it.
author Will Thompson <will.thompson@collabora.co.uk>
date Sun, 04 Nov 2007 14:43:45 +0000
parents c1c7e28223f8
children 0f029f9a75e1
files pidgin/Makefile.am pidgin/gtkutils.c pidgin/gtkutils.h pidgin/minidialog.c pidgin/minidialog.h
diffstat 5 files changed, 545 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin/Makefile.am	Sat Nov 03 17:08:21 2007 +0000
+++ b/pidgin/Makefile.am	Sun Nov 04 14:43:45 2007 +0000
@@ -118,7 +118,8 @@
 	gtkstatusbox.c \
 	gtkthemes.c \
 	gtkutils.c \
-	gtkwhiteboard.c
+	gtkwhiteboard.c \
+	minidialog.c
 
 pidgin_headers = \
 	eggtrayicon.h \
@@ -170,6 +171,7 @@
 	gtkthemes.h \
 	gtkutils.h \
 	gtkwhiteboard.h \
+	minidialog.h \
 	pidgin.h
 
 pidginincludedir=$(includedir)/pidgin
--- a/pidgin/gtkutils.c	Sat Nov 03 17:08:21 2007 +0000
+++ b/pidgin/gtkutils.c	Sun Nov 04 14:43:45 2007 +0000
@@ -61,6 +61,7 @@
 #include "pidginstock.h"
 #include "gtkthemes.h"
 #include "gtkutils.h"
+#include "pidgin/minidialog.h"
 
 typedef struct {
 	GtkWidget *menu;
@@ -2908,6 +2909,22 @@
 	minidialogs = g_slist_remove(minidialogs, widget);
 }
 
+struct _old_button_clicked_cb_data
+{
+	PidginUtilMiniDialogCallback cb;
+	gpointer data;
+};
+
+static void
+old_mini_dialog_button_clicked_cb(PidginMiniDialog *mini_dialog,
+                                  GtkButton *button,
+                                  gpointer user_data)
+{
+	struct _old_button_clicked_cb_data *data = user_data;
+	data->cb(data->data, button);
+	g_free(data);
+}
+
 GtkWidget *
 pidgin_make_mini_dialog(PurpleConnection *gc,
                         const char *icon_name,
@@ -2916,83 +2933,37 @@
                         void *user_data,
                         ...)
 {
-	GtkWidget *vbox;
-	GtkWidget *hbox;
-	GtkWidget *hbox2;
-	GtkWidget *label;
-	GtkWidget *button;
-	GtkWidget *img = NULL;
-	char label_text[2048];
+	PidginMiniDialog *mini_dialog;
 	const char *button_text;
-	GCallback callback;
-	char *primary_esc, *secondary_esc = NULL;
 	va_list args;
 	static gboolean first_call = TRUE;
 
-	img = gtk_image_new_from_stock(icon_name, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
-	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-
-	vbox = gtk_vbox_new(FALSE,0);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), PIDGIN_HIG_BOX_SPACE);
-
-	g_object_set_data(G_OBJECT(vbox), "gc" ,gc);
-	minidialogs = g_slist_prepend(minidialogs, vbox);
-	g_signal_connect(G_OBJECT(vbox), "destroy", G_CALLBACK(alert_killed_cb), NULL);
-
 	if (first_call) {
 		first_call = FALSE;
 		purple_signal_connect(purple_connections_get_handle(), "signed-off",
-				    pidgin_utils_get_handle(),
-				    PURPLE_CALLBACK(connection_signed_off_cb), NULL);
+		                      pidgin_utils_get_handle(),
+		                      PURPLE_CALLBACK(connection_signed_off_cb), NULL);
 	}
 
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
-	gtk_container_add(GTK_CONTAINER(vbox), hbox);
-
-	if (img != NULL)
-		gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-
-	primary_esc = g_markup_escape_text(primary, -1);
-
-	if (secondary)
-		secondary_esc = g_markup_escape_text(secondary, -1);
-	g_snprintf(label_text, sizeof(label_text),
-		   "<span weight=\"bold\" size=\"smaller\">%s</span>%s<span size=\"smaller\">%s</span>",
-		   primary_esc, secondary ? "\n" : "", secondary_esc ? secondary_esc : "");
-	g_free(primary_esc);
-	g_free(secondary_esc);
-	label = gtk_label_new(NULL);
-	gtk_widget_set_size_request(label, purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width")-25,-1);
-	gtk_label_set_markup(GTK_LABEL(label), label_text);
-	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
-
-	hbox2 = gtk_hbox_new(FALSE, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0);
+	mini_dialog = pidgin_mini_dialog_new(primary, secondary, icon_name);
+	g_object_set_data(G_OBJECT(mini_dialog), "gc" ,gc);
+	g_signal_connect(G_OBJECT(mini_dialog), "destroy",
+		G_CALLBACK(alert_killed_cb), NULL);
 
 	va_start(args, user_data);
 	while ((button_text = va_arg(args, char*))) {
-		callback = va_arg(args, GCallback);
-		button = gtk_button_new();
-
-		if (callback)
-			g_signal_connect_swapped(G_OBJECT(button), "clicked", callback, user_data);
-		g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), vbox);
-		hbox = gtk_hbox_new(FALSE, 0);
-		gtk_container_add(GTK_CONTAINER(button), hbox);
-		gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
-		g_snprintf(label_text, sizeof(label_text),
-			   "<span size=\"smaller\">%s</span>", button_text);
-		label = gtk_label_new(NULL);
-		gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), label_text);
-		gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
-		gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
-		gtk_box_pack_end(GTK_BOX(hbox2), button, FALSE, FALSE, 0);
+		PidginUtilMiniDialogCallback callback =
+			va_arg(args, PidginUtilMiniDialogCallback);
+		struct _old_button_clicked_cb_data *data =
+			g_new0(struct _old_button_clicked_cb_data, 1);
+		data->cb = callback;
+		data->data = user_data;
+		pidgin_mini_dialog_add_button(mini_dialog, button_text,
+			old_mini_dialog_button_clicked_cb, data);
 	}
 	va_end(args);
 
-	return vbox;
+	return GTK_WIDGET(mini_dialog);
 }
 
 /*
--- a/pidgin/gtkutils.h	Sat Nov 03 17:08:21 2007 +0000
+++ b/pidgin/gtkutils.h	Sun Nov 04 14:43:45 2007 +0000
@@ -599,8 +599,13 @@
 char *pidgin_make_pretty_arrows(const char *str);
 
 /**
- * Creates a "mini-dialog" suitable for embedding in the buddy list scrollbook
- * with pidgin_blist_add_alert().
+ * The type of callbacks passed to pidgin_make_mini_dialog().
+ */
+typedef void (*PidginUtilMiniDialogCallback)(gpointer user_data, GtkButton *);
+
+/**
+ * Creates a #PidginMiniDialog, tied to a #PurpleConnection, suitable for
+ * embedding in the buddy list scrollbook with pidgin_blist_add_alert().
  *
  * @param handle         The #PurpleConnection to which this mini-dialog
  *                       refers, or @c NULL if it does not refer to a
@@ -609,19 +614,17 @@
  *                       connection signs off.
  * @param stock_id       The ID of a stock image to use in the mini dialog.
  * @param primary        The primary text
- * @param secondary      The secondary text
+ * @param secondary      The secondary text, or @c NULL for no description.
  * @param user_data      Data to pass to the callbacks
  * @param ...            a <tt>NULL</tt>-terminated list of button labels
- *                       (<tt>char *</tt>) and callbacks, which should take a
- *                       <tt>void *</tt> argument, as which @a user_data will
- *                       be passed.  (Strictly speaking a <tt>GtkButton *</tt>
- *                       will be passed as the second argument, but it can
- *                       safely be omitted.)  When a button is pressed, the
- *                       callback will be called; when the callback returns the
- *                       dialog will evaporate.  Callbacks may be @c NULL, in
- *                       which case pressing the corresponding button simply
- *                       dismisses the dialog.
- * @return               The dialog widget, suitable for passing to
+ *                       (<tt>char *</tt>) and callbacks
+ *                       (#PidginUtilMiniDialogCallback).  @a user_data will be
+ *                       passed as the first argument.  (Callbacks may lack a
+ *                       second argument, or be @c NULL to take no action when
+ *                       the corresponding button is pressed.) When a button is
+ *                       pressed, the callback (if any) will be called; when
+ *                       the callback returns the dialog will be destroyed.
+ * @return               A #PidginMiniDialog, suitable for passing to
  *                       pidgin_blist_add_alert().
  * @see pidginstock.h
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/minidialog.c	Sun Nov 04 14:43:45 2007 +0000
@@ -0,0 +1,342 @@
+/**
+ * @file minidialog.c Implementation of the #PidginMiniDialog Gtk widget.
+ * @ingroup pidgin
+ */
+
+/* pidgin
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkbutton.h>
+
+#include "libpurple/prefs.h"
+
+#include "pidgin/minidialog.h"
+#include "pidgin/pidgin.h"
+#include "pidgin/pidginstock.h"
+
+G_DEFINE_TYPE (PidginMiniDialog, pidgin_mini_dialog, GTK_TYPE_VBOX)
+
+enum
+{
+	PROP_TITLE = 1,
+	PROP_DESCRIPTION,
+	PROP_ICON_NAME,
+
+	LAST_PROPERTY
+} HazeConnectionProperties;
+
+typedef struct _PidginMiniDialogPrivate
+{
+	GtkImage *icon;
+	GtkBox *label_box;
+	GtkLabel *title;
+	GtkLabel *description;
+	GtkBox *buttons;
+} PidginMiniDialogPrivate;
+
+#define PIDGIN_MINI_DIALOG_GET_PRIVATE(dialog) \
+	((PidginMiniDialogPrivate *) ((dialog)->priv))
+
+PidginMiniDialog *
+pidgin_mini_dialog_new(const gchar *title,
+                       const gchar *description,
+                       const gchar *icon_name)
+{
+	PidginMiniDialog *mini_dialog = g_object_new(PIDGIN_TYPE_MINI_DIALOG,
+		"title", title,
+		"description", description,
+		"icon-name", icon_name,
+		NULL);
+
+	return mini_dialog;
+}
+
+void
+pidgin_mini_dialog_set_title(PidginMiniDialog *mini_dialog,
+                             const char *title)
+{
+	g_object_set(G_OBJECT(mini_dialog), "title", title, NULL);
+}
+
+void
+pidgin_mini_dialog_set_description(PidginMiniDialog *mini_dialog,
+                                   const char *description)
+{
+	g_object_set(G_OBJECT(mini_dialog), "description", description, NULL);
+}
+
+void
+pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog,
+                                 const char *icon_name)
+{
+	g_object_set(G_OBJECT(mini_dialog), "icon_name", icon_name, NULL);
+}
+
+struct _mini_dialog_button_clicked_cb_data
+{
+	PidginMiniDialog *mini_dialog;
+	PidginMiniDialogCallback callback;
+	gpointer user_data;
+};
+
+static void
+mini_dialog_button_clicked_cb(GtkButton *button,
+                              gpointer user_data)
+{
+	struct _mini_dialog_button_clicked_cb_data *data = user_data;
+
+	data->callback(data->mini_dialog, button, data->user_data);
+
+	gtk_widget_destroy(GTK_WIDGET(data->mini_dialog));
+}
+
+static void
+mini_dialog_button_destroy_cb(GtkButton *button,
+                              gpointer user_data)
+{
+	struct _mini_dialog_button_clicked_cb_data *data = user_data;
+	g_free(data);
+}
+
+void
+pidgin_mini_dialog_add_button(PidginMiniDialog *self,
+                              const char *text,
+                              PidginMiniDialogCallback clicked_cb,
+                              gpointer user_data)
+{
+	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
+	struct _mini_dialog_button_clicked_cb_data *callback_data
+		= g_new0(struct _mini_dialog_button_clicked_cb_data, 1);
+	GtkWidget *button = gtk_button_new();
+	GtkWidget *label = gtk_label_new(NULL);
+	char *button_text =
+		g_strdup_printf("<span size=\"smaller\">%s</span>", text);
+
+	gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), button_text);
+	g_free(button_text);
+
+	callback_data->mini_dialog = self;
+	callback_data->callback = clicked_cb;
+	callback_data->user_data = user_data;
+	g_signal_connect(G_OBJECT(button), "clicked",
+		(GCallback) mini_dialog_button_clicked_cb, callback_data);
+	g_signal_connect(G_OBJECT(button), "destroy",
+		(GCallback) mini_dialog_button_destroy_cb, callback_data);
+
+	gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
+	gtk_container_add(GTK_CONTAINER(button), label);
+
+	gtk_box_pack_end(GTK_BOX(priv->buttons), button, FALSE, FALSE,
+		0);
+	gtk_widget_show(GTK_WIDGET(button));
+}
+
+static void
+pidgin_mini_dialog_get_property(GObject *object,
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+	PidginMiniDialog *self = PIDGIN_MINI_DIALOG(object);
+	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
+
+	switch (property_id) {
+		case PROP_TITLE:
+			g_value_set_string(value, gtk_label_get_text(priv->title));
+			break;
+		case PROP_DESCRIPTION:
+			g_value_set_string(value, gtk_label_get_text(priv->description));
+			break;
+		case PROP_ICON_NAME:
+		{
+			gchar *icon_name = NULL;
+			GtkIconSize size;
+			gtk_image_get_stock(priv->icon, &icon_name, &size);
+			g_value_set_string(value, icon_name);
+			break;
+		}
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+mini_dialog_set_title(PidginMiniDialog *self,
+                      const char *title)
+{
+	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
+
+	char *title_esc = g_markup_escape_text(title, -1);
+	char *title_markup = g_strdup_printf(
+		"<span weight=\"bold\" size=\"smaller\">%s</span>",
+		title_esc ? title_esc : "");
+
+	gtk_label_set_markup(priv->title, title_markup);
+
+	g_free(title_esc);
+	g_free(title_markup);
+}
+
+static void
+mini_dialog_set_description(PidginMiniDialog *self,
+                            const char *description)
+{
+	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
+	if(description)
+	{
+		char *desc_esc = g_markup_escape_text(description, -1);
+		char *desc_markup = g_strdup_printf(
+			"<span size=\"smaller\">%s</span>", desc_esc);
+
+		gtk_label_set_markup(priv->description, desc_markup);
+
+		g_free(desc_esc);
+		g_free(desc_markup);
+
+		gtk_widget_show(GTK_WIDGET(priv->description));
+	}
+	else
+	{
+		gtk_label_set_text(priv->description, NULL);
+		gtk_widget_hide(GTK_WIDGET(priv->description));
+	}
+}
+
+static void
+pidgin_mini_dialog_set_property(GObject *object,
+                                guint property_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+	PidginMiniDialog *self = PIDGIN_MINI_DIALOG(object);
+	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
+
+	switch (property_id) {
+		case PROP_TITLE:
+			mini_dialog_set_title(self, g_value_get_string(value));
+			break;
+		case PROP_DESCRIPTION:
+			mini_dialog_set_description(self, g_value_get_string(value));
+			break;
+		case PROP_ICON_NAME:
+			gtk_image_set_from_stock(priv->icon, g_value_get_string(value),
+				gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+pidgin_mini_dialog_finalize(GObject *object)
+{
+	PidginMiniDialog *self = PIDGIN_MINI_DIALOG(object);
+	PidginMiniDialogPrivate *priv = PIDGIN_MINI_DIALOG_GET_PRIVATE(self);
+
+	g_free(priv);
+	self->priv = NULL;
+
+	G_OBJECT_CLASS (pidgin_mini_dialog_parent_class)->finalize (object);
+}
+
+static void
+pidgin_mini_dialog_class_init(PidginMiniDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS(klass);
+	GParamSpec *param_spec;
+
+	object_class->get_property = pidgin_mini_dialog_get_property;
+	object_class->set_property = pidgin_mini_dialog_set_property;
+	object_class->finalize = pidgin_mini_dialog_finalize;
+
+	param_spec = g_param_spec_string("title", "title",
+		"String specifying the mini-dialog's title", NULL,
+#if GTK_CHECK_VERSION(2,8,0)
+		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+#endif
+		G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_TITLE, param_spec);
+
+	param_spec = g_param_spec_string("description", "description",
+		"Description text for the mini-dialog, if desired", NULL,
+#if GTK_CHECK_VERSION(2,8,0)
+		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+#endif
+		G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_DESCRIPTION, param_spec);
+
+	param_spec = g_param_spec_string("icon-name", "icon-name",
+		"String specifying the Gtk stock name of the dialog's icon",
+		NULL,
+#if GTK_CHECK_VERSION(2,8,0)
+		G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+#endif
+		G_PARAM_READWRITE);
+	g_object_class_install_property (object_class, PROP_ICON_NAME, param_spec);
+}
+
+static void
+pidgin_mini_dialog_init(PidginMiniDialog *self)
+{
+	GtkBox *self_box = GTK_BOX(self);
+	PidginMiniDialogPrivate *priv = g_new0(PidginMiniDialogPrivate, 1);
+	self->priv = priv;
+
+	gtk_container_set_border_width(GTK_CONTAINER(self), PIDGIN_HIG_BOX_SPACE);
+
+	priv->label_box = GTK_BOX(gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE));
+
+	priv->icon = GTK_IMAGE(gtk_image_new());
+	gtk_misc_set_alignment(GTK_MISC(priv->icon), 0, 0);
+
+	priv->title = GTK_LABEL(gtk_label_new(""));
+	/* TODO: update this request when /blist/width updates.  Also, 25 is
+	 * magic.
+	 */
+	gtk_widget_set_size_request(GTK_WIDGET(priv->title),
+		purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width")-25, -1);
+	gtk_label_set_line_wrap(priv->title, TRUE);
+	gtk_misc_set_alignment(GTK_MISC(priv->title), 0, 0);
+
+	gtk_box_pack_start(priv->label_box, GTK_WIDGET(priv->icon), FALSE, FALSE, 0);
+	gtk_box_pack_start(priv->label_box, GTK_WIDGET(priv->title), TRUE, TRUE, 0);
+
+	priv->description = GTK_LABEL(gtk_label_new(""));
+	/* TODO: update this request when /blist/width updates.  Also, 25 is
+	 * magic.
+	 */
+	gtk_widget_set_size_request(GTK_WIDGET(priv->description),
+		purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width")-25, -1);
+	gtk_label_set_line_wrap(priv->description, TRUE);
+	gtk_misc_set_alignment(GTK_MISC(priv->description), 0, 0);
+
+	self->contents = GTK_BOX(gtk_vbox_new(FALSE, 0));
+	priv->buttons = GTK_BOX(gtk_hbox_new(FALSE, 0));
+
+	gtk_box_pack_start(self_box, GTK_WIDGET(priv->label_box), FALSE, FALSE, 0);
+	gtk_box_pack_start(self_box, GTK_WIDGET(priv->description), FALSE, FALSE, 0);
+	gtk_box_pack_start(self_box, GTK_WIDGET(self->contents), TRUE, TRUE, 0);
+	gtk_box_pack_start(self_box, GTK_WIDGET(priv->buttons), FALSE, FALSE, 0);
+
+	gtk_widget_show_all(GTK_WIDGET(self));
+	gtk_widget_hide(GTK_WIDGET(priv->description));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pidgin/minidialog.h	Sun Nov 04 14:43:45 2007 +0000
@@ -0,0 +1,151 @@
+/**
+ * @file minidialog.h API for the #PidginMiniDialog Gtk widget.
+ * @ingroup pidgin
+ */
+
+/* pidgin
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef __PIDGIN_MINI_DIALOG_H__
+#define __PIDGIN_MINI_DIALOG_H__
+
+#include <glib-object.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtklabel.h>
+
+G_BEGIN_DECLS
+
+#define PIDGIN_TYPE_MINI_DIALOG pidgin_mini_dialog_get_type()
+
+#define PIDGIN_MINI_DIALOG(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  PIDGIN_TYPE_MINI_DIALOG, PidginMiniDialog))
+
+#define PIDGIN_MINI_DIALOG_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  PIDGIN_TYPE_MINI_DIALOG, PidginMiniDialogClass))
+
+#define PIDGIN_IS_MINI_DIALOG(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  PIDGIN_TYPE_MINI_DIALOG))
+
+#define PIDGIN_IS_MINI_DIALOG_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  PIDGIN_TYPE_MINI_DIALOG))
+
+#define PIDGIN_MINI_DIALOG_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  PIDGIN_TYPE_MINI_DIALOG, PidginMiniDialogClass))
+
+/**
+ * A widget resembling a diminutive dialog box, designed to be embedded in the
+ * #PidginBuddyList.  Mini-dialogs have titles, optional descriptions, and a row
+ * of buttons at the bottom; above the buttons is a <tt>GtkHBox</tt> into which
+ * you can pack any random widgets you want to add to the dialog.  When any of
+ * the dialog's buttons is clicked, the dialog will be destroyed.
+ *
+ * Dialogs have the following GObject properties:
+ * <dl>
+ *   <dt><tt>"title"</tt> (<tt>char *</tt>)</dt>
+ *   <dd>A string to be displayed as the dialog's title.</dd>
+ *   <dt><tt>"description"</tt> (<tt>char *</tt>)</dt>
+ *   <dd>A string to be displayed as the dialog's description.  If this is @c
+ *       NULL, the description widget will be hidden.
+ *   </dd>
+ *   <dt><tt>"icon-name"</tt> (<tt>char *</tt>)</dt>
+ *   <dd>The Gtk stock id of an icon for the dialog, or @c NULL for no icon.
+ *       @see pidginstock.h
+ *   </dd>
+ * </dl>
+ */
+typedef struct {
+	GtkVBox parent;
+
+	/** A GtkVBox into which extra widgets for the dialog should be packed.
+	 */
+	GtkBox *contents;
+
+	gpointer priv;
+} PidginMiniDialog;
+
+/** The class of #PidginMiniDialog objects. */
+typedef struct {
+	GtkBoxClass parent_class;
+} PidginMiniDialogClass;
+
+/** The type of a callback triggered by a button in a mini-dialog being pressed.
+ * @param mini_dialog a dialog, one of whose buttons has been pressed.
+ * @param button      the button which was pressed.
+ * @param user_data   arbitrary data, supplied to
+ *                    pidgin_mini_dialog_add_button() when the button was
+ *                    created.
+ */
+typedef void (*PidginMiniDialogCallback)(PidginMiniDialog *mini_dialog,
+	GtkButton *button, gpointer user_data);
+
+/** Get the GType of #PidginMiniDialog. */
+GType pidgin_mini_dialog_get_type (void);
+
+/** Creates a new #PidginMiniDialog.  This is a shortcut for creating the dialog
+ *  with @c g_object_new() then setting each property yourself.
+ *  @return a new #PidginMiniDialog.
+ */
+PidginMiniDialog *pidgin_mini_dialog_new(const gchar *title,
+	const gchar *description, const gchar *icon_name);
+
+/** Shortcut for setting a mini-dialog's title via GObject properties.
+ *  @param mini_dialog a mini-dialog
+ *  @param title       the new title for @a mini_dialog
+ */
+void pidgin_mini_dialog_set_title(PidginMiniDialog *mini_dialogtitle ,
+	const char *title);
+
+/** Shortcut for setting a mini-dialog's description via GObject properties.
+ *  @param mini_dialog a mini-dialog
+ *  @param description the new description for @a mini_dialog, or @c NULL to
+ *                     hide the description widget.
+ */
+void pidgin_mini_dialog_set_description(PidginMiniDialog *mini_dialog,
+	const char *description);
+
+/** Shortcut for setting a mini-dialog's icon via GObject properties.
+ *  @param mini_dialog a mini-dialog
+ *  @param title       the Gtk stock ID of an icon, or @c NULL for no icon.
+ */
+void pidgin_mini_dialog_set_icon_name(PidginMiniDialog *mini_dialog,
+	const char *icon_name);
+
+/** Adds a new button to a mini-dialog, and attaches the supplied callback to
+ *  its <tt>clicked</tt> signal.  After a button is clicked, the dialog is
+ *  destroyed.
+ *  @param mini_dialog a mini-dialog
+ *  @param text        the text to display on the new button
+ *  @param clicked_cb  the function to call when the button is clicked
+ *  @param user_data   arbitrary data to pass to @a clicked_cb when it is
+ *                     called.
+ */
+void pidgin_mini_dialog_add_button(PidginMiniDialog *mini_dialog,
+	const char *text, PidginMiniDialogCallback clicked_cb,
+	gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __PIDGIN_MINI_DIALOG_H__ */