comparison pidgin/gtkdocklet.c @ 32779:d72f2f13b60f

merge of 'c8c73eea7431e6f940916315ace40a41c8da3faa' and 'fec428131bde0ae8247941bd6a3d996c984c9189'
author Ethan Blanton <elb@pidgin.im>
date Fri, 21 Oct 2011 14:36:18 +0000
parents 2ec94166be43
children
comparison
equal deleted inserted replaced
32778:14787acaf9d7 32779:d72f2f13b60f
28 #include "conversation.h" 28 #include "conversation.h"
29 #include "debug.h" 29 #include "debug.h"
30 #include "prefs.h" 30 #include "prefs.h"
31 #include "signals.h" 31 #include "signals.h"
32 #include "sound.h" 32 #include "sound.h"
33 #include "status.h"
33 34
34 #include "gtkaccount.h" 35 #include "gtkaccount.h"
35 #include "gtkblist.h" 36 #include "gtkblist.h"
36 #include "gtkconv.h" 37 #include "gtkconv.h"
37 #include "gtkplugin.h" 38 #include "gtkplugin.h"
46 47
47 #ifndef DOCKLET_TOOLTIP_LINE_LIMIT 48 #ifndef DOCKLET_TOOLTIP_LINE_LIMIT
48 #define DOCKLET_TOOLTIP_LINE_LIMIT 5 49 #define DOCKLET_TOOLTIP_LINE_LIMIT 5
49 #endif 50 #endif
50 51
52 #define SHORT_EMBED_TIMEOUT 5
53 #define LONG_EMBED_TIMEOUT 15
54
51 /* globals */ 55 /* globals */
52 static struct docklet_ui_ops *ui_ops = NULL; 56 static GtkStatusIcon *docklet = NULL;
57 static guint embed_timeout = 0;
53 static PurpleStatusPrimitive status = PURPLE_STATUS_OFFLINE; 58 static PurpleStatusPrimitive status = PURPLE_STATUS_OFFLINE;
54 static gboolean pending = FALSE; 59 static gboolean pending = FALSE;
55 static gboolean connecting = FALSE; 60 static gboolean connecting = FALSE;
56 static gboolean enable_join_chat = FALSE; 61 static gboolean enable_join_chat = FALSE;
57 static guint docklet_blinking_timer = 0; 62 static guint docklet_blinking_timer = 0;
58 static gboolean visible = FALSE; 63 static gboolean visible = FALSE;
59 static gboolean visibility_manager = FALSE; 64 static gboolean visibility_manager = FALSE;
60 65
66 /* protos */
67 static void docklet_gtk_status_create(gboolean);
68 static void docklet_gtk_status_destroy(void);
69
61 /************************************************************************** 70 /**************************************************************************
62 * docklet status and utility functions 71 * docklet status and utility functions
63 **************************************************************************/ 72 **************************************************************************/
73 static void
74 docklet_gtk_status_update_icon(PurpleStatusPrimitive status, gboolean connecting, gboolean pending)
75 {
76 const gchar *icon_name = NULL;
77
78 switch (status) {
79 case PURPLE_STATUS_OFFLINE:
80 icon_name = PIDGIN_STOCK_TRAY_OFFLINE;
81 break;
82 case PURPLE_STATUS_AWAY:
83 icon_name = PIDGIN_STOCK_TRAY_AWAY;
84 break;
85 case PURPLE_STATUS_UNAVAILABLE:
86 icon_name = PIDGIN_STOCK_TRAY_BUSY;
87 break;
88 case PURPLE_STATUS_EXTENDED_AWAY:
89 icon_name = PIDGIN_STOCK_TRAY_XA;
90 break;
91 case PURPLE_STATUS_INVISIBLE:
92 icon_name = PIDGIN_STOCK_TRAY_INVISIBLE;
93 break;
94 default:
95 icon_name = PIDGIN_STOCK_TRAY_AVAILABLE;
96 break;
97 }
98
99 if (pending)
100 icon_name = PIDGIN_STOCK_TRAY_PENDING;
101 if (connecting)
102 icon_name = PIDGIN_STOCK_TRAY_CONNECT;
103
104 if (icon_name) {
105 gtk_status_icon_set_from_icon_name(docklet, icon_name);
106 }
107
108 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink")) {
109 gtk_status_icon_set_blinking(docklet, (pending && !connecting));
110 } else if (gtk_status_icon_get_blinking(docklet)) {
111 gtk_status_icon_set_blinking(docklet, FALSE);
112 }
113 }
114
64 static gboolean 115 static gboolean
65 docklet_blink_icon(gpointer data) 116 docklet_blink_icon(gpointer data)
66 { 117 {
67 static gboolean blinked = FALSE; 118 static gboolean blinked = FALSE;
68 gboolean ret = FALSE; /* by default, don't keep blinking */ 119 gboolean ret = FALSE; /* by default, don't keep blinking */
69 120
70 blinked = !blinked; 121 blinked = !blinked;
71 122
72 if(pending && !connecting) { 123 if(pending && !connecting) {
73 if (blinked) { 124 if (!blinked) {
74 if (ui_ops && ui_ops->blank_icon) 125 docklet_gtk_status_update_icon(status, connecting, pending);
75 ui_ops->blank_icon();
76 } else {
77 pidgin_docklet_update_icon();
78 } 126 }
79 ret = TRUE; /* keep blinking */ 127 ret = TRUE; /* keep blinking */
80 } else { 128 } else {
81 docklet_blinking_timer = 0; 129 docklet_blinking_timer = 0;
82 blinked = FALSE; 130 blinked = FALSE;
124 172
125 /* determine if any ims have unseen messages */ 173 /* determine if any ims have unseen messages */
126 convs = get_pending_list(DOCKLET_TOOLTIP_LINE_LIMIT); 174 convs = get_pending_list(DOCKLET_TOOLTIP_LINE_LIMIT);
127 175
128 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "pending")) { 176 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "pending")) {
129 if (convs && ui_ops->create && !visible) { 177 if (convs && !visible) {
130 g_list_free(convs); 178 g_list_free(convs);
131 ui_ops->create(); 179 docklet_gtk_status_create(FALSE);
132 return FALSE; 180 return FALSE;
133 } else if (!convs && ui_ops->destroy && visible) { 181 } else if (!convs && visible) {
134 ui_ops->destroy(); 182 docklet_gtk_status_destroy();
135 return FALSE; 183 return FALSE;
136 } 184 }
137 } 185 }
138 186
139 if (!visible) { 187 if (!visible) {
140 g_list_free(convs); 188 g_list_free(convs);
141 return FALSE; 189 return FALSE;
142 } 190 }
143 191
144 if (convs != NULL) { 192 if (convs != NULL) {
193 /* set tooltip if messages are pending */
194 GString *tooltip_text = g_string_new("");
145 newpending = TRUE; 195 newpending = TRUE;
146 196
147 /* set tooltip if messages are pending */ 197 for (l = convs, count = 0 ; l != NULL ; l = l->next, count++) {
148 if (ui_ops->set_tooltip) { 198 PurpleConversation *conv = (PurpleConversation *)l->data;
149 GString *tooltip_text = g_string_new(""); 199 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
150 for (l = convs, count = 0 ; l != NULL ; l = l->next, count++) { 200
151 PurpleConversation *conv = (PurpleConversation *)l->data; 201 if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1) {
152 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 202 g_string_append(tooltip_text, _("Right-click for more unread messages...\n"));
153 203 } else if(gtkconv) {
154 if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1) { 204 g_string_append_printf(tooltip_text,
155 g_string_append(tooltip_text, _("Right-click for more unread messages...\n")); 205 ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
156 } else if(gtkconv) { 206 gtkconv->unseen_count,
157 g_string_append_printf(tooltip_text, 207 purple_conversation_get_title(conv));
158 ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count), 208 } else {
159 gtkconv->unseen_count, 209 g_string_append_printf(tooltip_text,
160 purple_conversation_get_title(conv)); 210 ngettext("%d unread message from %s\n", "%d unread messages from %s\n",
161 } else { 211 GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"))),
162 g_string_append_printf(tooltip_text, 212 GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")),
163 ngettext("%d unread message from %s\n", "%d unread messages from %s\n", 213 purple_conversation_get_title(conv));
164 GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count"))),
165 GPOINTER_TO_INT(purple_conversation_get_data(conv, "unseen-count")),
166 purple_conversation_get_title(conv));
167 }
168 } 214 }
169 215 }
170 /* get rid of the last newline */ 216
171 if (tooltip_text->len > 0) 217 /* get rid of the last newline */
172 tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len - 1); 218 if (tooltip_text->len > 0)
173 219 tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len - 1);
174 ui_ops->set_tooltip(tooltip_text->str); 220
175 221 gtk_status_icon_set_tooltip(docklet, tooltip_text->str);
176 g_string_free(tooltip_text, TRUE); 222
177 } 223 g_string_free(tooltip_text, TRUE);
178
179 g_list_free(convs); 224 g_list_free(convs);
180 225
181 } else if (ui_ops->set_tooltip) { 226 } else {
182 char *tooltip_text = g_strconcat(PIDGIN_NAME, " - ", 227 char *tooltip_text = g_strconcat(PIDGIN_NAME, " - ",
183 purple_savedstatus_get_title(saved_status), NULL); 228 purple_savedstatus_get_title(saved_status), NULL);
184 ui_ops->set_tooltip(tooltip_text); 229 gtk_status_icon_set_tooltip(docklet, tooltip_text);
185 g_free(tooltip_text); 230 g_free(tooltip_text);
186 } 231 }
187 232
188 for(l = purple_accounts_get_all(); l != NULL; l = l->next) { 233 for(l = purple_accounts_get_all(); l != NULL; l = l->next) {
189 234
190 PurpleAccount *account = (PurpleAccount*)l->data; 235 PurpleAccount *account = (PurpleAccount*)l->data;
191 PurpleStatus *account_status;
192 236
193 if (!purple_account_get_enabled(account, PIDGIN_UI)) 237 if (!purple_account_get_enabled(account, PIDGIN_UI))
194 continue; 238 continue;
195 239
196 if (purple_account_is_disconnected(account)) 240 if (purple_account_is_disconnected(account))
197 continue; 241 continue;
198 242
199 account_status = purple_account_get_active_status(account);
200 if (purple_account_is_connecting(account)) 243 if (purple_account_is_connecting(account))
201 newconnecting = TRUE; 244 newconnecting = TRUE;
202 } 245 }
203 246
204 newstatus = purple_savedstatus_get_type(saved_status); 247 newstatus = purple_savedstatus_get_type(saved_status);
207 if (status != newstatus || pending!=newpending || connecting!=newconnecting) { 250 if (status != newstatus || pending!=newpending || connecting!=newconnecting) {
208 status = newstatus; 251 status = newstatus;
209 pending = newpending; 252 pending = newpending;
210 connecting = newconnecting; 253 connecting = newconnecting;
211 254
212 pidgin_docklet_update_icon(); 255 docklet_gtk_status_update_icon(status, connecting, pending);
213 256
214 /* and schedule the blinker function if messages are pending */ 257 /* and schedule the blinker function if messages are pending */
215 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink") 258 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink")
216 && pending && !connecting && docklet_blinking_timer == 0) { 259 && pending && !connecting && docklet_blinking_timer == 0) {
217 docklet_blinking_timer = g_timeout_add(500, docklet_blink_icon, NULL); 260 docklet_blinking_timer = g_timeout_add(500, docklet_blink_icon, NULL);
227 GList *c = NULL; 270 GList *c = NULL;
228 c = purple_connections_get_all(); 271 c = purple_connections_get_all();
229 272
230 while(c != NULL) { 273 while(c != NULL) {
231 PurpleConnection *gc = c->data; 274 PurpleConnection *gc = c->data;
232 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); 275 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc));
233 if (prpl_info != NULL && prpl_info->chat_info != NULL) 276 if (prpl_info != NULL && prpl_info->chat_info != NULL)
234 return TRUE; 277 return TRUE;
235 c = c->next; 278 c = c->next;
236 } 279 }
237 280
264 307
265 static void 308 static void
266 docklet_signed_on_cb(PurpleConnection *gc) 309 docklet_signed_on_cb(PurpleConnection *gc)
267 { 310 {
268 if (!enable_join_chat) { 311 if (!enable_join_chat) {
269 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL) 312 if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc))->chat_info != NULL)
270 enable_join_chat = TRUE; 313 enable_join_chat = TRUE;
271 } 314 }
272 docklet_update_status(); 315 docklet_update_status();
273 } 316 }
274 317
275 static void 318 static void
276 docklet_signed_off_cb(PurpleConnection *gc) 319 docklet_signed_off_cb(PurpleConnection *gc)
277 { 320 {
278 if (enable_join_chat) { 321 if (enable_join_chat) {
279 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL) 322 if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc))->chat_info != NULL)
280 enable_join_chat = online_account_supports_chat(); 323 enable_join_chat = online_account_supports_chat();
281 } 324 }
282 docklet_update_status(); 325 docklet_update_status();
283 } 326 }
284 327
286 docklet_show_pref_changed_cb(const char *name, PurplePrefType type, 329 docklet_show_pref_changed_cb(const char *name, PurplePrefType type,
287 gconstpointer value, gpointer data) 330 gconstpointer value, gpointer data)
288 { 331 {
289 const char *val = value; 332 const char *val = value;
290 if (!strcmp(val, "always")) { 333 if (!strcmp(val, "always")) {
291 if (ui_ops->create) { 334 if (!visible)
292 if (!visible) 335 docklet_gtk_status_create(FALSE);
293 ui_ops->create(); 336 else if (!visibility_manager) {
294 else if (!visibility_manager) { 337 pidgin_blist_visibility_manager_add();
295 pidgin_blist_visibility_manager_add(); 338 visibility_manager = TRUE;
296 visibility_manager = TRUE;
297 }
298 } 339 }
299 } else if (!strcmp(val, "never")) { 340 } else if (!strcmp(val, "never")) {
300 if (visible && ui_ops->destroy) 341 if (visible)
301 ui_ops->destroy(); 342 docklet_gtk_status_destroy();
302 } else { 343 } else {
303 if (visibility_manager) { 344 if (visibility_manager) {
304 pidgin_blist_visibility_manager_remove(); 345 pidgin_blist_visibility_manager_remove();
305 visibility_manager = FALSE; 346 visibility_manager = FALSE;
306 } 347 }
672 static void 713 static void
673 docklet_menu(void) 714 docklet_menu(void)
674 { 715 {
675 static GtkWidget *menu = NULL; 716 static GtkWidget *menu = NULL;
676 GtkWidget *menuitem; 717 GtkWidget *menuitem;
718 GtkMenuPositionFunc pos_func = gtk_status_icon_position_menu;
677 719
678 if (menu) { 720 if (menu) {
679 gtk_widget_destroy(menu); 721 gtk_widget_destroy(menu);
680 } 722 }
681 723
747 pidgin_new_item_from_stock(menu, _("_Quit"), GTK_STOCK_QUIT, G_CALLBACK(purple_core_quit), NULL, 0, 0, NULL); 789 pidgin_new_item_from_stock(menu, _("_Quit"), GTK_STOCK_QUIT, G_CALLBACK(purple_core_quit), NULL, 0, 0, NULL);
748 790
749 #ifdef _WIN32 791 #ifdef _WIN32
750 g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL); 792 g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
751 g_signal_connect(menu, "enter-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL); 793 g_signal_connect(menu, "enter-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
794 pos_func = NULL;
752 #endif 795 #endif
753 gtk_widget_show_all(menu); 796 gtk_widget_show_all(menu);
754 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, 797 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
755 ui_ops->position_menu, 798 pos_func,
756 NULL, 0, gtk_get_current_event_time()); 799 docklet, 0, gtk_get_current_event_time());
757 } 800 }
758 801
759 /************************************************************************** 802 static void
760 * public api for ui_ops
761 **************************************************************************/
762 void
763 pidgin_docklet_update_icon()
764 {
765 if (ui_ops && ui_ops->update_icon)
766 ui_ops->update_icon(status, connecting, pending);
767 }
768
769 void
770 pidgin_docklet_clicked(int button_type) 803 pidgin_docklet_clicked(int button_type)
771 { 804 {
772 switch (button_type) { 805 switch (button_type) {
773 case 1: 806 case 1:
774 if (pending) { 807 if (pending) {
785 docklet_menu(); 818 docklet_menu();
786 break; 819 break;
787 } 820 }
788 } 821 }
789 822
790 void 823 static void
791 pidgin_docklet_embedded() 824 pidgin_docklet_embedded(void)
792 { 825 {
793 if (!visibility_manager 826 if (!visibility_manager
794 && strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "pending")) { 827 && strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "pending")) {
795 pidgin_blist_visibility_manager_add(); 828 pidgin_blist_visibility_manager_add();
796 visibility_manager = TRUE; 829 visibility_manager = TRUE;
797 } 830 }
798 visible = TRUE; 831 visible = TRUE;
799 docklet_update_status(); 832 docklet_update_status();
800 pidgin_docklet_update_icon(); 833 docklet_gtk_status_update_icon(status, connecting, pending);
801 } 834 }
802 835
803 void 836 static void
804 pidgin_docklet_remove() 837 pidgin_docklet_remove(void)
805 { 838 {
806 if (visible) { 839 if (visible) {
807 if (visibility_manager) { 840 if (visibility_manager) {
808 pidgin_blist_visibility_manager_remove(); 841 pidgin_blist_visibility_manager_remove();
809 visibility_manager = FALSE; 842 visibility_manager = FALSE;
815 visible = FALSE; 848 visible = FALSE;
816 status = PURPLE_STATUS_OFFLINE; 849 status = PURPLE_STATUS_OFFLINE;
817 } 850 }
818 } 851 }
819 852
820 void 853 static gboolean
821 pidgin_docklet_set_ui_ops(struct docklet_ui_ops *ops) 854 docklet_gtk_recreate_cb(gpointer data)
822 { 855 {
823 ui_ops = ops; 856 docklet_gtk_status_create(TRUE);
824 } 857
825 858 return FALSE;
859 }
860
861 #ifndef _WIN32
862 static gboolean
863 docklet_gtk_embed_timeout_cb(gpointer data)
864 {
865 #if !GTK_CHECK_VERSION(2,12,0)
866 if (gtk_status_icon_is_embedded(docklet)) {
867 /* Older GTK+ (<2.12) don't implement the embedded signal, but the
868 information is still accessible through the above function. */
869 purple_debug_info("docklet", "embedded\n");
870
871 pidgin_docklet_embedded();
872 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
873 }
874 else
875 #endif
876 {
877 /* The docklet was not embedded within the timeout.
878 * Remove it as a visibility manager, but leave the plugin
879 * loaded so that it can embed automatically if/when a notification
880 * area becomes available.
881 */
882 purple_debug_info("docklet", "failed to embed within timeout\n");
883 pidgin_docklet_remove();
884 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
885 }
886
887 #if GTK_CHECK_VERSION(2,12,0)
888 embed_timeout = 0;
889 return FALSE;
890 #else
891 return TRUE;
892 #endif
893 }
894 #endif
895
896 #if GTK_CHECK_VERSION(2,12,0)
897 static gboolean
898 docklet_gtk_embedded_cb(GtkWidget *widget, gpointer data)
899 {
900 if (embed_timeout) {
901 purple_timeout_remove(embed_timeout);
902 embed_timeout = 0;
903 }
904
905 if (gtk_status_icon_is_embedded(docklet)) {
906 purple_debug_info("docklet", "embedded\n");
907
908 pidgin_docklet_embedded();
909 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
910 } else {
911 purple_debug_info("docklet", "detached\n");
912
913 pidgin_docklet_remove();
914 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
915 }
916
917 return TRUE;
918 }
919 #endif
920
921 static void
922 docklet_gtk_destroyed_cb(GtkWidget *widget, gpointer data)
923 {
924 purple_debug_info("docklet", "destroyed\n");
925
926 pidgin_docklet_remove();
927
928 g_object_unref(G_OBJECT(docklet));
929 docklet = NULL;
930
931 g_idle_add(docklet_gtk_recreate_cb, NULL);
932 }
933
934 static void
935 docklet_gtk_status_activated_cb(GtkStatusIcon *status_icon, gpointer user_data)
936 {
937 pidgin_docklet_clicked(1);
938 }
939
940 static void
941 docklet_gtk_status_clicked_cb(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data)
942 {
943 purple_debug_info("docklet", "The button is %u\n", button);
944 #ifdef GDK_WINDOWING_QUARTZ
945 /* You can only click left mouse button on MacOSX native GTK. Let that be the menu */
946 pidgin_docklet_clicked(3);
947 #else
948 pidgin_docklet_clicked(button);
949 #endif
950 }
951
952 static void
953 docklet_gtk_status_destroy(void)
954 {
955 g_return_if_fail(docklet != NULL);
956
957 pidgin_docklet_remove();
958
959 if (embed_timeout) {
960 purple_timeout_remove(embed_timeout);
961 embed_timeout = 0;
962 }
963
964 gtk_status_icon_set_visible(docklet, FALSE);
965 g_signal_handlers_disconnect_by_func(G_OBJECT(docklet), G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
966 g_object_unref(G_OBJECT(docklet));
967 docklet = NULL;
968
969 purple_debug_info("docklet", "GTK+ destroyed\n");
970 }
971
972 static void
973 docklet_gtk_status_create(gboolean recreate)
974 {
975 if (docklet) {
976 /* if this is being called when a tray icon exists, it's because
977 something messed up. try destroying it before we proceed,
978 although docklet_refcount may be all hosed. hopefully won't happen. */
979 purple_debug_warning("docklet", "trying to create icon but it already exists?\n");
980 docklet_gtk_status_destroy();
981 }
982
983 docklet = gtk_status_icon_new();
984 g_return_if_fail(docklet != NULL);
985
986 g_signal_connect(G_OBJECT(docklet), "activate", G_CALLBACK(docklet_gtk_status_activated_cb), NULL);
987 g_signal_connect(G_OBJECT(docklet), "popup-menu", G_CALLBACK(docklet_gtk_status_clicked_cb), NULL);
988 #if GTK_CHECK_VERSION(2,12,0)
989 g_signal_connect(G_OBJECT(docklet), "notify::embedded", G_CALLBACK(docklet_gtk_embedded_cb), NULL);
990 #endif
991 g_signal_connect(G_OBJECT(docklet), "destroy", G_CALLBACK(docklet_gtk_destroyed_cb), NULL);
992
993 gtk_status_icon_set_visible(docklet, TRUE);
994
995 /* This is a hack to avoid a race condition between the docklet getting
996 * embedded in the notification area and the gtkblist restoring its
997 * previous visibility state. If the docklet does not get embedded within
998 * the timeout, it will be removed as a visibility manager until it does
999 * get embedded. Ideally, we would only call docklet_embedded() when the
1000 * icon was actually embedded. This only happens when the docklet is first
1001 * created, not when being recreated.
1002 *
1003 * The gtk docklet tracks whether it successfully embedded in a pref and
1004 * allows for a longer timeout period if it successfully embedded the last
1005 * time it was run. This should hopefully solve problems with the buddy
1006 * list not properly starting hidden when Pidgin is started on login.
1007 */
1008 if (!recreate) {
1009 pidgin_docklet_embedded();
1010 #ifndef _WIN32
1011 #if GTK_CHECK_VERSION(2,12,0)
1012 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded")) {
1013 embed_timeout = purple_timeout_add_seconds(LONG_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
1014 } else {
1015 embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
1016 }
1017 #else
1018 embed_timeout = purple_timeout_add_seconds(SHORT_EMBED_TIMEOUT, docklet_gtk_embed_timeout_cb, NULL);
1019 #endif
1020 #endif
1021 }
1022
1023 purple_debug_info("docklet", "GTK+ created\n");
1024 }
1025
1026 /**************************************************************************
1027 * public api
1028 **************************************************************************/
1029
826 void* 1030 void*
827 pidgin_docklet_get_handle() 1031 pidgin_docklet_get_handle()
828 { 1032 {
829 static int i; 1033 static int i;
830 return &i; 1034 return &i;
836 void *conn_handle = purple_connections_get_handle(); 1040 void *conn_handle = purple_connections_get_handle();
837 void *conv_handle = purple_conversations_get_handle(); 1041 void *conv_handle = purple_conversations_get_handle();
838 void *accounts_handle = purple_accounts_get_handle(); 1042 void *accounts_handle = purple_accounts_get_handle();
839 void *status_handle = purple_savedstatuses_get_handle(); 1043 void *status_handle = purple_savedstatuses_get_handle();
840 void *docklet_handle = pidgin_docklet_get_handle(); 1044 void *docklet_handle = pidgin_docklet_get_handle();
1045 gchar *tmp;
841 1046
842 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/docklet"); 1047 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/docklet");
843 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/blink", FALSE); 1048 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/blink", FALSE);
844 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/docklet/show", "always"); 1049 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/docklet/show", "always");
845 purple_prefs_connect_callback(docklet_handle, PIDGIN_PREFS_ROOT "/docklet/show", 1050 purple_prefs_connect_callback(docklet_handle, PIDGIN_PREFS_ROOT "/docklet/show",
846 docklet_show_pref_changed_cb, NULL); 1051 docklet_show_pref_changed_cb, NULL);
847 1052
848 docklet_ui_init(); 1053 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/docklet/gtk");
849 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "always") && ui_ops && ui_ops->create) 1054 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/x11/embedded")) {
850 ui_ops->create(); 1055 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", TRUE);
1056 purple_prefs_remove(PIDGIN_PREFS_ROOT "/docklet/x11/embedded");
1057 } else {
1058 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/gtk/embedded", FALSE);
1059 }
1060
1061 tmp = g_build_path(G_DIR_SEPARATOR_S, DATADIR, "pixmaps", "pidgin", "tray", NULL);
1062 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), tmp);
1063 g_free(tmp);
1064
1065 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "always"))
1066 docklet_gtk_status_create(FALSE);
851 1067
852 purple_signal_connect(conn_handle, "signed-on", 1068 purple_signal_connect(conn_handle, "signed-on",
853 docklet_handle, PURPLE_CALLBACK(docklet_signed_on_cb), NULL); 1069 docklet_handle, PURPLE_CALLBACK(docklet_signed_on_cb), NULL);
854 purple_signal_connect(conn_handle, "signed-off", 1070 purple_signal_connect(conn_handle, "signed-off",
855 docklet_handle, PURPLE_CALLBACK(docklet_signed_off_cb), NULL); 1071 docklet_handle, PURPLE_CALLBACK(docklet_signed_off_cb), NULL);
874 } 1090 }
875 1091
876 void 1092 void
877 pidgin_docklet_uninit() 1093 pidgin_docklet_uninit()
878 { 1094 {
879 if (visible && ui_ops && ui_ops->destroy) 1095 if (visible)
880 ui_ops->destroy(); 1096 docklet_gtk_status_destroy();
881 } 1097 }
1098