diff -r 083eae91c9a8 -r a109a8cc8059 pidgin/plugins/disco/gtkdisco.c
--- a/pidgin/plugins/disco/gtkdisco.c Thu Feb 23 23:44:43 2023 -0600
+++ b/pidgin/plugins/disco/gtkdisco.c Fri Feb 24 00:45:22 2023 -0600
@@ -51,7 +51,6 @@
static void
pidgin_disco_list_destroy(PidginDiscoList *list)
{
- g_hash_table_destroy(list->services);
if (list->dialog && list->dialog->discolist == list) {
list->dialog->discolist = NULL;
}
@@ -181,11 +180,9 @@
g_simple_action_set_enabled(dialog->register_action, FALSE);
g_clear_pointer(&dialog->discolist, pidgin_disco_list_unref);
- gtk_tree_store_clear(dialog->model);
+ g_list_store_remove_all(dialog->root);
pdl = dialog->discolist = pidgin_disco_list_new();
- pdl->services = g_hash_table_new_full(NULL, NULL, NULL,
- (GDestroyNotify)gtk_tree_row_reference_free);
pdl->pc = pc;
/* We keep a copy... */
pidgin_disco_list_ref(pdl);
@@ -245,64 +242,30 @@
}
}
-static gboolean
-service_click_cb(G_GNUC_UNUSED GtkGestureClick *click,
- G_GNUC_UNUSED gint n_press,
- gdouble x, gdouble y, gpointer data)
+static void
+selection_changed_cb(GtkSelectionModel *self, G_GNUC_UNUSED guint position,
+ G_GNUC_UNUSED guint n_items, gpointer data)
{
PidginDiscoDialog *dialog = data;
- XmppDiscoService *service;
-
- GtkTreePath *path;
- GtkTreeIter iter;
- GValue val;
-
- GdkRectangle rect;
-
- /* Figure out what was clicked */
- if (!gtk_tree_view_get_path_at_pos(dialog->tree, (gint)x, (gint)y, &path,
- NULL, NULL, NULL))
- {
- return FALSE;
- }
- gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path);
- gtk_tree_path_free(path);
- val.g_type = 0;
- gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
- SERVICE_COLUMN, &val);
- service = g_value_get_pointer(&val);
-
- if (!service) {
- return FALSE;
- }
-
- gtk_tree_view_convert_bin_window_to_widget_coords(dialog->tree,
- (gint)x, (gint)y,
- &rect.x, &rect.y);
- rect.width = rect.height = 1;
-
- gtk_popover_set_pointing_to(GTK_POPOVER(dialog->popover), &rect);
- gtk_popover_popup(GTK_POPOVER(dialog->popover));
-
- return FALSE;
-}
-
-static void
-selection_changed_cb(GtkTreeSelection *selection, PidginDiscoDialog *dialog)
-{
- GtkTreeIter iter;
- GValue val;
+ GtkTreeListRow *row = NULL;
gboolean allow_add = FALSE, allow_register = FALSE;
- if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
- val.g_type = 0;
- gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
- SERVICE_COLUMN, &val);
- dialog->selected = g_value_get_pointer(&val);
- if (dialog->selected != NULL) {
- XmppDiscoServiceFlags flags = xmpp_disco_service_get_flags(dialog->selected);
+ /* The passed in position and n_items gives the *range* of selections that
+ * have changed, so just re-query it since GtkSingleSelection has exactly
+ * one. */
+ row = gtk_single_selection_get_selected_item(GTK_SINGLE_SELECTION(self));
+ if(row != NULL) {
+ dialog->selected = gtk_tree_list_row_get_item(row);
+ if(XMPP_DISCO_IS_SERVICE(dialog->selected)) {
+ XmppDiscoServiceFlags flags;
+
+ flags = xmpp_disco_service_get_flags(dialog->selected);
allow_add = (flags & XMPP_DISCO_ADD) != 0;
allow_register = (flags & XMPP_DISCO_REGISTER) != 0;
+
+ /* gtk_tree_list_row_get_item returns a ref, but this struct isn't
+ * supposed to hold one, as the model holds on to it. */
+ g_object_unref(dialog->selected);
}
}
@@ -310,54 +273,73 @@
g_simple_action_set_enabled(dialog->register_action, allow_register);
}
-static void
-row_expanded_cb(G_GNUC_UNUSED GtkTreeView *tree, GtkTreeIter *arg1,
- G_GNUC_UNUSED GtkTreePath *rg2, gpointer user_data)
-{
- PidginDiscoDialog *dialog = user_data;
- XmppDiscoService *service;
- GValue val;
+static GListModel *
+service_create_child_model_cb(GObject *item, G_GNUC_UNUSED gpointer data) {
+ XmppDiscoService *service = XMPP_DISCO_SERVICE(item);
+ GListModel *model = NULL;
- val.g_type = 0;
- gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), arg1,
- SERVICE_COLUMN, &val);
- service = g_value_get_pointer(&val);
- xmpp_disco_service_expand(service);
+ model = xmpp_disco_service_get_child_model(service);
+ if(G_IS_LIST_MODEL(model)) {
+ /* Always return a new ref, as the caller takes ownership. */
+ g_object_ref(model);
+ }
+
+ return model;
}
static void
-row_activated_cb(G_GNUC_UNUSED GtkTreeView *tree_view,
- GtkTreePath *path,
- G_GNUC_UNUSED GtkTreeViewColumn *column,
- gpointer user_data)
+row_expanded_cb(GObject *obj, G_GNUC_UNUSED GParamSpec *pspec,
+ G_GNUC_UNUSED gpointer data)
{
+ GtkTreeListRow *row = GTK_TREE_LIST_ROW(obj);
+
+ if(gtk_tree_list_row_get_expanded(row)) {
+ XmppDiscoService *service = gtk_tree_list_row_get_item(row);
+ if(XMPP_DISCO_IS_SERVICE(service)) {
+ xmpp_disco_service_expand(service);
+ }
+ g_clear_object(&service);
+ }
+}
+
+static void
+list_row_notify_cb(GObject *obj, GParamSpec *pspec, gpointer data) {
+ GtkTreeListRow *row = NULL;
+
+ row = gtk_tree_expander_get_list_row(GTK_TREE_EXPANDER(obj));
+ if(GTK_IS_TREE_LIST_ROW(row)) {
+ g_signal_connect(row, "notify::expanded", G_CALLBACK(row_expanded_cb),
+ NULL);
+ }
+}
+
+static void
+row_activated_cb(GtkColumnView *self, guint position, gpointer user_data) {
PidginDiscoDialog *dialog = user_data;
- GtkTreeIter iter;
- XmppDiscoService *service;
+ GtkSelectionModel *model = NULL;
+ GtkTreeListRow *row = NULL;
+ XmppDiscoService *service = NULL;
XmppDiscoServiceFlags flags;
- GValue val;
- if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path)) {
- return;
- }
-
- val.g_type = 0;
- gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
- SERVICE_COLUMN, &val);
- service = g_value_get_pointer(&val);
+ model = gtk_column_view_get_model(self);
+ row = g_list_model_get_item(G_LIST_MODEL(model), position);
+ service = gtk_tree_list_row_get_item(row);
flags = xmpp_disco_service_get_flags(service);
if((flags & XMPP_DISCO_BROWSE) != 0) {
- if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(dialog->tree), path)) {
- gtk_tree_view_collapse_row(GTK_TREE_VIEW(dialog->tree), path);
+ if(gtk_tree_list_row_get_expanded(row)) {
+ gtk_tree_list_row_set_expanded(row, FALSE);
} else {
- gtk_tree_view_expand_row(GTK_TREE_VIEW(dialog->tree), path, FALSE);
+ gtk_tree_list_row_set_expanded(row, TRUE);
}
} else if((flags & XMPP_DISCO_REGISTER) != 0) {
g_action_activate(G_ACTION(dialog->register_action), NULL);
} else if((flags & XMPP_DISCO_ADD) != 0) {
g_action_activate(G_ACTION(dialog->add_action), NULL);
}
+
+ g_clear_object(&service);
+ g_clear_object(&row);
}
static void
@@ -393,104 +375,6 @@
pidgin_disco_list_set_in_progress(dialog->discolist, FALSE);
}
-static gboolean
-disco_query_tooltip(GtkWidget *widget, int x, int y, gboolean keyboard_mode,
- GtkTooltip *tooltip, gpointer data)
-{
- PidginDiscoDialog *dialog = data;
- GtkTreePath *path = NULL;
- GtkTreeIter iter;
- XmppDiscoService *service;
- GValue val;
- const char *type = NULL;
- char *markup, *jid, *name, *desc = NULL;
-
- if (keyboard_mode) {
- GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
- if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
- return FALSE;
- }
- path = gtk_tree_model_get_path(GTK_TREE_MODEL(dialog->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(dialog->model), &iter, path)) {
- gtk_tree_path_free(path);
- return FALSE;
- }
- }
-
- val.g_type = 0;
- gtk_tree_model_get_value(GTK_TREE_MODEL(dialog->model), &iter,
- SERVICE_COLUMN, &val);
- service = g_value_get_pointer(&val);
- if (!service) {
- gtk_tree_path_free(path);
- return FALSE;
- }
-
- switch(xmpp_disco_service_get_service_type(service)) {
- case XMPP_DISCO_SERVICE_TYPE_UNSET:
- type = _("Unknown");
- break;
-
- case XMPP_DISCO_SERVICE_TYPE_GATEWAY:
- type = _("Gateway");
- break;
-
- case XMPP_DISCO_SERVICE_TYPE_DIRECTORY:
- type = _("Directory");
- break;
-
- case XMPP_DISCO_SERVICE_TYPE_CHAT:
- type = _("Chat");
- break;
-
- case XMPP_DISCO_SERVICE_TYPE_PUBSUB_COLLECTION:
- type = _("PubSub Collection");
- break;
-
- case XMPP_DISCO_SERVICE_TYPE_PUBSUB_LEAF:
- type = _("PubSub Leaf");
- break;
-
- case XMPP_DISCO_SERVICE_TYPE_OTHER:
- type = _("Other");
- break;
- }
-
- name = g_markup_escape_text(xmpp_disco_service_get_name(service), -1);
- jid = g_markup_escape_text(xmpp_disco_service_get_jid(service), -1);
- if(xmpp_disco_service_get_description(service) != NULL) {
- desc = g_markup_escape_text(xmpp_disco_service_get_description(service),
- -1);
- }
-
- markup = g_strdup_printf("%s\n%s: %s%s%s",
- name, type, jid,
- desc != NULL ? _("\nDescription: ") : "",
- desc != NULL ? desc : "");
-
- gtk_tooltip_set_markup(tooltip, markup);
- gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, path);
-
- g_free(markup);
- g_free(jid);
- g_free(name);
- g_free(desc);
- gtk_tree_path_free(path);
-
- return TRUE;
-}
-
void pidgin_disco_signed_off_cb(PurpleConnection *pc)
{
GList *node;
@@ -506,7 +390,7 @@
pidgin_disco_list_set_in_progress(list, FALSE);
}
- gtk_tree_store_clear(dialog->model);
+ g_list_store_remove_all(dialog->root);
pidgin_disco_list_unref(list);
dialog->discolist = NULL;
@@ -550,18 +434,13 @@
gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog,
progress);
gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog,
- tree);
- gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog,
- model);
- gtk_widget_class_bind_template_child(widget_class, PidginDiscoDialog,
- popover);
+ sorter);
gtk_widget_class_bind_template_callback(widget_class, destroy_win_cb);
gtk_widget_class_bind_template_callback(widget_class,
dialog_select_account_cb);
gtk_widget_class_bind_template_callback(widget_class, row_activated_cb);
- gtk_widget_class_bind_template_callback(widget_class, row_expanded_cb);
- gtk_widget_class_bind_template_callback(widget_class, service_click_cb);
+ gtk_widget_class_bind_template_callback(widget_class, list_row_notify_cb);
gtk_widget_class_bind_template_callback(widget_class,
selection_changed_cb);
}
@@ -574,6 +453,7 @@
static void
pidgin_disco_dialog_init(PidginDiscoDialog *dialog)
{
+ GtkTreeListModel *model = NULL;
GActionEntry entries[] = {
{ .name = "stop", .activate = activate_stop },
{ .name = "browse", .activate = activate_browse },
@@ -591,10 +471,6 @@
dialog->account = pidgin_account_chooser_get_selected(
PIDGIN_ACCOUNT_CHOOSER(dialog->account_chooser));
- gtk_widget_set_has_tooltip(GTK_WIDGET(dialog->tree), TRUE);
- g_signal_connect(G_OBJECT(dialog->tree), "query-tooltip",
- G_CALLBACK(disco_query_tooltip), dialog);
-
action_group = g_simple_action_group_new();
action_map = G_ACTION_MAP(action_group);
g_action_map_add_action_entries(action_map, entries, G_N_ELEMENTS(entries),
@@ -618,6 +494,13 @@
gtk_widget_insert_action_group(GTK_WIDGET(dialog), "disco",
G_ACTION_GROUP(action_group));
+
+ dialog->root = g_list_store_new(XMPP_DISCO_TYPE_SERVICE);
+ model = gtk_tree_list_model_new(G_LIST_MODEL(dialog->root), FALSE, FALSE,
+ (GtkTreeListModelCreateModelFunc)service_create_child_model_cb,
+ NULL, NULL);
+ gtk_sort_list_model_set_model(dialog->sorter, G_LIST_MODEL(model));
+ g_object_unref(model);
}
/******************************************************************************
@@ -638,86 +521,23 @@
return dialog;
}
-void pidgin_disco_add_service(PidginDiscoList *pdl, XmppDiscoService *service, XmppDiscoService *parent)
+void
+pidgin_disco_add_service(PidginDiscoList *pdl, XmppDiscoService *service,
+ XmppDiscoService *parent)
{
PidginDiscoDialog *dialog;
- GtkTreeIter iter, parent_iter, child;
- char *icon_name = NULL;
- gboolean append = TRUE;
dialog = pdl->dialog;
g_return_if_fail(dialog != NULL);
- if (service != NULL) {
- purple_debug_info("xmppdisco", "Adding service \"%s\"",
- xmpp_disco_service_get_name(service));
- } else {
- purple_debug_info("xmppdisco", "Service \"%s\" has no children",
- xmpp_disco_service_get_name(parent));
- }
+ purple_debug_info("xmppdisco", "Adding service \"%s\" to %p",
+ xmpp_disco_service_get_name(service), parent);
gtk_progress_bar_pulse(GTK_PROGRESS_BAR(dialog->progress));
- if (parent) {
- GtkTreeRowReference *rr;
- GtkTreePath *path;
-
- rr = g_hash_table_lookup(pdl->services, parent);
- path = gtk_tree_row_reference_get_path(rr);
- if (path) {
- gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model),
- &parent_iter, path);
- gtk_tree_path_free(path);
-
- if (gtk_tree_model_iter_children(
- GTK_TREE_MODEL(dialog->model), &child,
- &parent_iter)) {
- PidginDiscoList *tmp;
- gtk_tree_model_get(
- GTK_TREE_MODEL(dialog->model), &child,
- SERVICE_COLUMN, &tmp, -1);
- if (!tmp) {
- append = FALSE;
- }
- }
- }
- }
-
- if (service == NULL) {
- if (parent != NULL && !append) {
- gtk_tree_store_remove(dialog->model, &child);
- }
- return;
+ if(parent != NULL) {
+ xmpp_disco_service_add_child(parent, service);
+ } else {
+ g_list_store_append(dialog->root, service);
}
-
- if (append) {
- gtk_tree_store_append(dialog->model, &iter,
- (parent ? &parent_iter : NULL));
- } else {
- iter = child;
- }
-
- if((xmpp_disco_service_get_flags(service) & XMPP_DISCO_BROWSE) != 0) {
- GtkTreeRowReference *rr;
- GtkTreePath *path;
-
- gtk_tree_store_append(dialog->model, &child, &iter);
-
- path = gtk_tree_model_get_path(GTK_TREE_MODEL(dialog->model),
- &iter);
- rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(dialog->model),
- path);
- g_hash_table_insert(pdl->services, service, rr);
- gtk_tree_path_free(path);
- }
-
- icon_name = xmpp_disco_service_get_icon_name(service);
-
- gtk_tree_store_set(dialog->model, &iter, ICON_NAME_COLUMN, icon_name,
- NAME_COLUMN, xmpp_disco_service_get_name(service),
- DESCRIPTION_COLUMN, xmpp_disco_service_get_description(service),
- SERVICE_COLUMN, service, -1);
-
- g_free(icon_name);
}
-