--- a/pidgin/gtkblist.c Tue Jul 05 02:03:30 2022 -0500 +++ b/pidgin/gtkblist.c Wed Jul 06 05:47:52 2022 -0500 @@ -97,16 +97,6 @@ /* GBoxed reference count */ int box_count; - /* Used to hold error minidialogs. Gets packed - * inside PidginBuddyList.error_buttons - */ - PidginScrollBook *error_scrollbook; - - /* Pointer to the mini-dialog about having signed on elsewhere, if one - * is showing; %NULL otherwise. - */ - PidginMiniDialog *signed_on_elsewhere; - guint select_notebook_page_timeout; @@ -3097,453 +3087,6 @@ pidgin_blist_sort_method_set(val); } -/***********************************/ -/* Connection error handling stuff */ -/***********************************/ - -#define OBJECT_DATA_KEY_ACCOUNT "account" -#define DO_NOT_CLEAR_ERROR "do-not-clear-error" - -static gboolean -find_account_widget(GObject *widget, - PurpleAccount *account) -{ - if (g_object_get_data(widget, OBJECT_DATA_KEY_ACCOUNT) == account) - return 0; /* found */ - else - return 1; -} - -static void -pack_protocol_icon_start(GtkWidget *box, - PurpleAccount *account) -{ - GdkPixbuf *pixbuf; - GtkWidget *image; - - pixbuf = pidgin_create_protocol_icon(account, PIDGIN_PROTOCOL_ICON_SMALL); - if (pixbuf != NULL) { - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - - gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0); - } -} - -static void -add_error_dialog(PidginBuddyList *gtkblist, - GtkWidget *dialog) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - gtk_container_add(GTK_CONTAINER(priv->error_scrollbook), dialog); -} - -static GtkWidget * -find_child_widget_by_account(GtkContainer *container, - PurpleAccount *account) -{ - GList *l = NULL; - GList *children = NULL; - GtkWidget *ret = NULL; - /* XXX: Workaround for the currently incomplete implementation of PidginScrollBook */ - if(PIDGIN_IS_SCROLL_BOOK(container)) { - PidginScrollBook *scroll_book = PIDGIN_SCROLL_BOOK(container); - GtkWidget *notebook = pidgin_scroll_book_get_notebook(scroll_book); - container = GTK_CONTAINER(notebook); - } - children = gtk_container_get_children(container); - l = g_list_find_custom(children, account, (GCompareFunc) find_account_widget); - if (l) - ret = GTK_WIDGET(l->data); - g_list_free(children); - return ret; -} - -static void -remove_child_widget_by_account(GtkContainer *container, - PurpleAccount *account) -{ - GtkWidget *widget = find_child_widget_by_account(container, account); - if(widget) { - /* Since we are destroying the widget in response to a change in - * error, we should not clear the error. - */ - g_object_set_data(G_OBJECT(widget), DO_NOT_CLEAR_ERROR, - GINT_TO_POINTER(TRUE)); - gtk_widget_destroy(widget); - } -} - -/* Generic error buttons */ - -static void -generic_account_connect_cb(G_GNUC_UNUSED PidginMiniDialog *mini_dialog, - G_GNUC_UNUSED GtkButton *button, - gpointer user_data) -{ - PurpleAccount *account = user_data; - purple_account_connect(account); -} - -static void -generic_error_modify_cb(G_GNUC_UNUSED PidginMiniDialog *mini_dialog, - G_GNUC_UNUSED GtkButton *button, - gpointer user_data) -{ - PurpleAccount *account = user_data; - purple_account_clear_current_error(account); - pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account); -} - -static void -generic_error_enable_cb(G_GNUC_UNUSED PidginMiniDialog *mini_dialog, - G_GNUC_UNUSED GtkButton *button, - gpointer user_data) -{ - PurpleAccount *account = user_data; - purple_account_clear_current_error(account); - purple_account_set_enabled(account, TRUE); -} - -static void -generic_error_destroy_cb(GtkWidget *dialog, - PurpleAccount *account) -{ - /* If the error dialog is being destroyed in response to the - * account-error-changed signal, we don't want to clear the current - * error. - */ - if (g_object_get_data(G_OBJECT(dialog), DO_NOT_CLEAR_ERROR) == NULL) - purple_account_clear_current_error(account); -} - -#define SSL_FAQ_URI "https://developer.pidgin.im/wiki/FAQssl" - -static void -ssl_faq_clicked_cb(PidginMiniDialog *mini_dialog, - GtkButton *button, - gpointer ignored) -{ - purple_notify_uri(NULL, SSL_FAQ_URI); -} - -static void -add_generic_error_dialog(PurpleAccount *account, - const PurpleConnectionErrorInfo *err) -{ - GtkWidget *mini_dialog; - const char *username = purple_account_get_username(account); - gboolean enabled = purple_account_get_enabled(account); - char *primary; - - if (enabled) - primary = g_strdup_printf(_("%s disconnected"), username); - else - primary = g_strdup_printf(_("%s disabled"), username); - - mini_dialog = pidgin_mini_dialog_new_with_buttons( - primary, err->description, "dialog-error", account, - enabled ? _("Reconnect") : _("Re-enable"), - enabled ? generic_account_connect_cb : generic_error_enable_cb, - _("Modify Account"), generic_error_modify_cb, - NULL); - - g_free(primary); - - g_object_set_data(G_OBJECT(mini_dialog), OBJECT_DATA_KEY_ACCOUNT, - account); - - if(err->type == PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT) - pidgin_mini_dialog_add_non_closing_button(PIDGIN_MINI_DIALOG(mini_dialog), - _("SSL FAQs"), ssl_faq_clicked_cb, NULL); - - g_signal_connect_after(mini_dialog, "destroy", - (GCallback)generic_error_destroy_cb, - account); - - add_error_dialog(gtkblist, mini_dialog); -} - -static void -remove_generic_error_dialog(PurpleAccount *account) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - remove_child_widget_by_account( - GTK_CONTAINER(priv->error_scrollbook), account); -} - - -static void -update_generic_error_message(PurpleAccount *account, - const char *description) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - GtkWidget *mini_dialog = find_child_widget_by_account( - GTK_CONTAINER(priv->error_scrollbook), account); - pidgin_mini_dialog_set_description(PIDGIN_MINI_DIALOG(mini_dialog), - description); -} - - -/* Notifications about accounts which were disconnected with - * PURPLE_CONNECTION_ERROR_NAME_IN_USE - */ - -typedef void (*AccountFunction)(PurpleAccount *); - -static void -elsewhere_foreach_account(PidginMiniDialog *mini_dialog, - AccountFunction f) -{ - PurpleAccount *account; - GList *labels = gtk_container_get_children( - GTK_CONTAINER(mini_dialog->contents)); - GList *l; - - for (l = labels; l; l = l->next) { - account = g_object_get_data(G_OBJECT(l->data), OBJECT_DATA_KEY_ACCOUNT); - if (account) - f(account); - else - purple_debug_warning("gtkblist", "mini_dialog's child " - "didn't have an account stored in it!"); - } - g_list_free(labels); -} - -static void -enable_account(PurpleAccount *account) -{ - purple_account_set_enabled(account, TRUE); -} - -static void -reconnect_elsewhere_accounts(PidginMiniDialog *mini_dialog, - GtkButton *button, - gpointer unused) -{ - elsewhere_foreach_account(mini_dialog, enable_account); -} - -static void -clear_elsewhere_errors(PidginMiniDialog *mini_dialog, - gpointer unused) -{ - elsewhere_foreach_account(mini_dialog, purple_account_clear_current_error); -} - -static void -ensure_signed_on_elsewhere_minidialog(PidginBuddyList *gtkblist) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - PidginMiniDialog *mini_dialog; - - if(priv->signed_on_elsewhere) - return; - - mini_dialog = priv->signed_on_elsewhere = - pidgin_mini_dialog_new(_("Welcome back!"), NULL, "pidgin-disconnect"); - - pidgin_mini_dialog_add_button(mini_dialog, _("Re-enable"), - reconnect_elsewhere_accounts, NULL); - - /* Make dismissing the dialog clear the errors. The "destroy" signal - * does not appear to fire at quit, which is fortunate! - */ - g_signal_connect(G_OBJECT(mini_dialog), "destroy", - (GCallback) clear_elsewhere_errors, NULL); - - add_error_dialog(gtkblist, GTK_WIDGET(mini_dialog)); - - /* Set priv->signed_on_elsewhere to NULL when the dialog is destroyed */ - g_signal_connect(G_OBJECT(mini_dialog), "destroy", - (GCallback) gtk_widget_destroyed, &(priv->signed_on_elsewhere)); -} - -static void -update_signed_on_elsewhere_minidialog_title(void) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - PidginMiniDialog *mini_dialog = priv->signed_on_elsewhere; - guint accounts; - char *title; - - if (mini_dialog == NULL) - return; - - accounts = pidgin_mini_dialog_get_num_children(mini_dialog); - if (accounts == 0) { - gtk_widget_destroy(GTK_WIDGET(mini_dialog)); - return; - } - - title = g_strdup_printf( - ngettext("%d account was disabled because you signed on from another location:", - "%d accounts were disabled because you signed on from another location:", - accounts), - accounts); - pidgin_mini_dialog_set_description(mini_dialog, title); - g_free(title); -} - -static GtkWidget * -create_account_label(PurpleAccount *account) -{ - GtkWidget *hbox, *label; - const char *username = purple_account_get_username(account); - char *markup; - char *description; - - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - g_object_set_data(G_OBJECT(hbox), OBJECT_DATA_KEY_ACCOUNT, account); - - pack_protocol_icon_start(hbox, account); - - label = gtk_label_new(NULL); - markup = g_strdup_printf("<span size=\"smaller\">%s</span>", username); - gtk_label_set_markup(GTK_LABEL(label), markup); - g_free(markup); - gtk_label_set_xalign(GTK_LABEL(label), 0); - gtk_label_set_yalign(GTK_LABEL(label), 0); - g_object_set(G_OBJECT(label), "ellipsize", PANGO_ELLIPSIZE_END, NULL); - description = purple_account_get_current_error(account)->description; - if (description != NULL && *description != '\0') - gtk_widget_set_tooltip_text(label, description); - gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); - - return hbox; -} - -static void -add_to_signed_on_elsewhere(PurpleAccount *account) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - PidginMiniDialog *mini_dialog; - GtkWidget *account_label; - - ensure_signed_on_elsewhere_minidialog(gtkblist); - mini_dialog = priv->signed_on_elsewhere; - - if(find_child_widget_by_account(GTK_CONTAINER(mini_dialog->contents), account)) - return; - - account_label = create_account_label(account); - gtk_box_pack_start(mini_dialog->contents, account_label, FALSE, FALSE, 0); - gtk_widget_show_all(account_label); - - update_signed_on_elsewhere_minidialog_title(); -} - -static void -remove_from_signed_on_elsewhere(PurpleAccount *account) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - PidginMiniDialog *mini_dialog = priv->signed_on_elsewhere; - if(mini_dialog == NULL) - return; - - remove_child_widget_by_account(GTK_CONTAINER(mini_dialog->contents), account); - - update_signed_on_elsewhere_minidialog_title(); -} - - -static void -update_signed_on_elsewhere_tooltip(PurpleAccount *account, - const char *description) -{ - PidginBuddyListPrivate *priv = - pidgin_buddy_list_get_instance_private(gtkblist); - GtkContainer *c = GTK_CONTAINER(priv->signed_on_elsewhere->contents); - GtkWidget *label = find_child_widget_by_account(c, account); - gtk_widget_set_tooltip_text(label, description); -} - - -/* Call appropriate error notification code based on error types */ -static void -update_account_error_state(PurpleAccount *account, - const PurpleConnectionErrorInfo *old, - const PurpleConnectionErrorInfo *new, - PidginBuddyList *gtkblist) -{ - gboolean descriptions_differ; - const char *desc; - - if (old == NULL && new == NULL) - return; - - if (old != NULL && new == NULL) { - if(old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE) - remove_from_signed_on_elsewhere(account); - else - remove_generic_error_dialog(account); - return; - } - - if (old == NULL && new != NULL) { - if(new->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE) - add_to_signed_on_elsewhere(account); - else - add_generic_error_dialog(account, new); - return; - } - - /* else, new and old are both non-NULL */ - - descriptions_differ = !purple_strequal(old->description, new->description); - desc = new->description; - - switch (new->type) { - case PURPLE_CONNECTION_ERROR_NAME_IN_USE: - if (old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE - && descriptions_differ) { - update_signed_on_elsewhere_tooltip(account, desc); - } else { - remove_generic_error_dialog(account); - add_to_signed_on_elsewhere(account); - } - break; - default: - if (old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE) { - remove_from_signed_on_elsewhere(account); - add_generic_error_dialog(account, new); - } else if (descriptions_differ) { - update_generic_error_message(account, desc); - } - break; - } -} - -/* In case accounts are loaded before the blist (which they currently are), - * let's call update_account_error_state ourselves on every account's current - * state when the blist starts. - */ -static void -show_initial_account_errors(PidginBuddyList *gtkblist) -{ - PurpleAccountManager *manager = NULL; - GList *l = NULL; - PurpleAccount *account; - const PurpleConnectionErrorInfo *err; - - manager = purple_account_manager_get_default(); - l = purple_account_manager_get_all(manager); - for(; l; l = l->next) { - account = l->data; - err = purple_account_get_current_error(account); - - update_account_error_state(account, NULL, err, gtkblist); - } -} - /* This assumes there are not things like groupless buddies or multi-leveled groups. * I'm sure other things in this code assumes that also. */ @@ -3733,7 +3276,6 @@ static void pidgin_blist_show(PurpleBuddyList *list) { - PidginBuddyListPrivate *priv; GSimpleActionGroup *action_group = NULL; void *handle; GtkTreeViewColumn *column; @@ -3747,7 +3289,6 @@ } gtkblist = PIDGIN_BUDDY_LIST(list); - priv = pidgin_buddy_list_get_instance_private(gtkblist); gtkblist->window = pidgin_contact_list_window_new(); g_signal_connect(G_OBJECT(gtkblist->window), "focus-in-event", @@ -3840,10 +3381,6 @@ gtkblist->scrollbook = pidgin_scroll_book_new(); gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->scrollbook, FALSE, FALSE, 0); - priv->error_scrollbook = PIDGIN_SCROLL_BOOK(pidgin_scroll_book_new()); - gtk_box_pack_start(GTK_BOX(gtkblist->vbox), - GTK_WIDGET(priv->error_scrollbook), FALSE, FALSE, 0); - /* Update some dynamic things */ pidgin_blist_update_sort_methods(); @@ -3863,11 +3400,6 @@ /* Setup some purple signal handlers. */ - handle = purple_accounts_get_handle(); - purple_signal_connect(handle, "account-error-changed", gtkblist, - G_CALLBACK(update_account_error_state), - gtkblist); - handle = purple_conversations_get_handle(); purple_signal_connect(handle, "conversation-updated", gtkblist, G_CALLBACK(conversation_updated_cb), @@ -3882,8 +3414,6 @@ G_CALLBACK(conversation_created_cb), gtkblist); - show_initial_account_errors(gtkblist); - /* emit our created signal */ handle = pidgin_blist_get_handle(); purple_signal_emit(handle, "gtkblist-created", list);