changeset 31024:7fb5e60fd919

Re-implement the embedding timeout, so that the buddy list doesn't seem to disappear on startup entirely if you don't have a notification area. Fixes #12129.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Tue, 14 Dec 2010 06:14:35 +0000
parents fd43277108be
children cd61b074103a
files pidgin/gtkdocklet-gtk.c
diffstat 1 files changed, 98 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin/gtkdocklet-gtk.c	Sun Dec 12 11:32:07 2010 +0000
+++ b/pidgin/gtkdocklet-gtk.c	Tue Dec 14 06:14:35 2010 +0000
@@ -26,8 +26,74 @@
 #include "pidginstock.h"
 #include "gtkdocklet.h"
 
+#define SHORT_EMBED_TIMEOUT 5
+#define LONG_EMBED_TIMEOUT 15
+
 /* globals */
-GtkStatusIcon *docklet = NULL;
+static GtkStatusIcon *docklet = NULL;
+static guint embed_timeout = 0;
+
+/* protos */
+static void docklet_gtk_status_create(gboolean);
+
+static gboolean
+docklet_gtk_recreate_cb(gpointer data)
+{
+	docklet_gtk_status_create(TRUE);
+
+	return FALSE;
+}
+
+static gboolean
+docklet_gtk_embed_timeout_cb(gpointer data)
+{
+	/* The docklet was not embedded within the timeout.
+	 * Remove it as a visibility manager, but leave the plugin
+	 * loaded so that it can embed automatically if/when a notification
+	 * area becomes available.
+	 */
+	purple_debug_info("docklet", "failed to embed within timeout\n");
+	pidgin_docklet_remove();
+
+	embed_timeout = 0;
+	return FALSE;
+}
+
+static gboolean
+docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
+{
+	if (embed_timeout) {
+		purple_timeout_remove(embed_timeout);
+		embed_timeout = 0;
+	}
+
+	if (gtk_status_icon_is_embedded(docklet)) {
+		purple_debug_info("docklet", "embedded\n");
+
+		pidgin_docklet_embedded();
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
+	} else {
+		purple_debug_info("docklet", "detached\n");
+
+		pidgin_docklet_remove();
+		purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
+	}
+
+	return TRUE;
+}
+
+static void
+docklet_gtk_destroyed_cb(GtkWidget *widget, gpointer data)
+{
+	purple_debug_info("docklet", "destroyed\n");
+
+	pidgin_docklet_remove();
+
+	g_object_unref(G_OBJECT(docklet));
+	docklet = NULL;
+
+	g_idle_add(docklet_gtk_recreate_cb, NULL);
+}
 
 static void
 docklet_gtk_status_activated_cb(GtkStatusIcon *status_icon, gpointer user_data)
@@ -114,7 +180,13 @@
 
 	pidgin_docklet_remove();
 
+	if (embed_timeout) {
+		purple_timeout_remove(embed_timeout);
+		embed_timeout = 0;
+	}
+
 	gtk_status_icon_set_visible(docklet, FALSE);
+	g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
 	g_object_unref(G_OBJECT(docklet));
 	docklet = NULL;
 
@@ -137,9 +209,33 @@
 
 	g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
 	g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
+	g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL);
+	g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
 
-	pidgin_docklet_embedded();
 	gtk_status_icon_set_visible(docklet, TRUE);
+
+	/* This is a hack to avoid a race condition between the docklet getting
+	 * embedded in the notification area and the gtkblist restoring its
+	 * previous visibility state.  If the docklet does not get embedded within
+	 * the timeout, it will be removed as a visibility manager until it does
+	 * get embedded.  Ideally, we would only call docklet_embedded() when the
+	 * icon was actually embedded. This only happens when the docklet is first
+	 * created, not when being recreated.
+	 *
+	 * The gtk docklet tracks whether it successfully embedded in a pref and
+	 * allows for a longer timeout period if it successfully embedded the last
+	 * time it was run. This should hopefully solve problems with the buddy
+	 * list not properly starting hidden when Pidgin is started on login.
+	 */
+	if (!recreate) {
+		pidgin_docklet_embedded();
+		if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
+			embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
+		} else {
+			embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
+		}
+	}
+
 	purple_debug_info("docklet", "GTK+ created\n");
 }