comparison pidgin/gtkdocklet-gtk.c @ 31471: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 26c1c5069c28
children cd61b074103a
comparison
equal deleted inserted replaced
31470:fd43277108be 31471:7fb5e60fd919
24 #include "debug.h" 24 #include "debug.h"
25 #include "prefs.h" 25 #include "prefs.h"
26 #include "pidginstock.h" 26 #include "pidginstock.h"
27 #include "gtkdocklet.h" 27 #include "gtkdocklet.h"
28 28
29 #define SHORT_EMBED_TIMEOUT 5
30 #define LONG_EMBED_TIMEOUT 15
31
29 /* globals */ 32 /* globals */
30 GtkStatusIcon *docklet = NULL; 33 static GtkStatusIcon *docklet = NULL;
34 static guint embed_timeout = 0;
35
36 /* protos */
37 static void docklet_gtk_status_create(gboolean);
38
39 static gboolean
40 docklet_gtk_recreate_cb(gpointer data)
41 {
42 docklet_gtk_status_create(TRUE);
43
44 return FALSE;
45 }
46
47 static gboolean
48 docklet_gtk_embed_timeout_cb(gpointer data)
49 {
50 /* The docklet was not embedded within the timeout.
51 * Remove it as a visibility manager, but leave the plugin
52 * loaded so that it can embed automatically if/when a notification
53 * area becomes available.
54 */
55 purple_debug_info("docklet", "failed to embed within timeout\n");
56 pidgin_docklet_remove();
57
58 embed_timeout = 0;
59 return FALSE;
60 }
61
62 static gboolean
63 docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
64 {
65 if (embed_timeout) {
66 purple_timeout_remove(embed_timeout);
67 embed_timeout = 0;
68 }
69
70 if (gtk_status_icon_is_embedded(docklet)) {
71 purple_debug_info("docklet", "embedded\n");
72
73 pidgin_docklet_embedded();
74 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
75 } else {
76 purple_debug_info("docklet", "detached\n");
77
78 pidgin_docklet_remove();
79 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
80 }
81
82 return TRUE;
83 }
84
85 static void
86 docklet_gtk_destroyed_cb(GtkWidget *widget, gpointer data)
87 {
88 purple_debug_info("docklet", "destroyed\n");
89
90 pidgin_docklet_remove();
91
92 g_object_unref(G_OBJECT(docklet));
93 docklet = NULL;
94
95 g_idle_add(docklet_gtk_recreate_cb, NULL);
96 }
31 97
32 static void 98 static void
33 docklet_gtk_status_activated_cb(GtkStatusIcon *status_icon, gpointer user_data) 99 docklet_gtk_status_activated_cb(GtkStatusIcon *status_icon, gpointer user_data)
34 { 100 {
35 pidgin_docklet_clicked(1); 101 pidgin_docklet_clicked(1);
112 { 178 {
113 g_return_if_fail(docklet != NULL); 179 g_return_if_fail(docklet != NULL);
114 180
115 pidgin_docklet_remove(); 181 pidgin_docklet_remove();
116 182
183 if (embed_timeout) {
184 purple_timeout_remove(embed_timeout);
185 embed_timeout = 0;
186 }
187
117 gtk_status_icon_set_visible(docklet, FALSE); 188 gtk_status_icon_set_visible(docklet, FALSE);
189 g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
118 g_object_unref(G_OBJECT(docklet)); 190 g_object_unref(G_OBJECT(docklet));
119 docklet = NULL; 191 docklet = NULL;
120 192
121 purple_debug_info("docklet", "GTK+ destroyed\n"); 193 purple_debug_info("docklet", "GTK+ destroyed\n");
122 } 194 }
135 docklet = gtk_status_icon_new(); 207 docklet = gtk_status_icon_new();
136 g_return_if_fail(docklet != NULL); 208 g_return_if_fail(docklet != NULL);
137 209
138 g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL); 210 g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
139 g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL); 211 g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
140 212 g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL);
141 pidgin_docklet_embedded(); 213 g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
214
142 gtk_status_icon_set_visible(docklet, TRUE); 215 gtk_status_icon_set_visible(docklet, TRUE);
216
217 /* This is a hack to avoid a race condition between the docklet getting
218 * embedded in the notification area and the gtkblist restoring its
219 * previous visibility state. If the docklet does not get embedded within
220 * the timeout, it will be removed as a visibility manager until it does
221 * get embedded. Ideally, we would only call docklet_embedded() when the
222 * icon was actually embedded. This only happens when the docklet is first
223 * created, not when being recreated.
224 *
225 * The gtk docklet tracks whether it successfully embedded in a pref and
226 * allows for a longer timeout period if it successfully embedded the last
227 * time it was run. This should hopefully solve problems with the buddy
228 * list not properly starting hidden when Pidgin is started on login.
229 */
230 if (!recreate) {
231 pidgin_docklet_embedded();
232 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
233 embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
234 } else {
235 embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
236 }
237 }
238
143 purple_debug_info("docklet", "GTK+ created\n"); 239 purple_debug_info("docklet", "GTK+ created\n");
144 } 240 }
145 241
146 static void 242 static void
147 docklet_gtk_status_create_ui_op(void) 243 docklet_gtk_status_create_ui_op(void)