im.pidgin.cpw.resiak.disconnectreason: 5fc66358cde858aca7728721cb177c53739f524b
resiak at soc.pidgin.im
resiak at soc.pidgin.im
Wed Oct 31 11:41:03 EDT 2007
-----------------------------------------------------------------
Revision: 5fc66358cde858aca7728721cb177c53739f524b
Ancestor: 47fda7b123eae2b717ca991138186a53e6336d44
Author: resiak at soc.pidgin.im
Date: 2007-10-31T15:19:21
Branch: im.pidgin.cpw.resiak.disconnectreason
Modified files:
pidgin/gtkblist.c pidgin/gtkblist.h
ChangeLog:
Group all NAME_IN_USE errors together into one neat mini-dialog on the buddy
list, with a Re-enable button to re-enable all the accounts that were knocked
offline, and an Ignore button to dismiss the mini-dialog.
References #168
-------------- next part --------------
============================================================
--- pidgin/gtkblist.c 3ddbf234754f273de4a067f29bf39d81ebebbd5e
+++ pidgin/gtkblist.c 2cb6c8965df6f080b59abd936619edecfd138884
@@ -107,7 +107,24 @@ typedef struct
GList *entries;
} PidginJoinChatData;
+typedef struct
+{
+ /** List of #PurpleAccount that were disconnected with
+ * #PURPLE_CONNECTION_ERROR_NAME_IN_USE that have not been dealt with
+ * by the user.
+ */
+ GList *accounts_signed_on_elsewhere;
+ /** Pointer to the mini-dialog about having signed on elsewhere, if one
+ * is showing; @c NULL otherwise.
+ */
+ GtkWidget *signed_on_elsewhere_minidialog;
+ GtkLabel *signed_on_elsewhere_minidialog_title;
+ GtkVBox *signed_on_elsewhere_minidialog_accounts;
+} PidginBuddyListPrivate;
+#define PIDGIN_BUDDY_LIST_GET_PRIVATE(list) \
+ ((PidginBuddyListPrivate *)((list)->priv))
+
static GtkWidget *accountmenu = NULL;
static guint visibility_manager_count = 0;
@@ -4067,10 +4084,13 @@ static void pidgin_blist_new_list(Purple
static void pidgin_blist_new_list(PurpleBuddyList *blist)
{
PidginBuddyList *gtkblist;
+ PidginBuddyListPrivate *priv;
gtkblist = g_new0(PidginBuddyList, 1);
gtkblist->connection_errors = g_hash_table_new_full(g_direct_hash,
g_direct_equal, NULL, g_free);
+ gtkblist->priv = priv = g_new0(PidginBuddyListPrivate, 1);
+
blist->ui_data = gtkblist;
}
@@ -4296,7 +4316,37 @@ headline_box_press_cb(GtkWidget *widget,
/* Connection error handling stuff */
/***********************************/
+#define OBJECT_DATA_KEY_ACCOUNT "account"
+
+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_prpl_icon_start(GtkWidget *box,
+ PurpleAccount *account)
+{
+ GdkPixbuf *pixbuf;
+ GtkWidget *image;
+
+ pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_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);
+ }
+}
+
+/* Generic error buttons */
+
+static void
ce_modify_account_cb(PurpleAccount *account)
{
pidgin_account_dialog_show(PIDGIN_MODIFY_ACCOUNT_DIALOG, account);
@@ -4356,16 +4406,13 @@ connection_error_button_clicked_cb(GtkBu
remove_error_button(button);
}
-#define BUTTON_DATA_KEY_ACCOUNT "account"
-
/* Add a button showing the connection error message */
static void
add_generic_connection_error_button(PurpleAccount *account,
const PurpleConnectionErrorInfo *err)
{
gchar *escaped, *text;
- GtkWidget *button, *label, *image, *hbox;
- GdkPixbuf *pixbuf;
+ GtkWidget *button, *label, *hbox;
escaped = g_markup_escape_text(err->description, -1);
text = g_strdup_printf(_("<span color=\"red\">%s disconnected: %s</span>"),
@@ -4375,15 +4422,8 @@ add_generic_connection_error_button(Purp
hbox = gtk_hbox_new(FALSE, 6);
- /* Create the icon */
- pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_SMALL);
- if (pixbuf != NULL) {
- image = gtk_image_new_from_pixbuf(pixbuf);
- g_object_unref(pixbuf);
+ pack_prpl_icon_start(hbox, account);
- gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
- }
-
/* Create the text */
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), text);
@@ -4395,7 +4435,7 @@ add_generic_connection_error_button(Purp
/* Create the actual button and put the icon and text on it */
button = gtk_button_new();
- g_object_set_data(G_OBJECT(button), BUTTON_DATA_KEY_ACCOUNT, account);
+ g_object_set_data(G_OBJECT(button), OBJECT_DATA_KEY_ACCOUNT, account);
gtk_container_add(GTK_CONTAINER(button), hbox);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(connection_error_button_clicked_cb),
@@ -4407,23 +4447,13 @@ add_generic_connection_error_button(Purp
gtk_widget_show_all(gtkblist->error_buttons);
}
-static gboolean
-find_account_button(GObject *button,
- PurpleAccount *account)
-{
- if (g_object_get_data(button, BUTTON_DATA_KEY_ACCOUNT) == account)
- return 0; /* found */
- else
- return 1;
-}
-
static void
remove_generic_connection_error_button(PurpleAccount *account)
{
GtkButton *button;
GList *l = NULL;
GList *children = gtk_container_get_children(GTK_CONTAINER(gtkblist->error_buttons));
- l = g_list_find_custom(children, account, (GCompareFunc) find_account_button);
+ l = g_list_find_custom(children, account, (GCompareFunc) find_account_widget);
if (l) { /* it may have already been removed by being clicked on */
button = GTK_BUTTON(l->data);
remove_error_button(button);
@@ -4431,7 +4461,232 @@ remove_generic_connection_error_button(P
g_list_free(children);
}
+
+/* Notifications about accounts which were disconnected with
+ * PURPLE_CONNECTION_ERROR_NAME_IN_USE
+ */
+
static void
+destroy_signed_on_elsewhere_minidialog(PidginBuddyListPrivate *priv)
+{
+ if(priv->signed_on_elsewhere_minidialog == NULL)
+ return;
+
+ gtk_widget_destroy(priv->signed_on_elsewhere_minidialog);
+ priv->signed_on_elsewhere_minidialog = NULL;
+ priv->signed_on_elsewhere_minidialog_accounts = NULL;
+ priv->signed_on_elsewhere_minidialog_title = NULL;
+}
+
+static void
+reconnect_elsewhere_accounts(PidginBuddyList *gtkblist)
+{
+ PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+ GList *l;
+ PurpleAccount *account;
+ for (l = priv->accounts_signed_on_elsewhere; l; l = l->next) {
+ account = l->data;
+ purple_account_set_enabled(account, purple_core_get_ui(), TRUE);
+ }
+ g_list_free(priv->accounts_signed_on_elsewhere);
+ priv->accounts_signed_on_elsewhere = NULL;
+
+ destroy_signed_on_elsewhere_minidialog(priv);
+}
+
+static void
+ignore_elsewhere_accounts(PidginBuddyList *gtkblist)
+{
+ PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+
+ g_list_free(priv->accounts_signed_on_elsewhere);
+ priv->accounts_signed_on_elsewhere = NULL;
+
+ destroy_signed_on_elsewhere_minidialog(priv);
+}
+
+static GtkWidget *
+make_elsewhere_minidialog_button(const char *text,
+ GCallback callback)
+{
+ GtkWidget *button = gtk_button_new();
+ GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
+ GtkWidget *label = gtk_label_new(NULL);
+ char *button_text =
+ g_strdup_printf("<span size=\"smaller\">%s</span>", text);
+
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
+
+ g_signal_connect_swapped(G_OBJECT(button), "clicked", callback,
+ gtkblist);
+ gtk_container_add(GTK_CONTAINER(button), hbox);
+
+ gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), button_text);
+ g_free(button_text);
+
+ gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+
+ return button;
+}
+
+static void
+create_signed_on_elsewhere_minidialog(PidginBuddyList *gtkblist)
+{
+ PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+ GtkWidget *dialog, *vbox, *hbox, *label, *img, *button;
+ GtkSizeGroup *sg;
+
+ if(priv->signed_on_elsewhere_minidialog)
+ return;
+
+ dialog = gtk_vbox_new(FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(dialog), PIDGIN_HIG_BOX_SPACE);
+ priv->signed_on_elsewhere_minidialog = dialog;
+
+ /* HBox to hold error icon and title */
+ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+
+ img = gtk_image_new_from_stock(PIDGIN_STOCK_DISCONNECT,
+ gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL));
+ gtk_misc_set_alignment(GTK_MISC(img), 0, 0);
+ if (img)
+ gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
+
+ label = gtk_label_new(NULL);
+ priv->signed_on_elsewhere_minidialog_title = GTK_LABEL(label);
+ gtk_widget_set_size_request(label,
+ purple_prefs_get_int(PIDGIN_PREFS_ROOT "/blist/width")-25, -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(hbox), label, TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(dialog), hbox, FALSE, FALSE, 0);
+
+ /* VBox to hold "[prplicon] account at server.com" widgets */
+ vbox = gtk_vbox_new(FALSE, 0);
+ priv->signed_on_elsewhere_minidialog_accounts = GTK_VBOX(vbox);
+ gtk_box_pack_start(GTK_BOX(dialog), vbox, FALSE, FALSE, 0);
+
+ /* HBox to hold buttons */
+ hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+ sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
+
+ button = make_elsewhere_minidialog_button(_("Re-enable"),
+ (GCallback) reconnect_elsewhere_accounts);
+ gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_size_group_add_widget(sg, button);
+
+ button = make_elsewhere_minidialog_button(_("Ignore"),
+ (GCallback) ignore_elsewhere_accounts);
+ gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+ gtk_size_group_add_widget(sg, button);
+
+ gtk_box_pack_start(GTK_BOX(dialog), hbox, FALSE, FALSE, 0);
+ pidgin_blist_add_alert(dialog);
+}
+
+static void
+update_signed_on_elsewhere_minidialog_title(void)
+{
+ PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+ guint length;
+ char *title, *title_markup;
+
+ length = g_list_length(priv->accounts_signed_on_elsewhere);
+ if (length == 0)
+ {
+ destroy_signed_on_elsewhere_minidialog(priv);
+ return;
+ }
+
+ create_signed_on_elsewhere_minidialog(gtkblist);
+
+ 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.",
+ length),
+ length);
+ title_markup = g_strdup_printf("<span weight=\"bold\" size=\"smaller\">%s</span>", title);
+
+ gtk_label_set_markup(priv->signed_on_elsewhere_minidialog_title, title_markup);
+
+ g_free(title_markup);
+ g_free(title);
+
+ gtk_widget_show_all(priv->signed_on_elsewhere_minidialog);
+}
+
+static GtkWidget *
+create_account_label(PurpleAccount *account)
+{
+ GtkWidget *hbox, *label;
+ const char *username = purple_account_get_username(account);
+ char *markup;
+
+ hbox = gtk_hbox_new(FALSE, 6);
+ g_object_set_data(G_OBJECT(hbox), OBJECT_DATA_KEY_ACCOUNT, account);
+
+ pack_prpl_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_misc_set_alignment(GTK_MISC(label), 0, 0);
+#if GTK_CHECK_VERSION(2,6,0)
+ g_object_set(label, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+#endif
+ 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_PRIVATE(gtkblist);
+ GtkWidget *account_label;
+ if(g_list_find(priv->accounts_signed_on_elsewhere, account) != NULL)
+ return;
+
+ priv->accounts_signed_on_elsewhere =
+ g_list_prepend(priv->accounts_signed_on_elsewhere, account);
+
+ update_signed_on_elsewhere_minidialog_title();
+
+ account_label = create_account_label(account);
+ gtk_box_pack_start(GTK_BOX(priv->signed_on_elsewhere_minidialog_accounts),
+ account_label, FALSE, FALSE, 0);
+ gtk_widget_show_all(account_label);
+}
+
+static void
+remove_from_signed_on_elsewhere(PurpleAccount *account)
+{
+ PidginBuddyListPrivate *priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+ if(g_list_find(priv->accounts_signed_on_elsewhere, account) == NULL)
+ return;
+
+ priv->accounts_signed_on_elsewhere =
+ g_list_remove(priv->accounts_signed_on_elsewhere, account);
+
+ if(priv->signed_on_elsewhere_minidialog_accounts) {
+ GList *children = gtk_container_get_children(
+ GTK_CONTAINER(priv->signed_on_elsewhere_minidialog_accounts));
+ GList *l = g_list_find_custom(children, account,
+ (GCompareFunc) find_account_widget);
+ if (l)
+ gtk_widget_destroy(GTK_WIDGET(l->data));
+
+ g_list_free(children);
+ }
+
+ update_signed_on_elsewhere_minidialog_title();
+}
+
+/* Call appropriate error notification code based on error types */
+
+static void
update_account_error_state(PurpleAccount *account,
const PurpleConnectionErrorInfo *old,
const PurpleConnectionErrorInfo *new,
@@ -4444,11 +4699,17 @@ update_account_error_state(PurpleAccount
pidgin_blist_update_account_error_state(account, NULL);
if (old) {
- remove_generic_connection_error_button(account);
+ if(old->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE)
+ remove_from_signed_on_elsewhere(account);
+ else
+ remove_generic_connection_error_button(account);
}
if (new) {
- add_generic_connection_error_button(account, new);
+ if(new->type == PURPLE_CONNECTION_ERROR_NAME_IN_USE)
+ add_to_signed_on_elsewhere(account);
+ else
+ add_generic_connection_error_button(account, new);
}
}
@@ -5662,6 +5923,8 @@ static void pidgin_blist_destroy(PurpleB
static void pidgin_blist_destroy(PurpleBuddyList *list)
{
+ PidginBuddyListPrivate *priv;
+
if (!gtkblist)
return;
@@ -5695,6 +5958,9 @@ static void pidgin_blist_destroy(PurpleB
gtkblist->hand_cursor = NULL;
gtkblist->arrow_cursor = NULL;
+ priv = PIDGIN_BUDDY_LIST_GET_PRIVATE(gtkblist);
+ g_free(priv);
+
g_free(gtkblist);
accountmenu = NULL;
gtkblist = NULL;
============================================================
--- pidgin/gtkblist.h f688dd28ed3f798d1e3d3de35f588963685a29f8
+++ pidgin/gtkblist.h 1432074dfa3f5aab3563e5db7c1ee41e7e759fa9
@@ -126,6 +126,8 @@ struct _PidginBuddyList {
GtkWidget *error_buttons; /**< Box containing the connection error buttons */
GtkWidget *statusbox; /**< The status selector dropdown */
GdkPixbuf *empty_avatar; /**< A 32x32 transparent pixbuf */
+
+ gpointer priv; /**< Pointer to opaque private data */
};
#define PIDGIN_BLIST(list) ((PidginBuddyList *)(list)->ui_data)
More information about the Commits
mailing list