Mercurial > pidgin.yaz
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 |