changeset 26884:88c87a40a738

A patch from Gabriel Schulhof, updated to apply by Paul 'darkrain42' Aurich, which eliminates code duplication in gtkblist.c. Fixes #3553 committer: Richard Laager <rlaager@wiktel.com>
author Gabriel Schulhof <nix@go-nix.ca>
date Sat, 16 May 2009 19:06:53 +0000
parents 7c58f6f50f16
children 8290e36a5a73
files pidgin/gtkblist.c
diffstat 1 files changed, 246 insertions(+), 461 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin/gtkblist.c	Sat May 16 17:11:50 2009 +0000
+++ b/pidgin/gtkblist.c	Sat May 16 19:06:53 2009 +0000
@@ -75,47 +75,40 @@
 typedef struct
 {
 	PurpleAccount *account;
-
 	GtkWidget *window;
+	GtkBox *vbox;
+	GtkWidget *account_menu;
+	GtkSizeGroup *sg;
+} PidginBlistRequestData;
+
+typedef struct
+{
+	PidginBlistRequestData rq_data;
 	GtkWidget *combo;
 	GtkWidget *entry;
 	GtkWidget *entry_for_alias;
-	GtkWidget *account_box;
 
 } PidginAddBuddyData;
 
 typedef struct
 {
-	PurpleAccount *account;
+	PidginBlistRequestData rq_data;
 	gchar *default_chat_name;
-
-	GtkWidget *window;
-	GtkWidget *account_menu;
+	GList *entries;
+} PidginChatData;
+
+typedef struct
+{
+	PidginChatData chat_data;
+
 	GtkWidget *alias_entry;
 	GtkWidget *group_combo;
-	GtkWidget *entries_box;
-	GtkSizeGroup *sg;
 	GtkWidget *autojoin;
 	GtkWidget *persistent;
-
-	GList *entries;
-
 } PidginAddChatData;
 
 typedef struct
 {
-	PurpleAccount *account;
-
-	GtkWidget *window;
-	GtkWidget *account_menu;
-	GtkWidget *entries_box;
-	GtkSizeGroup *sg;
-
-	GList *entries;
-} PidginJoinChatData;
-
-typedef struct
-{
 	/** Used to hold error minidialogs.  Gets packed
 	 *  inside PidginBuddyList.error_buttons
 	 */
@@ -868,7 +861,7 @@
 }
 
 static void
-do_join_chat(PidginJoinChatData *data)
+do_join_chat(PidginChatData *data)
 {
 	if (data)
 	{
@@ -894,14 +887,14 @@
 			}
 		}
 
-		chat = purple_chat_new(data->account, NULL, components);
+		chat = purple_chat_new(data->rq_data.account, NULL, components);
 		gtk_blist_join_chat(chat);
 		purple_blist_remove_chat(chat);
 	}
 }
 
 static void
-do_joinchat(GtkWidget *dialog, int id, PidginJoinChatData *info)
+do_joinchat(GtkWidget *dialog, int id, PidginChatData *info)
 {
 	switch(id)
 	{
@@ -910,7 +903,7 @@
 			break;
 
 		case 1:
-			pidgin_roomlist_dialog_show_with_account(info->account);
+			pidgin_roomlist_dialog_show_with_account(info->rq_data.account);
 			return;
 
 		break;
@@ -926,11 +919,11 @@
  * strings are empty then don't allow the user to click on "OK."
  */
 static void
-joinchat_set_sensitive_if_input_cb(GtkWidget *entry, gpointer user_data)
+set_sensitive_if_input_cb(GtkWidget *entry, gpointer user_data)
 {
 	PurplePluginProtocolInfo *prpl_info;
 	PurpleConnection *gc;
-	PidginJoinChatData *data;
+	PidginChatData *data;
 	GList *tmp;
 	const char *text;
 	gboolean required;
@@ -949,13 +942,13 @@
 		}
 	}
 
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), GTK_RESPONSE_OK, sensitive);
-
-	gc = purple_account_get_connection(data->account);
+	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->rq_data.window), GTK_RESPONSE_OK, sensitive);
+
+	gc = purple_account_get_connection(data->rq_data.account);
 	prpl_info = (gc != NULL) ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
 	sensitive = (prpl_info != NULL && prpl_info->roomlist_get_list != NULL);
 
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), 1, sensitive);
+	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->rq_data.window), 1, sensitive);
 }
 
 static void
@@ -967,97 +960,6 @@
 	pidgin_blist_update_buddy(purple_get_blist(), PURPLE_BLIST_NODE(buddy), TRUE);
 }
 
-static void
-rebuild_joinchat_entries(PidginJoinChatData *data)
-{
-	PurpleConnection *gc;
-	GList *list = NULL, *tmp;
-	GHashTable *defaults = NULL;
-	struct proto_chat_entry *pce;
-	gboolean focus = TRUE;
-
-	g_return_if_fail(data->account != NULL);
-
-	gc = purple_account_get_connection(data->account);
-
-	gtk_container_foreach(GTK_CONTAINER(data->entries_box), (GtkCallback)gtk_widget_destroy, NULL);
-
-	g_list_free(data->entries);
-	data->entries = NULL;
-
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
-		list = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info(gc);
-
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
-		defaults = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, NULL);
-
-	for (tmp = list; tmp; tmp = tmp->next)
-	{
-		GtkWidget *input;
-
-		pce = tmp->data;
-
-		if (pce->is_int)
-		{
-			GtkObject *adjust;
-			adjust = gtk_adjustment_new(pce->min, pce->min, pce->max,
-										1, 10, 10);
-			input = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
-			gtk_widget_set_size_request(input, 50, -1);
-			pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, FALSE, NULL);
-		}
-		else
-		{
-			char *value;
-			input = gtk_entry_new();
-			gtk_entry_set_activates_default(GTK_ENTRY(input), TRUE);
-			value = g_hash_table_lookup(defaults, pce->identifier);
-			if (value != NULL)
-				gtk_entry_set_text(GTK_ENTRY(input), value);
-			if (pce->secret)
-			{
-				gtk_entry_set_visibility(GTK_ENTRY(input), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-				if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*')
-					gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
-			}
-			pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL);
-			g_signal_connect(G_OBJECT(input), "changed",
-							 G_CALLBACK(joinchat_set_sensitive_if_input_cb), data);
-		}
-
-		/* Do the following for any type of input widget */
-		if (focus)
-		{
-			gtk_widget_grab_focus(input);
-			focus = FALSE;
-		}
-		g_object_set_data(G_OBJECT(input), "identifier", (gpointer)pce->identifier);
-		g_object_set_data(G_OBJECT(input), "is_spin", GINT_TO_POINTER(pce->is_int));
-		g_object_set_data(G_OBJECT(input), "required", GINT_TO_POINTER(pce->required));
-		data->entries = g_list_append(data->entries, input);
-
-		g_free(pce);
-	}
-
-	g_list_free(list);
-	g_hash_table_destroy(defaults);
-
-	/* Set whether the "OK" button should be clickable initially */
-	joinchat_set_sensitive_if_input_cb(NULL, data);
-
-	gtk_widget_show_all(data->entries_box);
-}
-
-static void
-joinchat_select_account_cb(GObject *w, PurpleAccount *account,
-                           PidginJoinChatData *data)
-{
-    data->account = account;
-    rebuild_joinchat_entries(data);
-}
-
 static gboolean
 chat_account_filter_func(PurpleAccount *account)
 {
@@ -1085,32 +987,38 @@
 	return FALSE;
 }
 
-void
-pidgin_blist_joinchat_show(void)
-{
-	GtkWidget *hbox, *vbox;
+static GtkWidget *
+make_blist_request_dialog(PidginBlistRequestData *data, PurpleAccount *account,
+	const char *title, const char *window_role, const char *label_text, 
+	GCallback callback_func, PurpleFilterAccountFunc filter_func,
+	GCallback response_cb)
+{
 	GtkWidget *label;
+	GtkWidget *img;
+	GtkWidget *hbox;
+	GtkWidget *vbox;
+	GtkWindow *blist_window;
 	PidginBuddyList *gtkblist;
-	GtkWidget *img = NULL;
-	PidginJoinChatData *data = NULL;
-
-	gtkblist = purple_blist_get_ui_data();
+
+	data->account = account;
+
 	img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION,
-					gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
-	data = g_new0(PidginJoinChatData, 1);
-
-	data->window = gtk_dialog_new_with_buttons(_("Join a Chat"),
-		NULL, GTK_DIALOG_NO_SEPARATOR,
-		_("Room _List"), 1,
-		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-		PIDGIN_STOCK_CHAT, GTK_RESPONSE_OK, NULL);
+		gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
+
+	gtkblist = PIDGIN_BLIST(purple_get_blist());
+	blist_window = gtkblist ? GTK_WINDOW(gtkblist->window) : NULL;
+
+	data->window = gtk_dialog_new_with_buttons(title,
+		blist_window, GTK_DIALOG_NO_SEPARATOR,
+		NULL);
+
+	gtk_window_set_transient_for(GTK_WINDOW(data->window), blist_window);
 	gtk_dialog_set_default_response(GTK_DIALOG(data->window), GTK_RESPONSE_OK);
 	gtk_container_set_border_width(GTK_CONTAINER(data->window), PIDGIN_HIG_BOX_SPACE);
 	gtk_window_set_resizable(GTK_WINDOW(data->window), FALSE);
 	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BORDER);
-	gtk_container_set_border_width(
-		GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BOX_SPACE);
-	gtk_window_set_role(GTK_WINDOW(data->window), "join_chat");
+	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BOX_SPACE);
+	gtk_window_set_role(GTK_WINDOW(data->window), window_role);
 
 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
 	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), hbox);
@@ -1118,37 +1026,154 @@
 	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
 
 	vbox = gtk_vbox_new(FALSE, 5);
-	gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
 	gtk_container_add(GTK_CONTAINER(hbox), vbox);
 
-	label = gtk_label_new(_("Please enter the appropriate information "
-							"about the chat you would like to join.\n"));
+	label = gtk_label_new(label_text);
+
+	gtk_widget_set_size_request(label, 400, -1);
 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
 
 	data->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
-	data->account_menu = pidgin_account_option_menu_new(NULL, FALSE,
-			G_CALLBACK(joinchat_select_account_cb),
-			chat_account_filter_func, data);
-
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Account:"), data->sg, data->account_menu, TRUE, NULL);
-
-	data->entries_box = gtk_vbox_new(FALSE, 5);
-	gtk_container_add(GTK_CONTAINER(vbox), data->entries_box);
-	gtk_container_set_border_width(GTK_CONTAINER(data->entries_box), 0);
-
-	data->account =	pidgin_account_option_menu_get_selected(data->account_menu);
-
-	rebuild_joinchat_entries(data);
-
-	g_signal_connect(G_OBJECT(data->window), "response",
-					 G_CALLBACK(do_joinchat), data);
+	data->account_menu = pidgin_account_option_menu_new(account, FALSE,
+			callback_func, filter_func, data);
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("A_ccount"), data->sg, data->account_menu, TRUE, NULL);
+
+	data->vbox = GTK_BOX(gtk_vbox_new(FALSE, 5));
+	gtk_container_set_border_width(GTK_CONTAINER(data->vbox), 0);
+	gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(data->vbox), FALSE, FALSE, 0);
+
+	g_signal_connect(G_OBJECT(data->window), "response", response_cb, data);
 
 	g_object_unref(data->sg);
 
-	gtk_widget_show_all(data->window);
+	return vbox;
+}
+
+static void
+rebuild_chat_entries(PidginChatData *data, const char *default_chat_name)
+{
+	PurpleConnection *gc;
+	GList *list = NULL, *tmp;
+	GHashTable *defaults = NULL;
+	struct proto_chat_entry *pce;
+	gboolean focus = TRUE;
+
+	g_return_if_fail(data->rq_data.account != NULL);
+
+	gc = purple_account_get_connection(data->rq_data.account);
+
+	gtk_container_foreach(GTK_CONTAINER(data->rq_data.vbox), (GtkCallback)gtk_widget_destroy, NULL);
+
+	g_list_free(data->entries);
+	data->entries = NULL;
+
+	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
+		list = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info(gc);
+
+	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
+		defaults = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, default_chat_name);
+
+	for (tmp = list; tmp; tmp = tmp->next)
+	{
+		GtkWidget *input;
+
+		pce = tmp->data;
+
+		if (pce->is_int)
+		{
+			GtkObject *adjust;
+			adjust = gtk_adjustment_new(pce->min, pce->min, pce->max,
+										1, 10, 10);
+			input = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
+			gtk_widget_set_size_request(input, 50, -1);
+			pidgin_add_widget_to_vbox(GTK_BOX(data->rq_data.vbox), pce->label, data->rq_data.sg, input, FALSE, NULL);
+		}
+		else
+		{
+			char *value;
+			input = gtk_entry_new();
+			gtk_entry_set_activates_default(GTK_ENTRY(input), TRUE);
+			value = g_hash_table_lookup(defaults, pce->identifier);
+			if (value != NULL)
+				gtk_entry_set_text(GTK_ENTRY(input), value);
+			if (pce->secret)
+			{
+				gtk_entry_set_visibility(GTK_ENTRY(input), FALSE);
+#if !GTK_CHECK_VERSION(2,16,0)
+				if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*')
+					gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR);
+#endif /* Less than GTK+ 2.16 */
+			}
+			pidgin_add_widget_to_vbox(data->rq_data.vbox, pce->label, data->rq_data.sg, input, TRUE, NULL);
+			g_signal_connect(G_OBJECT(input), "changed",
+							 G_CALLBACK(set_sensitive_if_input_cb), data);
+		}
+
+		/* Do the following for any type of input widget */
+		if (focus)
+		{
+			gtk_widget_grab_focus(input);
+			focus = FALSE;
+		}
+		g_object_set_data(G_OBJECT(input), "identifier", (gpointer)pce->identifier);
+		g_object_set_data(G_OBJECT(input), "is_spin", GINT_TO_POINTER(pce->is_int));
+		g_object_set_data(G_OBJECT(input), "required", GINT_TO_POINTER(pce->required));
+		data->entries = g_list_append(data->entries, input);
+
+		g_free(pce);
+	}
+
+	g_list_free(list);
+	g_hash_table_destroy(defaults);
+
+	/* Set whether the "OK" button should be clickable initially */
+	set_sensitive_if_input_cb(NULL, data);
+
+	gtk_widget_show_all(GTK_WIDGET(data->rq_data.vbox));
+}
+
+static void
+chat_select_account_cb(GObject *w, PurpleAccount *account,
+                       PidginChatData *data)
+{
+	if (strcmp(purple_account_get_protocol_id(data->rq_data.account),
+	           purple_account_get_protocol_id(account)) == 0)
+	{
+		data->rq_data.account = account;
+	}
+	else
+	{
+		data->rq_data.account = account;
+		rebuild_chat_entries(data, data->default_chat_name);
+	}
+}
+
+void
+pidgin_blist_joinchat_show(void)
+{
+	PidginChatData *data = NULL;
+
+	data = g_new0(PidginChatData, 1);
+
+	make_blist_request_dialog((PidginBlistRequestData *)data, NULL,
+		_("Join a Chat"), "join_chat",
+		_("Please enter the appropriate information about the chat "
+			"you would like to join.\n"),
+		G_CALLBACK(chat_select_account_cb),
+		chat_account_filter_func, (GCallback)do_joinchat);
+	gtk_dialog_add_buttons(GTK_DIALOG(data->rq_data.window),
+		_("Room _List"), 1,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		PIDGIN_STOCK_CHAT, GTK_RESPONSE_OK, NULL);
+	data->default_chat_name = NULL;
+	data->rq_data.account = pidgin_account_option_menu_get_selected(data->rq_data.account_menu);
+
+	rebuild_chat_entries(data, NULL);
+
+	gtk_widget_show_all(data->rq_data.window);
 }
 
 static void gtk_blist_row_expanded_cb(GtkTreeView *tv, GtkTreeIter *iter, GtkTreePath *path, gpointer user_data)
@@ -6734,7 +6759,7 @@
 							PidginAddBuddyData *data)
 {
 	/* Save our account */
-	data->account = account;
+	data->rq_data.account = account;
 }
 
 static void
@@ -6747,6 +6772,7 @@
 add_buddy_cb(GtkWidget *w, int resp, PidginAddBuddyData *data)
 {
 	const char *grp, *who, *whoalias;
+	PurpleAccount *account;
 	PurpleGroup *g;
 	PurpleBuddy *b;
 	PurpleConversation *c;
@@ -6760,6 +6786,8 @@
 		if (*whoalias == '\0')
 			whoalias = NULL;
 
+		account = data->rq_data.account;
+
 		g = NULL;
 		if ((grp != NULL) && (*grp != '\0'))
 		{
@@ -6769,20 +6797,20 @@
 				purple_blist_add_group(g, NULL);
 			}
 
-			b = purple_find_buddy_in_group(data->account, who, g);
+			b = purple_find_buddy_in_group(account, who, g);
 		}
-		else if ((b = purple_find_buddy(data->account, who)) != NULL)
+		else if ((b = purple_find_buddy(account, who)) != NULL)
 		{
 			g = purple_buddy_get_group(b);
 		}
 
 		if (b == NULL)
 		{
-			b = purple_buddy_new(data->account, who, whoalias);
+			b = purple_buddy_new(account, who, whoalias);
 			purple_blist_add_buddy(b, NULL, g, NULL);
 		}
 
-		purple_account_add_buddy(data->account, b);
+		purple_account_add_buddy(account, b);
 
 		/* Offer to merge people with the same alias. */
 		if (whoalias != NULL && g != NULL)
@@ -6803,7 +6831,7 @@
 		 * Or something.  --Mark
 		 */
 
-		c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, data->account);
+		c = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, data->rq_data.account);
 		if (c != NULL) {
 			icon = purple_conv_im_get_icon(PURPLE_CONV_IM(c));
 			if (icon != NULL)
@@ -6811,103 +6839,52 @@
 		}
 	}
 
-	gtk_widget_destroy(data->window);
+	gtk_widget_destroy(data->rq_data.window);
 }
 
 static void
 pidgin_blist_request_add_buddy(PurpleAccount *account, const char *username,
 								 const char *group, const char *alias)
 {
-	GtkWidget *table;
-	GtkWidget *label;
-	GtkWidget *hbox;
-	GtkWidget *vbox;
-	GtkWidget *img;
-	PidginBuddyList *gtkblist;
 	PidginAddBuddyData *data = g_new0(PidginAddBuddyData, 1);
 
-	data->account =
+	make_blist_request_dialog((PidginBlistRequestData *)data,
 		(account != NULL
-		 ? account
-		 : purple_connection_get_account(purple_connections_get_all()->data));
-
-	img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION,
-					gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
-
-	gtkblist = PIDGIN_BLIST(purple_get_blist());
-
-	data->window = gtk_dialog_new_with_buttons(_("Add Buddy"),
-			gtkblist ? GTK_WINDOW(gtkblist->window) : NULL, GTK_DIALOG_NO_SEPARATOR,
+			? account : purple_connection_get_account(purple_connections_get_all()->data)),
+		_("Add Buddy"), "add_buddy",
+		_("Add a buddy.\n"),
+		G_CALLBACK(add_buddy_select_account_cb), NULL,
+		G_CALLBACK(add_buddy_cb));
+	gtk_dialog_add_buttons(GTK_DIALOG(data->rq_data.window),
 			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 			GTK_STOCK_ADD, GTK_RESPONSE_OK,
 			NULL);
 
-	if (gtkblist)
-		gtk_window_set_transient_for(GTK_WINDOW(data->window), GTK_WINDOW(gtkblist->window));
-	gtk_dialog_set_default_response(GTK_DIALOG(data->window), GTK_RESPONSE_OK);
-	gtk_container_set_border_width(GTK_CONTAINER(data->window), PIDGIN_HIG_BOX_SPACE);
-	gtk_window_set_resizable(GTK_WINDOW(data->window), FALSE);
-	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BORDER);
-	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BOX_SPACE);
-	gtk_window_set_role(GTK_WINDOW(data->window), "add_buddy");
-	gtk_window_set_type_hint(GTK_WINDOW(data->window),
-							 GDK_WINDOW_TYPE_HINT_DIALOG);
-
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), hbox);
-	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-
-	vbox = gtk_vbox_new(FALSE, 0);
-	gtk_container_add(GTK_CONTAINER(hbox), vbox);
-
-	g_signal_connect(G_OBJECT(data->window), "destroy",
+	g_signal_connect(G_OBJECT(data->rq_data.window), "destroy",
 	                 G_CALLBACK(destroy_add_buddy_dialog_cb), data);
 
-	label = gtk_label_new(_("Add a buddy.\n"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-	table = gtk_table_new(4, 2, FALSE);
-	gtk_table_set_row_spacings(GTK_TABLE(table), 5);
-	gtk_table_set_col_spacings(GTK_TABLE(table), 5);
-	gtk_container_set_border_width(GTK_CONTAINER(table), 0);
-	gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
-
-	data->account_box = pidgin_account_option_menu_new(account, FALSE,
-			G_CALLBACK(add_buddy_select_account_cb), NULL, data);
-
-	gtk_table_attach_defaults(GTK_TABLE(table), data->account_box, 0, 2, 0, 1);
-
-	label = gtk_label_new_with_mnemonic(_("Buddy's _username:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
-
 	data->entry = gtk_entry_new();
-	gtk_table_attach_defaults(GTK_TABLE(table), data->entry, 1, 2, 1, 2);
+
+	pidgin_add_widget_to_vbox(data->rq_data.vbox, _("Buddy's _username:"),
+		data->rq_data.sg, data->entry, TRUE, NULL);
 	gtk_widget_grab_focus(data->entry);
 
 	if (username != NULL)
 		gtk_entry_set_text(GTK_ENTRY(data->entry), username);
 	else
-		gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window),
+		gtk_dialog_set_response_sensitive(GTK_DIALOG(data->rq_data.window),
 		                                  GTK_RESPONSE_OK, FALSE);
 
 	gtk_entry_set_activates_default (GTK_ENTRY(data->entry), TRUE);
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->entry);
-	pidgin_set_accessible_label (data->entry, label);
 
 	g_signal_connect(G_OBJECT(data->entry), "changed",
 	                 G_CALLBACK(pidgin_set_sensitive_if_input),
-	                 data->window);
-
-	label = gtk_label_new_with_mnemonic(_("(Optional) A_lias:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
+	                 data->rq_data.window);
 
 	data->entry_for_alias = gtk_entry_new();
-	gtk_table_attach_defaults(GTK_TABLE(table),
-	                          data->entry_for_alias, 1, 2, 2, 3);
+	pidgin_add_widget_to_vbox(data->rq_data.vbox, _("(Optional) A_lias:"),
+	                          data->rq_data.sg, data->entry_for_alias, TRUE,
+	                          NULL);
 
 	if (alias != NULL)
 		gtk_entry_set_text(GTK_ENTRY(data->entry_for_alias), alias);
@@ -6915,23 +6892,11 @@
 	if (username != NULL)
 		gtk_widget_grab_focus(GTK_WIDGET(data->entry_for_alias));
 
-	gtk_entry_set_activates_default (GTK_ENTRY(data->entry_for_alias), TRUE);
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label), data->entry_for_alias);
-	pidgin_set_accessible_label (data->entry_for_alias, label);
-
-	label = gtk_label_new_with_mnemonic(_("Add buddy to _group:"));
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
-	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
-
 	data->combo = pidgin_text_combo_box_entry_new(group, groups_tree());
-	gtk_table_attach_defaults(GTK_TABLE(table), data->combo, 1, 2, 3, 4);
-	gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_BIN(data->combo)->child);
-	pidgin_set_accessible_label (data->combo, label);
-
-	g_signal_connect(G_OBJECT(data->window), "response",
-					 G_CALLBACK(add_buddy_cb), data);
-
-	gtk_widget_show_all(data->window);
+	pidgin_add_widget_to_vbox(data->rq_data.vbox, _("Add buddy to _group:"),
+	                          data->rq_data.sg, data->combo, TRUE, NULL);
+
+	gtk_widget_show_all(data->rq_data.window);
 }
 
 static void
@@ -6947,7 +6912,7 @@
 	components = g_hash_table_new_full(g_str_hash, g_str_equal,
 									   g_free, g_free);
 
-	for (tmp = data->entries; tmp; tmp = tmp->next)
+	for (tmp = data->chat_data.entries; tmp; tmp = tmp->next)
 	{
 		if (g_object_get_data(tmp->data, "is_spin"))
 		{
@@ -6966,7 +6931,7 @@
 		}
 	}
 
-	chat = purple_chat_new(data->account,
+	chat = purple_chat_new(data->chat_data.rq_data.account,
 							   gtk_entry_get_text(GTK_ENTRY(data->alias_entry)),
 							   components);
 
@@ -6990,9 +6955,9 @@
 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->persistent)))
 		purple_blist_node_set_bool((PurpleBlistNode*)chat, "gtk-persistent", TRUE);
 
-	gtk_widget_destroy(data->window);
-	g_free(data->default_chat_name);
-	g_list_free(data->entries);
+	gtk_widget_destroy(data->chat_data.rq_data.window);
+	g_free(data->chat_data.default_chat_name);
+	g_list_free(data->chat_data.entries);
 	g_free(data);
 }
 
@@ -7005,166 +6970,25 @@
 	}
 	else if (resp == 1)
 	{
-		pidgin_roomlist_dialog_show_with_account(data->account);
+		pidgin_roomlist_dialog_show_with_account(data->chat_data.rq_data.account);
 	}
 	else
 	{
-		gtk_widget_destroy(data->window);
-		g_free(data->default_chat_name);
-		g_list_free(data->entries);
+		gtk_widget_destroy(data->chat_data.rq_data.window);
+		g_free(data->chat_data.default_chat_name);
+		g_list_free(data->chat_data.entries);
 		g_free(data);
 	}
 }
 
-/*
- * Check the values of all the text entry boxes.  If any required input
- * strings are empty then don't allow the user to click on "OK."
- */
-static void
-addchat_set_sensitive_if_input_cb(GtkWidget *entry, gpointer user_data)
-{
-	PurplePluginProtocolInfo *prpl_info;
-	PurpleConnection *gc;
-	PidginAddChatData *data;
-	GList *tmp;
-	const char *text;
-	gboolean required;
-	gboolean sensitive = TRUE;
-
-	data = user_data;
-
-	for (tmp = data->entries; tmp != NULL; tmp = tmp->next)
-	{
-		if (!g_object_get_data(tmp->data, "is_spin"))
-		{
-			required = GPOINTER_TO_INT(g_object_get_data(tmp->data, "required"));
-			text = gtk_entry_get_text(tmp->data);
-			if (required && (*text == '\0'))
-				sensitive = FALSE;
-		}
-	}
-
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), GTK_RESPONSE_OK, sensitive);
-
-	gc = purple_account_get_connection(data->account);
-	prpl_info = (gc != NULL) ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
-	sensitive = (prpl_info != NULL && prpl_info->roomlist_get_list != NULL);
-
-	gtk_dialog_set_response_sensitive(GTK_DIALOG(data->window), 1, sensitive);
-}
-
-static void
-rebuild_addchat_entries(PidginAddChatData *data)
-{
-	PurpleConnection *gc;
-	GList *list = NULL, *tmp;
-	GHashTable *defaults = NULL;
-	struct proto_chat_entry *pce;
-	gboolean focus = TRUE;
-
-	g_return_if_fail(data->account != NULL);
-
-	gc = purple_account_get_connection(data->account);
-
-	gtk_container_foreach(GTK_CONTAINER(data->entries_box), (GtkCallback)gtk_widget_destroy, NULL);
-
-	g_list_free(data->entries);
-
-	data->entries = NULL;
-
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
-		list = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info(gc);
-
-	if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL)
-		defaults = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, data->default_chat_name);
-
-	for (tmp = list; tmp; tmp = tmp->next)
-	{
-		GtkWidget *input;
-
-		pce = tmp->data;
-
-		if (pce->is_int)
-		{
-			GtkObject *adjust;
-			adjust = gtk_adjustment_new(pce->min, pce->min, pce->max,
-										1, 10, 10);
-			input = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
-			gtk_widget_set_size_request(input, 50, -1);
-			pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, FALSE, NULL);
-		}
-		else
-		{
-			char *value;
-			input = gtk_entry_new();
-			gtk_entry_set_activates_default(GTK_ENTRY(input), TRUE);
-			value = g_hash_table_lookup(defaults, pce->identifier);
-			if (value != NULL)
-				gtk_entry_set_text(GTK_ENTRY(input), value);
-			if (pce->secret)
-			{
-				gtk_entry_set_visibility(GTK_ENTRY(input), FALSE);
-#if !GTK_CHECK_VERSION(2,16,0)
-				if (gtk_entry_get_invisible_char(GTK_ENTRY(input)) == '*')
-					gtk_entry_set_invisible_char(GTK_ENTRY(input), PIDGIN_INVISIBLE_CHAR);
-#endif /* Less than GTK+ 2.16 */
-			}
-			pidgin_add_widget_to_vbox(GTK_BOX(data->entries_box), pce->label, data->sg, input, TRUE, NULL);
-			g_signal_connect(G_OBJECT(input), "changed",
-							 G_CALLBACK(addchat_set_sensitive_if_input_cb), data);
-		}
-
-		/* Do the following for any type of input widget */
-		if (focus)
-		{
-			gtk_widget_grab_focus(input);
-			focus = FALSE;
-		}
-		g_object_set_data(G_OBJECT(input), "identifier", (gpointer)pce->identifier);
-		g_object_set_data(G_OBJECT(input), "is_spin", GINT_TO_POINTER(pce->is_int));
-		g_object_set_data(G_OBJECT(input), "required", GINT_TO_POINTER(pce->required));
-		data->entries = g_list_append(data->entries, input);
-
-		g_free(pce);
-	}
-
-	g_list_free(list);
-	g_hash_table_destroy(defaults);
-
-	/* Set whether the "OK" button should be clickable initially */
-	addchat_set_sensitive_if_input_cb(NULL, data);
-
-	gtk_widget_show_all(data->entries_box);
-}
-
-static void
-addchat_select_account_cb(GObject *w, PurpleAccount *account,
-						   PidginAddChatData *data)
-{
-	if (strcmp(purple_account_get_protocol_id(data->account),
-		purple_account_get_protocol_id(account)) == 0)
-	{
-		data->account = account;
-	}
-	else
-	{
-		data->account = account;
-		rebuild_addchat_entries(data);
-	}
-}
-
 static void
 pidgin_blist_request_add_chat(PurpleAccount *account, PurpleGroup *group,
 								const char *alias, const char *name)
 {
 	PidginAddChatData *data;
-	PidginBuddyList *gtkblist;
 	GList *l;
 	PurpleConnection *gc;
-	GtkWidget *label;
-	GtkWidget *hbox;
-	GtkWidget *vbox;
-	GtkWidget *img;
+	GtkBox *vbox;
 
 	if (account != NULL) {
 		gc = purple_account_get_connection(account);
@@ -7193,82 +7017,44 @@
 	}
 
 	data = g_new0(PidginAddChatData, 1);
-	data->account = account;
-	data->default_chat_name = g_strdup(name);
-
-	img = gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION,
-					gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE));
-
-	gtkblist = PIDGIN_BLIST(purple_get_blist());
-
-	data->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
-	data->window = gtk_dialog_new_with_buttons(_("Add Chat"),
-		gtkblist ? GTK_WINDOW(gtkblist->window) : NULL, GTK_DIALOG_NO_SEPARATOR,
-		_("Room _List"), 1,
+	vbox = GTK_BOX(make_blist_request_dialog((PidginBlistRequestData *)data, account,
+			_("Add Chat"), "add_chat",
+			_("Please enter an alias, and the appropriate information "
+			  "about the chat you would like to add to your buddy list.\n"),
+			G_CALLBACK(chat_select_account_cb), chat_account_filter_func,
+			G_CALLBACK(add_chat_resp_cb)));
+	gtk_dialog_add_buttons(GTK_DIALOG(data->chat_data.rq_data.window),
+		_("Room List"), 1,
 		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 		GTK_STOCK_ADD, GTK_RESPONSE_OK,
 		NULL);
 
-	if (gtkblist)
-		gtk_window_set_transient_for(GTK_WINDOW(data->window), GTK_WINDOW(gtkblist->window));
-	gtk_dialog_set_default_response(GTK_DIALOG(data->window), GTK_RESPONSE_OK);
-	gtk_container_set_border_width(GTK_CONTAINER(data->window), PIDGIN_HIG_BOX_SPACE);
-	gtk_window_set_resizable(GTK_WINDOW(data->window), FALSE);
-	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BORDER);
-	gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), PIDGIN_HIG_BOX_SPACE);
-	gtk_window_set_role(GTK_WINDOW(data->window), "add_chat");
-	gtk_window_set_type_hint(GTK_WINDOW(data->window),
-							 GDK_WINDOW_TYPE_HINT_DIALOG);
-
-	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
-	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(data->window)->vbox), hbox);
-	gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
-	gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
-
-	vbox = gtk_vbox_new(FALSE, 5);
-	gtk_container_add(GTK_CONTAINER(hbox), vbox);
-
-	label = gtk_label_new(
-		_("Please enter an alias, and the appropriate information "
-		  "about the chat you would like to add to your buddy list.\n"));
-	gtk_widget_set_size_request(label, 400, -1);
-	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
-
-	data->account_menu = pidgin_account_option_menu_new(account, FALSE,
-			G_CALLBACK(addchat_select_account_cb),
-			chat_account_filter_func, data);
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Account:"), data->sg, data->account_menu, TRUE, NULL);
-
-	data->entries_box = gtk_vbox_new(FALSE, 5);
-	gtk_container_set_border_width(GTK_CONTAINER(data->entries_box), 0);
-	gtk_box_pack_start(GTK_BOX(vbox), data->entries_box, TRUE, TRUE, 0);
-
-	rebuild_addchat_entries(data);
+	data->chat_data.default_chat_name = g_strdup(name);
+
+	rebuild_chat_entries((PidginChatData *)data, name);
 
 	data->alias_entry = gtk_entry_new();
 	if (alias != NULL)
 		gtk_entry_set_text(GTK_ENTRY(data->alias_entry), alias);
 	gtk_entry_set_activates_default(GTK_ENTRY(data->alias_entry), TRUE);
 
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("A_lias:"), data->sg, data->alias_entry, TRUE, NULL);
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("A_lias:"),
+	                          data->chat_data.rq_data.sg, data->alias_entry,
+	                          TRUE, NULL);
 	if (name != NULL)
 		gtk_widget_grab_focus(data->alias_entry);
 
 	data->group_combo = pidgin_text_combo_box_entry_new(group ? group->name : NULL, groups_tree());
-	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Group:"), data->sg, data->group_combo, TRUE, NULL);
+	pidgin_add_widget_to_vbox(GTK_BOX(vbox), _("_Group:"),
+	                          data->chat_data.rq_data.sg, data->group_combo,
+	                          TRUE, NULL);
 
 	data->autojoin = gtk_check_button_new_with_mnemonic(_("Auto_join when account becomes online."));
 	data->persistent = gtk_check_button_new_with_mnemonic(_("_Remain in chat after window is closed."));
 	gtk_box_pack_start(GTK_BOX(vbox), data->autojoin, FALSE, FALSE, 0);
 	gtk_box_pack_start(GTK_BOX(vbox), data->persistent, FALSE, FALSE, 0);
 
-	g_signal_connect(G_OBJECT(data->window), "response",
-					 G_CALLBACK(add_chat_resp_cb), data);
-
-	gtk_widget_show_all(data->window);
+	gtk_widget_show_all(data->chat_data.rq_data.window);
 }
 
 static void
@@ -8195,4 +7981,3 @@
 	if (activeitem)
 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(activeitem), TRUE);
 }
-