# HG changeset patch
# Node ID 61337b8f8147
# Parent  f66f7b1c7824
diff --git a/pidgin/gtkroomlist.c b/pidgin/gtkroomlist.c
--- a/pidgin/gtkroomlist.c
+++ b/pidgin/gtkroomlist.c
@@ -27,7 +27,6 @@
 
 #include "gtkroomlist.h"
 
-#include "gtkutils.h"
 #include "pidginaccountchooser.h"
 
 #define PIDGIN_TYPE_ROOMLIST_DIALOG (pidgin_roomlist_dialog_get_type())
@@ -36,12 +35,20 @@
 
 #define PIDGIN_ROOMLIST_UI_DATA "pidgin-ui"
 
+enum {
+	RESPONSE_STOP = 0,
+	RESPONSE_LIST,
+	RESPONSE_ADD,
+	RESPONSE_JOIN,
+};
+
 struct _PidginRoomlistDialog {
 	GtkDialog parent;
 
 	GtkWidget *account_widget;
 	GtkWidget *progress;
 	GtkWidget *tree;
+	GtkTreeSelection *tree_selection;
 
 	GtkWidget *stop_button;
 	GtkWidget *list_button;
@@ -49,6 +56,8 @@
 	GtkWidget *join_button;
 	GtkWidget *close_button;
 
+	GtkWidget *popover_menu;
+
 	PurpleAccount *account;
 	PurpleRoomlist *roomlist;
 
@@ -70,30 +79,27 @@
 	NUM_OF_COLUMNS,
 };
 
-static gboolean
-_search_func(GtkTreeModel *model, gint column, const gchar *key,
-             GtkTreeIter *iter, gpointer search_data)
-{
-	gboolean result;
-	gchar *name, *fold, *fkey;
 
-	gtk_tree_model_get(model, iter, column, &name, -1);
-	fold = g_utf8_casefold(name, -1);
-	fkey = g_utf8_casefold(key, -1);
-
-	result = (g_strstr_len(fold, strlen(fold), fkey) == NULL);
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static PurpleRoomlistRoom *
+pidgin_roomlist_get_selected(PidginRoomlistDialog *dialog)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = NULL;
+	PurpleRoomlistRoom *room = NULL;
 
-	g_free(fold);
-	g_free(fkey);
-	g_free(name);
+	if(gtk_tree_selection_get_selected(dialog->tree_selection, &model, &iter)) {
+		gtk_tree_model_get(model, &iter, ROOM_COLUMN, &room, -1);
+	}
 
-	return result;
+	return room;
 }
 
-static gint delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
+static void
+pidgin_roomlist_close(PidginRoomlistDialog *dialog)
 {
-	PidginRoomlistDialog *dialog = PIDGIN_ROOMLIST_DIALOG(w);
-
 	if (dialog->roomlist && purple_roomlist_get_in_progress(dialog->roomlist))
 		purple_roomlist_cancel_get_list(dialog->roomlist);
 
@@ -116,30 +122,10 @@
 	}
 
 	dialog->progress = NULL;
-
-	return FALSE;
 }
 
 static void
-dialog_select_account_cb(GtkWidget *w, PidginRoomlistDialog *dialog) {
-	PidginAccountChooser *chooser = PIDGIN_ACCOUNT_CHOOSER(w);
-	PurpleAccount *account = pidgin_account_chooser_get_selected(chooser);
-	gboolean change = (account != dialog->account);
-	dialog->account = account;
-
-	if (change && dialog->roomlist) {
-		PidginRoomlist *rl = NULL;
-
-		rl = g_object_get_data(G_OBJECT(dialog->roomlist),
-		                       PIDGIN_ROOMLIST_UI_DATA);
-
-		g_clear_object(&rl->model);
-		g_object_unref(dialog->roomlist);
-		dialog->roomlist = NULL;
-	}
-}
-
-static void list_button_cb(GtkButton *button, PidginRoomlistDialog *dialog)
+pidgin_roomlist_start_listing(PidginRoomlistDialog *dialog)
 {
 	PurpleConnection *gc;
 	PidginRoomlist *rl;
@@ -183,7 +169,8 @@
 	gtk_widget_set_sensitive(dialog->join_button, FALSE);
 }
 
-static void stop_button_cb(GtkButton *button, PidginRoomlistDialog *dialog)
+static void
+pidgin_roomlist_stop_listing(PidginRoomlistDialog *dialog)
 {
 	purple_roomlist_cancel_get_list(dialog->roomlist);
 
@@ -195,53 +182,21 @@
 	gtk_widget_set_sensitive(dialog->join_button, FALSE);
 }
 
-struct _menu_cb_info {
-	PurpleRoomlist *list;
-	PurpleRoomlistRoom *room;
-};
-
 static void
-selection_changed_cb(GtkTreeSelection *selection,
-                     PidginRoomlistDialog *dialog)
+pidgin_roomlist_add_to_blist(PidginRoomlistDialog *dialog)
 {
-	GtkTreeIter iter;
-	PurpleRoomlistRoom *room;
-	static struct _menu_cb_info *info;
-	PidginRoomlist *grl = NULL;
-
-	grl = g_object_get_data(G_OBJECT(dialog->roomlist),
-	                        PIDGIN_ROOMLIST_UI_DATA);
-
-	if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
-		gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter,
-		                   ROOM_COLUMN, &room,
-		                   -1);
+	char *name = NULL;
+	PurpleAccount *account = NULL;
+	PurpleConnection *gc = NULL;
+	PurpleProtocol *protocol = NULL;
+	PurpleRoomlistRoom *room = NULL;
 
-		info = g_new0(struct _menu_cb_info, 1);
-		info->list = dialog->roomlist;
-		info->room = room;
-
-		g_object_set_data_full(G_OBJECT(dialog->join_button), "room-info",
-							   info, g_free);
-		g_object_set_data(G_OBJECT(dialog->add_button), "room-info", info);
-
-		gtk_widget_set_sensitive(dialog->add_button, TRUE);
-		gtk_widget_set_sensitive(dialog->join_button, TRUE);
+	account = purple_roomlist_get_account(dialog->roomlist);
+	gc = purple_account_get_connection(account);
 
-		g_object_unref(room);
-	} else {
-		gtk_widget_set_sensitive(dialog->add_button, FALSE);
-		gtk_widget_set_sensitive(dialog->join_button, FALSE);
-	}
-}
+	room = pidgin_roomlist_get_selected(dialog);
 
-static void
-do_add_room_cb(G_GNUC_UNUSED GtkWidget *w, struct _menu_cb_info *info)
-{
-	char *name;
-	PurpleAccount *account = purple_roomlist_get_account(info->list);
-	PurpleConnection *gc = purple_account_get_connection(account);
-	PurpleProtocol *protocol = NULL;
+	g_return_if_fail(room != NULL);
 
 	if(gc != NULL) {
 		protocol = purple_connection_get_protocol(gc);
@@ -249,9 +204,9 @@
 
 	if(protocol != NULL && PURPLE_PROTOCOL_IMPLEMENTS(protocol, ROOMLIST, room_serialize)) {
 		name = purple_protocol_roomlist_room_serialize(PURPLE_PROTOCOL_ROOMLIST(protocol),
-		                                               info->room);
+		                                               room);
 	} else {
-		name = g_strdup(purple_roomlist_room_get_name(info->room));
+		name = g_strdup(purple_roomlist_room_get_name(room));
 	}
 
 	purple_blist_request_add_chat(account, NULL, NULL, name);
@@ -259,26 +214,131 @@
 	g_free(name);
 }
 
+static gboolean
+_search_func(GtkTreeModel *model, gint column, const gchar *key,
+             GtkTreeIter *iter, gpointer search_data)
+{
+	gboolean result;
+	gchar *name, *fold, *fkey;
+
+	gtk_tree_model_get(model, iter, column, &name, -1);
+	fold = g_utf8_casefold(name, -1);
+	fkey = g_utf8_casefold(key, -1);
+
+	result = (g_strstr_len(fold, strlen(fold), fkey) == NULL);
+
+	g_free(fold);
+	g_free(fkey);
+	g_free(name);
+
+	return result;
+}
+
 static void
-add_room_to_blist_cb(GtkButton *button, G_GNUC_UNUSED gpointer data)
+pidgin_roomlist_join(PidginRoomlistDialog *dialog)
+{
+	PurpleRoomlistRoom *room = NULL;
+
+	room = pidgin_roomlist_get_selected(dialog);
+
+	if(room != NULL) {
+		purple_roomlist_join_room(dialog->roomlist, room);
+	}
+}
+
+/******************************************************************************
+ * Actions
+ *****************************************************************************/
+static void
+pidgin_roomlist_add_to_blist_cb(G_GNUC_UNUSED GSimpleAction *action,
+				G_GNUC_UNUSED GVariant *parameter,
+                                gpointer data)
+{
+	pidgin_roomlist_add_to_blist(data);
+}
+
+
+static void
+pidgin_roomlist_join_cb(GSimpleAction *action, GVariant *parameter,
+                        gpointer data)
 {
-	struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "room-info");
+	pidgin_roomlist_join(data);
+}
+
+static GActionEntry actions[] = {
+	{
+		.name = "add",
+		.activate = pidgin_roomlist_add_to_blist_cb,
+	}, {
+		.name = "join",
+		.activate = pidgin_roomlist_join_cb,
+	},
+};
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static void
+pidgin_roomlist_response_cb(GtkDialog *gtk_dialog, gint response_id,
+                            gpointer data)
+{
+	PidginRoomlistDialog *dialog = PIDGIN_ROOMLIST_DIALOG(gtk_dialog);
 
-	if(info != NULL) {
-		do_add_room_cb(NULL, info);
+	switch(response_id) {
+	case RESPONSE_STOP:
+		pidgin_roomlist_stop_listing(dialog);
+		break;
+	case RESPONSE_LIST:
+		pidgin_roomlist_start_listing(dialog);
+		break;
+	case RESPONSE_ADD:
+		pidgin_roomlist_add_to_blist(dialog);
+		break;
+	case RESPONSE_JOIN:
+		pidgin_roomlist_join(dialog);
+		break;
+	}
+}
+
+static gboolean
+close_request_cb(GtkWidget *w, G_GNUC_UNUSED gpointer d)
+{
+	pidgin_roomlist_close(PIDGIN_ROOMLIST_DIALOG(w));
+
+	gtk_window_destroy(GTK_WINDOW(w));
+
+	return TRUE;
+}
+
+static void
+dialog_select_account_cb(G_GNUC_UNUSED GtkWidget *w, PidginRoomlistDialog *dialog) {
+	PidginAccountChooser *chooser = PIDGIN_ACCOUNT_CHOOSER(w);
+	PurpleAccount *account = pidgin_account_chooser_get_selected(chooser);
+	gboolean change = (account != dialog->account);
+	dialog->account = account;
+
+	if (change && dialog->roomlist) {
+		PidginRoomlist *rl = NULL;
+
+		rl = g_object_get_data(G_OBJECT(dialog->roomlist),
+		                       PIDGIN_ROOMLIST_UI_DATA);
+
+		g_clear_object(&rl->model);
+		g_object_unref(dialog->roomlist);
+		dialog->roomlist = NULL;
 	}
 }
 
 static void
-do_join_cb(G_GNUC_UNUSED GtkWidget *w, struct _menu_cb_info *info) {
-	purple_roomlist_join_room(info->list, info->room);
-}
+selection_changed_cb(GtkTreeSelection *selection,
+                     PidginRoomlistDialog *dialog)
+{
+	gboolean found = FALSE;
 
-static void
-join_button_cb(GtkButton *button, G_GNUC_UNUSED gpointer data) {
-	struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "room-info");
+	found = gtk_tree_selection_get_selected(selection, NULL, NULL);
 
-	purple_roomlist_join_room(info->list, info->room);
+	gtk_widget_set_sensitive(dialog->add_button, found);
+	gtk_widget_set_sensitive(dialog->join_button, found);
 }
 
 static void
@@ -289,66 +349,36 @@
 	PidginRoomlist *grl = NULL;
 	GtkTreeIter iter;
 	PurpleRoomlistRoom *room;
-	struct _menu_cb_info info;
 
 	grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA);
 
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path);
 	gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &room, -1);
 
-	info.list = dialog->roomlist;
-	info.room = room;
-
-	do_join_cb(NULL, &info);
+	if(PURPLE_IS_ROOMLIST_ROOM(room)) {
+		purple_roomlist_join_room(dialog->roomlist, room);
+	}
 
 	g_clear_object(&room);
 }
 
 static gboolean
-room_click_cb(GtkWidget *tv, GdkEventButton *event, gpointer data) {
+room_click_cb(GtkWidget *tv, GdkEvent *event, gpointer data) {
 	PidginRoomlistDialog *dialog = data;
-	GtkTreePath *path;
-	PidginRoomlist *grl = NULL;
-	PurpleRoomlistRoom *room;
-	GtkTreeIter iter;
-	GtkWidget *menu;
-	GtkWidget *menuitem;
-	static struct _menu_cb_info info; /* XXX? */
+	gdouble x, y;
 
 	if (!gdk_event_triggers_context_menu((GdkEvent *)event))
 		return FALSE;
 
-	grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA);
+	gdk_event_get_position(event, &x, &y);
 
-	/* Here we figure out which room was clicked */
-	if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL))
+	if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), x, y, NULL, NULL, NULL, NULL))
 		return FALSE;
-	gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path);
-	gtk_tree_path_free(path);
-	gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &room, -1);
-
-	info.list = dialog->roomlist;
-	info.room = room;
 
-	/* The current implementation isn't expecting a ref to unref the one we got
-	 * when we pulled the room out of the model.
-	 */
-	g_clear_object(&room);
-
-	menu = gtk_menu_new();
+	gtk_popover_set_pointing_to(GTK_POPOVER(dialog->popover_menu),
+	                            &(const GdkRectangle){(int)x, (int)y, 0, 0});
 
-	menuitem = gtk_menu_item_new_with_mnemonic(_("_Join"));
-	g_signal_connect(G_OBJECT(menuitem), "activate",
-	                 G_CALLBACK(do_join_cb), &info);
-	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	menuitem = gtk_menu_item_new_with_mnemonic(_("_Add"));
-	g_signal_connect(G_OBJECT(menuitem), "activate",
-	                 G_CALLBACK(do_add_room_cb), &info);
-	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
-
-	gtk_widget_show_all(menu);
-	gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event);
+	gtk_popover_popup(GTK_POPOVER(dialog->popover_menu));
 
 	return FALSE;
 }
@@ -370,8 +400,7 @@
 	grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA);
 
 	if (keyboard_mode) {
-		GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
-		if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
+		if (!gtk_tree_selection_get_selected(dialog->tree_selection, NULL, &iter)) {
 			return FALSE;
 		}
 		path = gtk_tree_model_get_path(GTK_TREE_MODEL(grl->model), &iter);
@@ -449,6 +478,8 @@
 	gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
 	                                     tree);
 	gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
+	                                     tree_selection);
+	gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
 	                                     add_button);
 	gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
 	                                     close_button);
@@ -460,10 +491,10 @@
 	                                     progress);
 	gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
 	                                     stop_button);
+	gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
+	                                     popover_menu);
 
-	gtk_widget_class_bind_template_callback(widget_class,
-	                                        add_room_to_blist_cb);
-	gtk_widget_class_bind_template_callback(widget_class, delete_win_cb);
+	gtk_widget_class_bind_template_callback(widget_class, close_request_cb);
 	gtk_widget_class_bind_template_callback(widget_class, row_activated_cb);
 	gtk_widget_class_bind_template_callback(widget_class, room_click_cb);
 	gtk_widget_class_bind_template_callback(widget_class,
@@ -472,14 +503,15 @@
 	                                        selection_changed_cb);
 	gtk_widget_class_bind_template_callback(widget_class,
 	                                        pidgin_roomlist_query_tooltip);
-	gtk_widget_class_bind_template_callback(widget_class, join_button_cb);
-	gtk_widget_class_bind_template_callback(widget_class, list_button_cb);
-	gtk_widget_class_bind_template_callback(widget_class, stop_button_cb);
+	gtk_widget_class_bind_template_callback(widget_class,
+	                                        pidgin_roomlist_response_cb);
 }
 
 static void
 pidgin_roomlist_dialog_init(PidginRoomlistDialog *self)
 {
+	GSimpleActionGroup *group = NULL;
+
 	gtk_widget_init_template(GTK_WIDGET(self));
 
 	pidgin_account_chooser_set_filter_func(
@@ -488,6 +520,13 @@
 
 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(self->tree),
 	                                    _search_func, NULL, NULL);
+
+	/* Now setup our actions. */
+	group = g_simple_action_group_new();
+	g_action_map_add_action_entries(G_ACTION_MAP(group), actions,
+	                                G_N_ELEMENTS(actions), self);
+	gtk_widget_insert_action_group(GTK_WIDGET(self), "roomlist",
+	                               G_ACTION_GROUP(group));
 }
 
 static PidginRoomlistDialog *
@@ -519,10 +558,7 @@
 {
 	PidginRoomlistDialog *dialog = pidgin_roomlist_dialog_new_with_account(account);
 
-	if (!dialog)
-		return;
-
-	list_button_cb(GTK_BUTTON(dialog->list_button), dialog);
+	pidgin_roomlist_start_listing(dialog);
 }
 
 void pidgin_roomlist_dialog_show(void)
@@ -604,18 +640,12 @@
 }
 
 static void
-pidgin_roomlist_destroy(PidginRoomlist *rl)
-{
-	g_free(rl);
-}
-
-static void
 pidgin_roomlist_new(PurpleRoomlist *list)
 {
 	PidginRoomlist *rl = g_new0(PidginRoomlist, 1);
 
 	g_object_set_data_full(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA, rl,
-	                       (GDestroyNotify)pidgin_roomlist_destroy);
+	                       (GDestroyNotify)g_free);
 
 	rl->model = gtk_tree_store_new(3, G_TYPE_OBJECT, G_TYPE_STRING,
 	                               G_TYPE_STRING);
diff --git a/pidgin/resources/Roomlist/roomlist.ui b/pidgin/resources/Roomlist/roomlist.ui
--- a/pidgin/resources/Roomlist/roomlist.ui
+++ b/pidgin/resources/Roomlist/roomlist.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>
 
@@ -15,180 +14,67 @@
 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  02110-1301, USA.
+along with this library; if not, see <https://www.gnu.org/licenses/>.
+-->
 
--->
 <interface>
-  <requires lib="gtk+" version="3.22"/>
+  <requires lib="gtk" version="4.0"/>
   <requires lib="pidgin" version="3.0"/>
-  <!-- interface-license-type gplv2 -->
-  <!-- interface-name Pidgin -->
-  <!-- interface-description Internet Messenger -->
-  <!-- interface-copyright Pidgin Developers <devel@pidgin.im> -->
   <object class="PidginAccountStore" id="accounts"/>
   <template class="PidginRoomlistDialog" parent="GtkDialog">
-    <property name="can-focus">False</property>
-    <property name="title" translatable="yes">Room List</property>
+    <property name="title" translatable="1">Room List</property>
     <property name="role">room list</property>
     <property name="type-hint">dialog</property>
-    <signal name="delete-event" handler="delete_win_cb" swapped="no"/>
-    <child internal-child="vbox">
+    <signal name="close-request" handler="close_request_cb" swapped="no"/>
+    <signal name="response" handler="pidgin_roomlist_response_cb" swapped="no"/>
+    <child internal-child="content_area">
       <object class="GtkBox">
-        <property name="can-focus">False</property>
         <property name="orientation">vertical</property>
         <property name="spacing">2</property>
-        <child internal-child="action_area">
-          <object class="GtkButtonBox">
-            <property name="can-focus">False</property>
-            <property name="layout-style">end</property>
-            <child>
-              <object class="GtkButton" id="stop_button">
-                <property name="label">_Stop</property>
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="can-focus">True</property>
-                <property name="receives-default">True</property>
-                <property name="use-underline">True</property>
-                <signal name="clicked" handler="stop_button_cb" object="PidginRoomlistDialog" swapped="no"/>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="list_button">
-                <property name="label" translatable="yes">_Get List</property>
-                <property name="visible">True</property>
-                <property name="can-focus">True</property>
-                <property name="receives-default">True</property>
-                <property name="use-underline">True</property>
-                <signal name="clicked" handler="list_button_cb" object="PidginRoomlistDialog" swapped="no"/>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="add_button">
-                <property name="label" translatable="yes">_Add Chat</property>
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="can-focus">True</property>
-                <property name="receives-default">True</property>
-                <property name="use-underline">True</property>
-                <signal name="clicked" handler="add_room_to_blist_cb" object="PidginRoomlistDialog" swapped="no"/>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="join_button">
-                <property name="label" translatable="yes">_Join</property>
-                <property name="visible">True</property>
-                <property name="sensitive">False</property>
-                <property name="can-focus">True</property>
-                <property name="receives-default">True</property>
-                <property name="use-underline">True</property>
-                <signal name="clicked" handler="join_button_cb" object="PidginRoomlistDialog" swapped="no"/>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">3</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="close_button">
-                <property name="label">_Close</property>
-                <property name="visible">True</property>
-                <property name="can-focus">True</property>
-                <property name="receives-default">True</property>
-                <property name="use-underline">True</property>
-                <signal name="clicked" handler="gtk_widget_destroy" object="PidginRoomlistDialog" swapped="yes"/>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">4</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
         <child>
           <object class="GtkBox">
-            <property name="visible">True</property>
-            <property name="can-focus">False</property>
             <property name="orientation">vertical</property>
             <property name="spacing">12</property>
             <child>
               <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can-focus">False</property>
                 <property name="spacing">5</property>
                 <child>
                   <object class="GtkLabel" id="label1">
-                    <property name="visible">True</property>
-                    <property name="can-focus">False</property>
-                    <property name="label" translatable="yes">_Account:</property>
-                    <property name="use-underline">True</property>
+                    <property name="halign">start</property>
+                    <property name="label" translatable="1">_Account:</property>
+                    <property name="use-underline">1</property>
                     <property name="mnemonic-widget">account_widget</property>
                     <accessibility>
                       <relation type="label-for" target="account_widget"/>
                     </accessibility>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
                 </child>
                 <child>
                   <object class="PidginAccountChooser" id="account_widget">
+                    <property name="hexpand">1</property>
                     <property name="visible">True</property>
                     <property name="can-focus">False</property>
                     <property name="model">accounts</property>
                     <property name="active">0</property>
+		    <property name="halign">fill</property>
                     <signal name="changed" handler="dialog_select_account_cb" object="PidginRoomlistDialog" swapped="no"/>
                     <accessibility>
                       <relation type="labelled-by" target="label1"/>
                     </accessibility>
                   </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
             </child>
             <child>
               <object class="GtkScrolledWindow" id="sw">
-                <property name="visible">True</property>
-                <property name="can-focus">True</property>
+                <property name="vexpand">1</property>
+                <property name="focusable">1</property>
                 <property name="shadow-type">in</property>
                 <property name="min-content-height">250</property>
-                <child>
+		<property name="valign">fill</property>
+                <property name="child">
                   <object class="GtkTreeView" id="tree">
-                    <property name="visible">True</property>
-                    <property name="can-focus">True</property>
+                    <property name="focusable">1</property>
                     <property name="search-column">1</property>
                     <signal name="button-press-event" handler="room_click_cb" object="PidginRoomlistDialog" swapped="no"/>
                     <signal name="query-tooltip" handler="pidgin_roomlist_query_tooltip" object="PidginRoomlistDialog" swapped="no"/>
@@ -200,7 +86,7 @@
                     </child>
                     <child>
                       <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Name</property>
+                        <property name="title" translatable="1">Name</property>
                         <child>
                           <object class="GtkCellRendererText"/>
                           <attributes>
@@ -211,7 +97,7 @@
                     </child>
                     <child>
                       <object class="GtkTreeViewColumn">
-                        <property name="title" translatable="yes">Description</property>
+                        <property name="title" translatable="1">Description</property>
                         <child>
                           <object class="GtkCellRendererText"/>
                           <attributes>
@@ -221,33 +107,106 @@
                       </object>
                     </child>
                   </object>
-                </child>
+                </property>
               </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
             </child>
             <child>
-              <object class="GtkProgressBar" id="progress">
-                <property name="visible">True</property>
-                <property name="can-focus">False</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">2</property>
-              </packing>
+              <object class="GtkProgressBar" id="progress" />
             </child>
           </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="valign">center</property>
+        <property name="can-focus">False</property>
+        <child type="action">
+          <object class="GtkButton" id="stop_button">
+            <property name="label">_Stop</property>
+            <property name="sensitive">0</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="use-underline">1</property>
+          </object>
           <packing>
-            <property name="expand">False</property>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child type="action">
+          <object class="GtkButton" id="list_button">
+            <property name="label" translatable="1">_Get List</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="use-underline">1</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
             <property name="fill">True</property>
             <property name="position">1</property>
           </packing>
         </child>
+        <child type="action">
+          <object class="GtkButton" id="add_button">
+            <property name="label" translatable="1">_Add Chat</property>
+            <property name="sensitive">0</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="use-underline">1</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child type="action">
+          <object class="GtkButton" id="join_button">
+            <property name="label" translatable="1">_Join</property>
+            <property name="sensitive">0</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="use-underline">1</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child type="action">
+          <object class="GtkButton" id="close_button">
+            <property name="label">_Close</property>
+            <property name="focusable">1</property>
+            <property name="receives-default">1</property>
+            <property name="use-underline">1</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
       </object>
     </child>
+    <action-widgets>
+      <action-widget response="0">stop_button</action-widget>
+      <action-widget response="1">list_button</action-widget>
+      <action-widget response="2">add_button</action-widget>
+      <action-widget response="3">join_button</action-widget>
+      <action-widget response="-6">close_button</action-widget>
+    </action-widgets>
   </template>
+  <menu id="popover_menu">
+    <item>
+      <attribute name="label" translatable="yes">_Join</attribute>
+      <attribute name="action">roomlist.join</attribute>
+    </item>
+    <item>
+      <attribute name="label" translatable="yes">_Add</attribute>
+      <attribute name="action">roomlist.add</attribute>
+    </item>
+  </menu>
 </interface>
