Minor changelog updates
[pidgin-git.git] / pidgin / gtkdocklet.c
blob4a01ea7b79ca7d9f78de37c4244798772bce3d06
1 /*
2 * System tray icon (aka docklet) plugin for Purple
4 * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
5 * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
6 * Inspired by a similar plugin by:
7 * John (J5) Palmieri <johnp@martianrock.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02111-1301, USA.
24 #include "internal.h"
25 #include "pidgin.h"
27 #include "core.h"
28 #include "conversation.h"
29 #include "debug.h"
30 #include "prefs.h"
31 #include "signals.h"
32 #include "sound.h"
34 #include "gtkaccount.h"
35 #include "gtkblist.h"
36 #include "gtkconv.h"
37 #include "gtkplugin.h"
38 #include "gtkprefs.h"
39 #include "gtksavedstatuses.h"
40 #include "gtksound.h"
41 #include "gtkutils.h"
42 #include "pidginstock.h"
43 #include "gtkdocklet.h"
44 #include "gtkdialogs.h"
46 #ifndef DOCKLET_TOOLTIP_LINE_LIMIT
47 #define DOCKLET_TOOLTIP_LINE_LIMIT 5
48 #endif
50 /* globals */
51 static struct docklet_ui_ops *ui_ops = NULL;
52 static PurpleStatusPrimitive status = PURPLE_STATUS_OFFLINE;
53 static gboolean pending = FALSE;
54 static gboolean connecting = FALSE;
55 static gboolean enable_join_chat = FALSE;
56 static guint docklet_blinking_timer = 0;
57 static gboolean visible = FALSE;
58 static gboolean visibility_manager = FALSE;
60 /**************************************************************************
61 * docklet status and utility functions
62 **************************************************************************/
63 static gboolean
64 docklet_blink_icon()
66 static gboolean blinked = FALSE;
67 gboolean ret = FALSE; /* by default, don't keep blinking */
69 blinked = !blinked;
71 if(pending && !connecting) {
72 if (blinked) {
73 if (ui_ops && ui_ops->blank_icon)
74 ui_ops->blank_icon();
75 } else {
76 pidgin_docklet_update_icon();
78 ret = TRUE; /* keep blinking */
79 } else {
80 docklet_blinking_timer = 0;
81 blinked = FALSE;
84 return ret;
87 static GList *
88 get_pending_list(guint max)
90 GList *l_im = NULL;
91 GList *l_chat = NULL;
93 l_im = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_IM,
94 PIDGIN_UNSEEN_TEXT,
95 FALSE, max);
97 l_chat = pidgin_conversations_find_unseen_list(PURPLE_CONV_TYPE_CHAT,
98 PIDGIN_UNSEEN_NICK,
99 FALSE, max);
101 if (l_im != NULL && l_chat != NULL)
102 return g_list_concat(l_im, l_chat);
103 else if (l_im != NULL)
104 return l_im;
105 else
106 return l_chat;
109 static gboolean
110 docklet_update_status()
112 GList *convs, *l;
113 int count;
114 PurpleSavedStatus *saved_status;
115 PurpleStatusPrimitive newstatus = PURPLE_STATUS_OFFLINE;
116 gboolean newpending = FALSE, newconnecting = FALSE;
118 /* get the current savedstatus */
119 saved_status = purple_savedstatus_get_current();
121 /* determine if any ims have unseen messages */
122 convs = get_pending_list(DOCKLET_TOOLTIP_LINE_LIMIT);
124 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "pending")) {
125 if (convs && ui_ops->create && !visible) {
126 g_list_free(convs);
127 ui_ops->create();
128 return FALSE;
129 } else if (!convs && ui_ops->destroy && visible) {
130 ui_ops->destroy();
131 return FALSE;
135 if (!visible) {
136 g_list_free(convs);
137 return FALSE;
140 if (convs != NULL) {
141 newpending = TRUE;
143 /* set tooltip if messages are pending */
144 if (ui_ops->set_tooltip) {
145 GString *tooltip_text = g_string_new("");
146 for (l = convs, count = 0 ; l != NULL ; l = l->next, count++) {
147 if (PIDGIN_IS_PIDGIN_CONVERSATION(l->data)) {
148 PidginConversation *gtkconv = PIDGIN_CONVERSATION((PurpleConversation *)l->data);
149 if (count == DOCKLET_TOOLTIP_LINE_LIMIT - 1)
150 g_string_append(tooltip_text, _("Right-click for more unread messages...\n"));
151 else
152 g_string_append_printf(tooltip_text,
153 ngettext("%d unread message from %s\n", "%d unread messages from %s\n", gtkconv->unseen_count),
154 gtkconv->unseen_count,
155 gtk_label_get_text(GTK_LABEL(gtkconv->tab_label)));
159 /* get rid of the last newline */
160 if (tooltip_text->len > 0)
161 tooltip_text = g_string_truncate(tooltip_text, tooltip_text->len - 1);
163 ui_ops->set_tooltip(tooltip_text->str);
165 g_string_free(tooltip_text, TRUE);
168 g_list_free(convs);
170 } else if (ui_ops->set_tooltip) {
171 char *tooltip_text = g_strconcat(PIDGIN_NAME, " - ",
172 purple_savedstatus_get_title(saved_status), NULL);
173 ui_ops->set_tooltip(tooltip_text);
174 g_free(tooltip_text);
177 for(l = purple_accounts_get_all(); l != NULL; l = l->next) {
179 PurpleAccount *account = (PurpleAccount*)l->data;
180 PurpleStatus *account_status;
182 if (!purple_account_get_enabled(account, PIDGIN_UI))
183 continue;
185 if (purple_account_is_disconnected(account))
186 continue;
188 account_status = purple_account_get_active_status(account);
189 if (purple_account_is_connecting(account))
190 newconnecting = TRUE;
193 newstatus = purple_savedstatus_get_type(saved_status);
195 /* update the icon if we changed status */
196 if (status != newstatus || pending!=newpending || connecting!=newconnecting) {
197 status = newstatus;
198 pending = newpending;
199 connecting = newconnecting;
201 pidgin_docklet_update_icon();
203 /* and schedule the blinker function if messages are pending */
204 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink")
205 && pending && !connecting && docklet_blinking_timer == 0) {
206 docklet_blinking_timer = g_timeout_add(500, docklet_blink_icon, NULL);
210 return FALSE; /* for when we're called by the glib idle handler */
213 static gboolean
214 online_account_supports_chat()
216 GList *c = NULL;
217 c = purple_connections_get_all();
219 while(c != NULL) {
220 PurpleConnection *gc = c->data;
221 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl);
222 if (prpl_info != NULL && prpl_info->chat_info != NULL)
223 return TRUE;
224 c = c->next;
227 return FALSE;
230 /**************************************************************************
231 * callbacks and signal handlers
232 **************************************************************************/
233 #if 0
234 static void
235 pidgin_quit_cb()
237 /* TODO: confirm quit while pending */
239 #endif
241 static void
242 docklet_update_status_cb(void *data)
244 docklet_update_status();
247 static void
248 docklet_conv_updated_cb(PurpleConversation *conv, PurpleConvUpdateType type)
250 if (type == PURPLE_CONV_UPDATE_UNSEEN)
251 docklet_update_status();
254 static void
255 docklet_signed_on_cb(PurpleConnection *gc)
257 if (!enable_join_chat) {
258 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
259 enable_join_chat = TRUE;
261 docklet_update_status();
264 static void
265 docklet_signed_off_cb(PurpleConnection *gc)
267 if (enable_join_chat) {
268 if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info != NULL)
269 enable_join_chat = online_account_supports_chat();
271 docklet_update_status();
274 static void
275 docklet_show_pref_changed_cb(const char *name, PurplePrefType type,
276 gconstpointer value, gpointer data)
278 const char *val = value;
279 if (!strcmp(val, "always")) {
280 if (ui_ops->create) {
281 if (!visible)
282 ui_ops->create();
283 else if (!visibility_manager) {
284 pidgin_blist_visibility_manager_add();
285 visibility_manager = TRUE;
288 } else if (!strcmp(val, "never")) {
289 if (visible && ui_ops->destroy)
290 ui_ops->destroy();
291 } else {
292 if (visibility_manager) {
293 pidgin_blist_visibility_manager_remove();
294 visibility_manager = FALSE;
296 docklet_update_status();
301 /**************************************************************************
302 * docklet pop-up menu
303 **************************************************************************/
304 static void
305 docklet_toggle_mute(GtkWidget *toggle, void *data)
307 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", GTK_CHECK_MENU_ITEM(toggle)->active);
310 static void
311 docklet_toggle_blink(GtkWidget *toggle, void *data)
313 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/docklet/blink", GTK_CHECK_MENU_ITEM(toggle)->active);
316 static void
317 docklet_toggle_blist(GtkWidget *toggle, void *data)
319 purple_blist_set_visible(GTK_CHECK_MENU_ITEM(toggle)->active);
322 #ifdef _WIN32
323 /* This is a workaround for a bug in windows GTK+. Clicking outside of the
324 menu does not get rid of it, so instead we get rid of it as soon as the
325 pointer leaves the menu. */
326 static gboolean
327 hide_docklet_menu(gpointer data)
329 if (data != NULL) {
330 gtk_menu_popdown(GTK_MENU(data));
332 return FALSE;
335 static gboolean
336 docklet_menu_leave_enter(GtkWidget *menu, GdkEventCrossing *event, void *data)
338 static guint hide_docklet_timer = 0;
339 if (event->type == GDK_LEAVE_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
340 purple_debug(PURPLE_DEBUG_INFO, "docklet", "menu leave-notify-event\n");
341 /* Add some slop so that the menu doesn't annoyingly disappear when mousing around */
342 if (hide_docklet_timer == 0) {
343 hide_docklet_timer = purple_timeout_add(500,
344 hide_docklet_menu, menu);
346 } else if (event->type == GDK_ENTER_NOTIFY && event->detail == GDK_NOTIFY_ANCESTOR) {
347 purple_debug(PURPLE_DEBUG_INFO, "docklet", "menu enter-notify-event\n");
348 if (hide_docklet_timer != 0) {
349 /* Cancel the hiding if we reenter */
351 purple_timeout_remove(hide_docklet_timer);
352 hide_docklet_timer = 0;
355 return FALSE;
357 #endif
359 static void
360 show_custom_status_editor_cb(GtkMenuItem *menuitem, gpointer user_data)
362 PurpleSavedStatus *saved_status;
363 saved_status = purple_savedstatus_get_current();
365 if (purple_savedstatus_get_type(saved_status) == PURPLE_STATUS_AVAILABLE)
366 saved_status = purple_savedstatus_new(NULL, PURPLE_STATUS_AWAY);
368 pidgin_status_editor_show(FALSE,
369 purple_savedstatus_is_transient(saved_status) ? saved_status : NULL);
372 static void
373 activate_status_primitive_cb(GtkMenuItem *menuitem, gpointer user_data)
375 PurpleStatusPrimitive primitive;
376 PurpleSavedStatus *saved_status;
378 primitive = GPOINTER_TO_INT(user_data);
380 /* Try to lookup an already existing transient saved status */
381 saved_status = purple_savedstatus_find_transient_by_type_and_message(primitive, NULL);
383 /* Create a new transient saved status if we weren't able to find one */
384 if (saved_status == NULL)
385 saved_status = purple_savedstatus_new(NULL, primitive);
387 /* Set the status for each account */
388 purple_savedstatus_activate(saved_status);
391 static void
392 activate_saved_status_cb(GtkMenuItem *menuitem, gpointer user_data)
394 time_t creation_time;
395 PurpleSavedStatus *saved_status;
397 creation_time = GPOINTER_TO_INT(user_data);
398 saved_status = purple_savedstatus_find_by_creation_time(creation_time);
399 if (saved_status != NULL)
400 purple_savedstatus_activate(saved_status);
403 static GtkWidget *
404 new_menu_item_with_status_icon(GtkWidget *menu, const char *str, PurpleStatusPrimitive primitive, GtkSignalFunc sf, gpointer data, guint accel_key, guint accel_mods, char *mod)
406 GtkWidget *menuitem;
407 GdkPixbuf *pixbuf;
408 GtkWidget *image;
410 menuitem = gtk_image_menu_item_new_with_mnemonic(str);
412 if (menu)
413 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
415 if (sf)
416 g_signal_connect(G_OBJECT(menuitem), "activate", sf, data);
418 pixbuf = pidgin_create_status_icon(primitive, menu, PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
419 image = gtk_image_new_from_pixbuf(pixbuf);
420 g_object_unref(pixbuf);
421 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
423 gtk_widget_show_all(menuitem);
425 return menuitem;
428 static GtkWidget *
429 docklet_status_submenu()
431 GtkWidget *submenu, *menuitem;
432 GList *popular_statuses, *cur;
434 submenu = gtk_menu_new();
435 menuitem = gtk_menu_item_new_with_label(_("Change Status"));
436 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
438 new_menu_item_with_status_icon(submenu, _("Available"),
439 PURPLE_STATUS_AVAILABLE, G_CALLBACK(activate_status_primitive_cb),
440 GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE), 0, 0, NULL);
442 new_menu_item_with_status_icon(submenu, _("Away"),
443 PURPLE_STATUS_AWAY, G_CALLBACK(activate_status_primitive_cb),
444 GINT_TO_POINTER(PURPLE_STATUS_AWAY), 0, 0, NULL);
446 new_menu_item_with_status_icon(submenu, _("Invisible"),
447 PURPLE_STATUS_INVISIBLE, G_CALLBACK(activate_status_primitive_cb),
448 GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE), 0, 0, NULL);
450 new_menu_item_with_status_icon(submenu, _("Offline"),
451 PURPLE_STATUS_OFFLINE, G_CALLBACK(activate_status_primitive_cb),
452 GINT_TO_POINTER(PURPLE_STATUS_OFFLINE), 0, 0, NULL);
454 popular_statuses = purple_savedstatuses_get_popular(6);
455 if (popular_statuses != NULL)
456 pidgin_separator(submenu);
457 for (cur = popular_statuses; cur != NULL; cur = cur->next)
459 PurpleSavedStatus *saved_status = cur->data;
460 time_t creation_time = purple_savedstatus_get_creation_time(saved_status);
461 new_menu_item_with_status_icon(submenu,
462 purple_savedstatus_get_title(saved_status),
463 purple_savedstatus_get_type(saved_status), G_CALLBACK(activate_saved_status_cb),
464 GINT_TO_POINTER(creation_time), 0, 0, NULL);
466 g_list_free(popular_statuses);
468 pidgin_separator(submenu);
470 pidgin_new_item_from_stock(submenu, _("New..."), NULL, G_CALLBACK(show_custom_status_editor_cb), NULL, 0, 0, NULL);
471 pidgin_new_item_from_stock(submenu, _("Saved..."), NULL, G_CALLBACK(pidgin_status_window_show), NULL, 0, 0, NULL);
473 return menuitem;
476 static void
477 docklet_menu() {
478 static GtkWidget *menu = NULL;
479 GtkWidget *menuitem;
481 if (menu) {
482 gtk_widget_destroy(menu);
485 menu = gtk_menu_new();
487 menuitem = gtk_check_menu_item_new_with_label(_("Show Buddy List"));
488 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/list_visible"));
489 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_blist), NULL);
490 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
492 menuitem = gtk_menu_item_new_with_label(_("Unread Messages"));
494 if (pending) {
495 GtkWidget *submenu = gtk_menu_new();
496 GList *l = get_pending_list(0);
497 if (l == NULL) {
498 gtk_widget_set_sensitive(menuitem, FALSE);
499 purple_debug_warning("docklet",
500 "status indicates messages pending, but no conversations with unseen messages were found.");
501 } else {
502 pidgin_conversations_fill_menu(submenu, l);
503 g_list_free(l);
504 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
506 } else {
507 gtk_widget_set_sensitive(menuitem, FALSE);
509 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
511 pidgin_separator(menu);
513 menuitem = pidgin_new_item_from_stock(menu, _("New Message..."), PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, G_CALLBACK(pidgin_dialogs_im), NULL, 0, 0, NULL);
514 if (status == PURPLE_STATUS_OFFLINE)
515 gtk_widget_set_sensitive(menuitem, FALSE);
517 menuitem = docklet_status_submenu();
518 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
520 pidgin_separator(menu);
522 pidgin_new_item_from_stock(menu, _("Accounts"), NULL, G_CALLBACK(pidgin_accounts_window_show), NULL, 0, 0, NULL);
523 pidgin_new_item_from_stock(menu, _("Plugins"), PIDGIN_STOCK_TOOLBAR_PLUGINS, G_CALLBACK(pidgin_plugin_dialog_show), NULL, 0, 0, NULL);
524 pidgin_new_item_from_stock(menu, _("Preferences"), GTK_STOCK_PREFERENCES, G_CALLBACK(pidgin_prefs_show), NULL, 0, 0, NULL);
526 pidgin_separator(menu);
528 menuitem = gtk_check_menu_item_new_with_label(_("Mute Sounds"));
529 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute"));
530 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/method"), "none"))
531 gtk_widget_set_sensitive(GTK_WIDGET(menuitem), FALSE);
532 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_mute), NULL);
533 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
535 menuitem = gtk_check_menu_item_new_with_label(_("Blink on new message"));
536 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/docklet/blink"));
537 g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(docklet_toggle_blink), NULL);
538 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
540 pidgin_separator(menu);
542 pidgin_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, G_CALLBACK(purple_core_quit), NULL, 0, 0, NULL);
544 #ifdef _WIN32
545 g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
546 g_signal_connect(menu, "enter-notify-event", G_CALLBACK(docklet_menu_leave_enter), NULL);
547 #endif
548 gtk_widget_show_all(menu);
549 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
550 ui_ops->position_menu,
551 NULL, 0, gtk_get_current_event_time());
554 /**************************************************************************
555 * public api for ui_ops
556 **************************************************************************/
557 void
558 pidgin_docklet_update_icon()
560 if (ui_ops && ui_ops->update_icon)
561 ui_ops->update_icon(status, connecting, pending);
564 void
565 pidgin_docklet_clicked(int button_type)
567 switch (button_type) {
568 case 1:
569 if (pending) {
570 GList *l = get_pending_list(1);
571 if (l != NULL) {
572 purple_conversation_present((PurpleConversation *)l->data);
573 g_list_free(l);
575 } else {
576 pidgin_blist_toggle_visibility();
578 break;
579 case 3:
580 docklet_menu();
581 break;
585 void
586 pidgin_docklet_embedded()
588 if (!visibility_manager
589 && strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "pending")) {
590 pidgin_blist_visibility_manager_add();
591 visibility_manager = TRUE;
593 visible = TRUE;
594 docklet_update_status();
595 pidgin_docklet_update_icon();
598 void
599 pidgin_docklet_remove()
601 if (visible) {
602 if (visibility_manager) {
603 pidgin_blist_visibility_manager_remove();
604 visibility_manager = FALSE;
606 if (docklet_blinking_timer) {
607 g_source_remove(docklet_blinking_timer);
608 docklet_blinking_timer = 0;
610 visible = FALSE;
611 status = PURPLE_STATUS_OFFLINE;
615 void
616 pidgin_docklet_set_ui_ops(struct docklet_ui_ops *ops)
618 ui_ops = ops;
621 void*
622 pidgin_docklet_get_handle()
624 static int i;
625 return &i;
628 void
629 pidgin_docklet_init()
631 void *conn_handle = purple_connections_get_handle();
632 void *conv_handle = purple_conversations_get_handle();
633 void *accounts_handle = purple_accounts_get_handle();
634 void *status_handle = purple_savedstatuses_get_handle();
635 void *docklet_handle = pidgin_docklet_get_handle();
637 purple_prefs_add_none(PIDGIN_PREFS_ROOT "/docklet");
638 purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/docklet/blink", FALSE);
639 purple_prefs_add_string(PIDGIN_PREFS_ROOT "/docklet/show", "always");
640 purple_prefs_connect_callback(docklet_handle, PIDGIN_PREFS_ROOT "/docklet/show",
641 docklet_show_pref_changed_cb, NULL);
643 docklet_ui_init();
644 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/docklet/show"), "always") && ui_ops && ui_ops->create)
645 ui_ops->create();
647 purple_signal_connect(conn_handle, "signed-on",
648 docklet_handle, PURPLE_CALLBACK(docklet_signed_on_cb), NULL);
649 purple_signal_connect(conn_handle, "signed-off",
650 docklet_handle, PURPLE_CALLBACK(docklet_signed_off_cb), NULL);
651 purple_signal_connect(accounts_handle, "account-connecting",
652 docklet_handle, PURPLE_CALLBACK(docklet_update_status_cb), NULL);
653 purple_signal_connect(conv_handle, "received-im-msg",
654 docklet_handle, PURPLE_CALLBACK(docklet_update_status_cb), NULL);
655 purple_signal_connect(conv_handle, "conversation-created",
656 docklet_handle, PURPLE_CALLBACK(docklet_update_status_cb), NULL);
657 purple_signal_connect(conv_handle, "deleting-conversation",
658 docklet_handle, PURPLE_CALLBACK(docklet_update_status_cb), NULL);
659 purple_signal_connect(conv_handle, "conversation-updated",
660 docklet_handle, PURPLE_CALLBACK(docklet_conv_updated_cb), NULL);
661 purple_signal_connect(status_handle, "savedstatus-changed",
662 docklet_handle, PURPLE_CALLBACK(docklet_update_status_cb), NULL);
663 #if 0
664 purple_signal_connect(purple_get_core(), "quitting",
665 docklet_handle, PURPLE_CALLBACK(purple_quit_cb), NULL);
666 #endif
668 enable_join_chat = online_account_supports_chat();
671 void
672 pidgin_docklet_uninit()
674 if (visible && ui_ops && ui_ops->destroy)
675 ui_ops->destroy();