pidgin/pidgin

Port the room list from GtkTreeView to GtkColumnView

15 months ago, Elliott Sales de Andrade
941734e74261
Parents e110f2d6dbd3
Children af20db93f2c2
Port the room list from GtkTreeView to GtkColumnView

Note, this removes the tooltip. It's not super easy to get the cell that the mouse is over, plus all it showed was the Name, which is pretty redundant.

It also removes the popup menu, for the same reason, as it just duplicates the response buttons, and on a `ColumnView`, right-clicking does not select the hovered row anyway.

Testing Done:
Fetched room list for `conference.pidgin.im`, clicked on the rows, and saw that the buttons were enabled (though I think all responses were chats so they were always enabled once one was selected.) Typed some bit of the names and they were filtered.

Reviewed at https://reviews.imfreedom.org/r/2209/
--- a/pidgin/gtkroomlist.c Mon Jan 23 20:55:34 2023 -0600
+++ b/pidgin/gtkroomlist.c Mon Jan 23 23:27:47 2023 -0600
@@ -47,8 +47,9 @@
GtkWidget *account_widget;
GtkWidget *progress;
- GtkWidget *tree;
- GtkTreeSelection *tree_selection;
+ GtkWidget *view;
+ GtkSingleSelection *selection;
+ GtkFilterListModel *filter;
GtkWidget *stop_button;
GtkWidget *list_button;
@@ -56,8 +57,6 @@
GtkWidget *join_button;
GtkWidget *close_button;
- GtkWidget *popover;
-
PurpleAccount *account;
PurpleRoomlist *roomlist;
@@ -69,34 +68,12 @@
typedef struct {
PidginRoomlistDialog *dialog;
- GtkTreeStore *model;
+ GListStore *model;
} PidginRoomlist;
-enum {
- ROOM_COLUMN = 0,
- NAME_COLUMN,
- DESCRIPTION_COLUMN,
- NUM_OF_COLUMNS,
-};
-
-
/******************************************************************************
* Helpers
*****************************************************************************/
-static PurpleRoomlistRoom *
-pidgin_roomlist_get_selected(PidginRoomlistDialog *dialog)
-{
- GtkTreeIter iter;
- GtkTreeModel *model = NULL;
- PurpleRoomlistRoom *room = NULL;
-
- if(gtk_tree_selection_get_selected(dialog->tree_selection, &model, &iter)) {
- gtk_tree_model_get(model, &iter, ROOM_COLUMN, &room, -1);
- }
-
- return room;
-}
-
static void
pidgin_roomlist_close(PidginRoomlistDialog *dialog)
{
@@ -153,8 +130,7 @@
gtk_widget_set_sensitive(dialog->account_widget, FALSE);
- gtk_tree_view_set_model(GTK_TREE_VIEW(dialog->tree),
- GTK_TREE_MODEL(rl->model));
+ gtk_filter_list_model_set_model(dialog->filter, G_LIST_MODEL(rl->model));
/* some protocols (not bundled with libpurple) finish getting their
* room list immediately */
@@ -194,9 +170,8 @@
account = purple_roomlist_get_account(dialog->roomlist);
gc = purple_account_get_connection(account);
- room = pidgin_roomlist_get_selected(dialog);
-
- g_return_if_fail(room != NULL);
+ room = gtk_single_selection_get_selected_item(dialog->selection);
+ g_return_if_fail(PURPLE_IS_ROOMLIST_ROOM(room));
if(gc != NULL) {
protocol = purple_connection_get_protocol(gc);
@@ -214,34 +189,13 @@
g_free(name);
}
-static gboolean
-_search_func(GtkTreeModel *model, gint column, const gchar *key,
- GtkTreeIter *iter, G_GNUC_UNUSED 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
pidgin_roomlist_join(PidginRoomlistDialog *dialog)
{
PurpleRoomlistRoom *room = NULL;
- room = pidgin_roomlist_get_selected(dialog);
-
- if(room != NULL) {
+ room = gtk_single_selection_get_selected_item(dialog->selection);
+ if(PURPLE_IS_ROOMLIST_ROOM(room)) {
purple_roomlist_join_room(dialog->roomlist, room);
}
}
@@ -332,36 +286,37 @@
PIDGIN_ROOMLIST_UI_DATA);
g_clear_object(&rl->model);
- g_object_unref(dialog->roomlist);
- dialog->roomlist = NULL;
+ g_clear_object(&dialog->roomlist);
}
}
static void
-selection_changed_cb(GtkTreeSelection *selection,
- PidginRoomlistDialog *dialog)
+selection_changed_cb(GtkSelectionModel *self, G_GNUC_UNUSED guint position,
+ G_GNUC_UNUSED guint n_items, gpointer data)
{
+ PidginRoomlistDialog *dialog = data;
+ guint index = GTK_INVALID_LIST_POSITION;
gboolean found = FALSE;
- found = gtk_tree_selection_get_selected(selection, NULL, NULL);
+ /* The passed in position and n_items gives the *range* of selections that
+ * have changed, so just re-query it exactly since GtkSingleSelection has
+ * only one. */
+ index = gtk_single_selection_get_selected(GTK_SINGLE_SELECTION(self));
+ found = index != GTK_INVALID_LIST_POSITION;
gtk_widget_set_sensitive(dialog->add_button, found);
gtk_widget_set_sensitive(dialog->join_button, found);
}
static void
-row_activated_cb(G_GNUC_UNUSED GtkTreeView *tv, GtkTreePath *path,
- G_GNUC_UNUSED GtkTreeViewColumn *arg2, gpointer data)
+row_activated_cb(GtkColumnView *self, guint position, gpointer data)
{
PidginRoomlistDialog *dialog = data;
- PidginRoomlist *grl = NULL;
- GtkTreeIter iter;
- PurpleRoomlistRoom *room;
+ PurpleRoomlistRoom *room = NULL;
+ GtkSelectionModel *model = NULL;
- 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);
+ model = gtk_column_view_get_model(self);
+ room = g_list_model_get_item(G_LIST_MODEL(model), position);
if(PURPLE_IS_ROOMLIST_ROOM(room)) {
purple_roomlist_join_room(dialog->roomlist, room);
@@ -370,81 +325,6 @@
g_clear_object(&room);
}
-static void
-room_click_cb(G_GNUC_UNUSED GtkGestureClick *self, gint n_press, gdouble x,
- gdouble y, gpointer data)
-{
- PidginRoomlistDialog *dialog = data;
-
- if(n_press != 1) {
- return;
- }
-
- if(!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->tree), (gint)x,
- (gint)y, NULL, NULL, NULL, NULL))
- {
- return;
- }
-
- gtk_popover_set_pointing_to(GTK_POPOVER(dialog->popover),
- &(const GdkRectangle){(int)x, (int)y, 0, 0});
-
- gtk_popover_popup(GTK_POPOVER(dialog->popover));
-}
-
-static gboolean
-pidgin_roomlist_query_tooltip(GtkWidget *widget, int x, int y,
- gboolean keyboard_mode, GtkTooltip *tooltip,
- gpointer data)
-{
- PidginRoomlistDialog *dialog = data;
- PidginRoomlist *grl = NULL;
- GtkTreePath *path = NULL;
- GtkTreeIter iter;
- gchar *name, *tmp;
- GString *tooltip_text = NULL;
-
- grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA);
-
- if (keyboard_mode) {
- 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);
- } else {
- gint bx, by;
-
- gtk_tree_view_convert_widget_to_bin_window_coords(GTK_TREE_VIEW(widget),
- x, y, &bx, &by);
- gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bx, by, &path,
- NULL, NULL, NULL);
- if (path == NULL) {
- return FALSE;
- }
-
- if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path)) {
- gtk_tree_path_free(path);
- return FALSE;
- }
- }
-
- tooltip_text = g_string_new("");
-
- gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, NAME_COLUMN, &name, -1);
- tmp = g_markup_escape_text(name, -1);
- g_free(name);
- g_string_append_printf(
- tooltip_text, "<span size='x-large' weight='bold'>%s</span>\n", tmp);
- g_free(tmp);
-
- gtk_tooltip_set_markup(tooltip, tooltip_text->str);
- gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, path);
- g_string_free(tooltip_text, TRUE);
- gtk_tree_path_free(path);
-
- return TRUE;
-}
-
static gboolean
account_filter_func(gpointer item, G_GNUC_UNUSED gpointer data) {
PurpleProtocol *protocol = NULL;
@@ -488,9 +368,11 @@
gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
account_widget);
gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
- tree);
+ view);
gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
- tree_selection);
+ selection);
+ gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
+ filter);
gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
add_button);
gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
@@ -503,19 +385,14 @@
progress);
gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
stop_button);
- gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog,
- popover);
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,
dialog_select_account_cb);
gtk_widget_class_bind_template_callback(widget_class,
selection_changed_cb);
gtk_widget_class_bind_template_callback(widget_class,
- pidgin_roomlist_query_tooltip);
- gtk_widget_class_bind_template_callback(widget_class,
pidgin_roomlist_response_cb);
}
@@ -533,9 +410,6 @@
GTK_FILTER(filter));
g_object_unref(filter);
- 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,
@@ -602,8 +476,6 @@
static void
pidgin_roomlist_add_room(PurpleRoomlist *list, PurpleRoomlistRoom *room) {
PidginRoomlist *rl = NULL;
- GtkTreePath *path;
- GtkTreeIter iter;
rl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA);
@@ -616,18 +488,7 @@
rl->dialog->pg_needs_pulse = TRUE;
}
- gtk_tree_store_append(rl->model, &iter, NULL);
-
- path = gtk_tree_model_get_path(GTK_TREE_MODEL(rl->model), &iter);
-
- gtk_tree_path_free(path);
-
- gtk_tree_store_set(
- rl->model, &iter,
- ROOM_COLUMN, room,
- NAME_COLUMN, purple_roomlist_room_get_name(room),
- DESCRIPTION_COLUMN, purple_roomlist_room_get_description(room),
- -1);
+ g_list_store_append(rl->model, room);
}
static void
@@ -662,8 +523,7 @@
g_object_set_data_full(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA, rl,
(GDestroyNotify)g_free);
- rl->model = gtk_tree_store_new(3, G_TYPE_OBJECT, G_TYPE_STRING,
- G_TYPE_STRING);
+ rl->model = g_list_store_new(PURPLE_TYPE_ROOMLIST_ROOM);
g_signal_connect(list, "notify::in-progress",
G_CALLBACK(pidgin_roomlist_in_progress), rl);
--- a/pidgin/resources/Roomlist/roomlist.ui Mon Jan 23 20:55:34 2023 -0600
+++ b/pidgin/resources/Roomlist/roomlist.ui Mon Jan 23 23:27:47 2023 -0600
@@ -60,49 +60,94 @@
<property name="focusable">1</property>
<property name="min-content-height">250</property>
<property name="child">
- <object class="GtkTreeView" id="tree">
+ <object class="GtkColumnView" id="view">
<property name="focusable">1</property>
- <property name="search-column">1</property>
- <signal name="query-tooltip" handler="pidgin_roomlist_query_tooltip" object="PidginRoomlistDialog" swapped="no"/>
- <signal name="row-activated" handler="row_activated_cb" object="PidginRoomlistDialog" swapped="no"/>
- <child>
- <object class="GtkGestureClick">
- <property name="button">3</property>
- <signal name="pressed" handler="room_click_cb" object="PidginRoomlistDialog" swapped="no"/>
+ <property name="model">
+ <object class="GtkSingleSelection" id="selection">
+ <property name="model">
+ <object class="GtkFilterListModel" id="filter">
+ <property name="filter">
+ <object class="GtkStringFilter">
+ <property name="expression">
+ <lookup name="name" type="PurpleRoomlistRoom"></lookup>
+ </property>
+ <binding name="search">
+ <lookup name="text">search-entry</lookup>
+ </binding>
+ </object>
+ </property>
+ </object>
+ </property>
+ <signal name="selection-changed" handler="selection_changed_cb" swapped="no"/>
</object>
- </child>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="tree_selection">
- <signal name="changed" handler="selection_changed_cb" object="PidginRoomlistDialog" swapped="no"/>
- </object>
- </child>
+ </property>
+ <signal name="activate" handler="row_activated_cb" swapped="no"/>
<child>
- <object class="GtkPopoverMenu" id="popover">
- <property name="menu-model">popover_menu</property>
+ <object class="GtkColumnViewColumn">
+ <property name="title" translatable="1">Name</property>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="bytes">
+<![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkListItem">
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="xalign">0</property>
+ <binding name="label">
+ <lookup name="name" type="PurpleRoomlistRoom">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </property>
+ </template>
+</interface>
+]]>
+ </property>
+ </object>
+ </property>
</object>
</child>
<child>
- <object class="GtkTreeViewColumn">
- <property name="title" translatable="1">Name</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="markup">1</attribute>
- </attributes>
- </child>
+ <object class="GtkColumnViewColumn">
+ <property name="expand">1</property>
+ <property name="title" translatable="1">Description</property>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="bytes">
+<![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkListItem">
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="xalign">0</property>
+ <binding name="label">
+ <lookup name="description" type="PurpleRoomlistRoom">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </property>
+ </template>
+</interface>
+]]>
+ </property>
+ </object>
+ </property>
</object>
</child>
- <child>
- <object class="GtkTreeViewColumn">
- <property name="title" translatable="1">Description</property>
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="markup">2</attribute>
- </attributes>
- </child>
- </object>
- </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSearchBar">
+ <property name="key-capture-widget">PidginRoomlistDialog</property>
+ <property name="child">
+ <object class="GtkSearchEntry" id="search-entry">
</object>
</property>
</object>
@@ -164,14 +209,4 @@
<action-widget response="close">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>