comparison plugins/docklet/docklet.c @ 6208:3e3ee3cba192

[gaim-migrate @ 6694] Robot101: I fixed the docklet stuff, little buglet with not redrawing after a redisplay, and I spiffed everything up and moved code around for no reason committer: Tailor Script <tailor@pidgin.im>
author Herman Bloggs <hermanator12002@yahoo.com>
date Fri, 18 Jul 2003 03:45:39 +0000
parents 16e384bb7fbf
children 9fd7716068d9
comparison
equal deleted inserted replaced
6207:f78a42ef3101 6208:3e3ee3cba192
1 /* System tray icon (aka docklet) plugin for Gaim 1 /*
2 * Copyright (C) 2002 Robert McQueen <robot101@debian.org> 2 * System tray icon (aka docklet) plugin for Gaim
3 *
4 * Copyright (C) 2002-3 Robert McQueen <robot101@debian.org>
3 * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com> 5 * Copyright (C) 2003 Herman Bloggs <hermanator12002@yahoo.com>
4 * Inspired by a similar plugin by: 6 * Inspired by a similar plugin by:
5 * John (J5) Palmieri <johnp@martianrock.com> 7 * John (J5) Palmieri <johnp@martianrock.com>
6 * 8 *
7 * This program is free software; you can redistribute it and/or 9 * This program is free software; you can redistribute it and/or
25 - handle and update tooltips to show your current accounts/queued messages? 27 - handle and update tooltips to show your current accounts/queued messages?
26 - show a count of queued messages in the unified queue 28 - show a count of queued messages in the unified queue
27 - dernyi's account status menu in the right click 29 - dernyi's account status menu in the right click
28 - optional pop up notices when GNOME2's system-tray-applet supports it */ 30 - optional pop up notices when GNOME2's system-tray-applet supports it */
29 31
30 /* includes */
31 #include "internal.h" 32 #include "internal.h"
32 33
33 #include "core.h" 34 #include "core.h"
34 #include "debug.h" 35 #include "debug.h"
35 #include "prefs.h" 36 #include "prefs.h"
46 #include "docklet.h" 47 #include "docklet.h"
47 48
48 #include "gaim.h" 49 #include "gaim.h"
49 #include "ui.h" 50 #include "ui.h"
50 51
51 #define DOCKLET_PLUGIN_ID "gtk-docklet"
52
53 /* globals */ 52 /* globals */
54 static struct gaim_tray_ops *tray_ops = NULL; 53
55 static enum docklet_status status=offline; 54 GaimPlugin *handle = NULL;
56 static enum docklet_status icon=offline; 55 static struct docklet_ui_ops *ui_ops = NULL;
56 static enum docklet_status status = offline;
57 static enum docklet_status icon = offline;
57 #ifdef _WIN32 58 #ifdef _WIN32
58 __declspec(dllimport) GSList *unread_message_queue; 59 __declspec(dllimport) GSList *unread_message_queue;
59 __declspec(dllimport) GSList *away_messages; 60 __declspec(dllimport) GSList *away_messages;
60 __declspec(dllimport) struct away_message *awaymessage; 61 __declspec(dllimport) struct away_message *awaymessage;
61 __declspec(dllimport) GSList *message_queue; 62 __declspec(dllimport) GSList *message_queue;
62 #endif 63 #endif
63 64
64 /* functions */ 65 /* private functions */
65 extern void trayicon_init(); 66
66 static gboolean docklet_update_status(); 67 static void
67 static gboolean plugin_unload(GaimPlugin *plugin); 68 docklet_toggle_mute(GtkWidget *toggle, void *data)
68 69 {
69 static void docklet_toggle_mute(GtkWidget *toggle, void *data) {
70 gaim_gtk_sound_set_mute(GTK_CHECK_MENU_ITEM(toggle)->active); 70 gaim_gtk_sound_set_mute(GTK_CHECK_MENU_ITEM(toggle)->active);
71 } 71 }
72 72
73 static void docklet_set_bool(GtkWidget *widget, const char *key) { 73 static void
74 docklet_set_bool(GtkWidget *widget, const char *key)
75 {
74 gaim_prefs_set_bool(key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); 76 gaim_prefs_set_bool(key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
75 } 77 }
76 78
77 static void docklet_auto_login() { 79 static void
80 docklet_auto_login()
81 {
78 gaim_accounts_auto_login(GAIM_GTK_UI); 82 gaim_accounts_auto_login(GAIM_GTK_UI);
79 } 83 }
80 84
81 #ifdef _WIN32 85 #ifdef _WIN32
82 /* This is a workaround for a bug in windows GTK+.. Clicking outside of the 86 /* This is a workaround for a bug in windows GTK+.. Clicking outside of the
83 menu does not get rid of it, so instead we get rid of it as soon as the 87 menu does not get rid of it, so instead we get rid of it as soon as the
84 pointer leaves the menu. */ 88 pointer leaves the menu. */
85 static gboolean menu_leave(GtkWidget *menu, 89 static gboolean
86 GdkEventCrossing *event, 90 docklet_menu_leave(GtkWidget *menu, GdkEventCrossing *event, void *data)
87 gpointer user_data) { 91 {
88 if(event->detail == GDK_NOTIFY_ANCESTOR) { 92 if(event->detail == GDK_NOTIFY_ANCESTOR) {
89 gaim_debug(GAIM_DEBUG_INFO, "docklet", "leave-notify-event\n"); 93 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "menu leave-notify-event\n");
90 gtk_menu_popdown(GTK_MENU(menu)); 94 gtk_menu_popdown(GTK_MENU(menu));
91 } 95 }
92 return FALSE; 96 return FALSE;
93 } 97 }
94 #endif 98 #endif
100 if (menu) { 104 if (menu) {
101 gtk_widget_destroy(menu); 105 gtk_widget_destroy(menu);
102 } 106 }
103 107
104 menu = gtk_menu_new(); 108 menu = gtk_menu_new();
105 #ifdef _WIN32 109
106 g_signal_connect(menu, "leave-notify-event", G_CALLBACK(menu_leave), NULL);
107 #endif
108 switch (status) { 110 switch (status) {
109 case offline: 111 case offline:
110 case offline_connecting: 112 case offline_connecting:
111 gaim_new_item_from_stock(menu, _("Auto-login"), GAIM_STOCK_SIGN_ON, G_CALLBACK(docklet_auto_login), NULL, 0, 0, NULL); 113 gaim_new_item_from_stock(menu, _("Auto-login"), GAIM_STOCK_SIGN_ON, G_CALLBACK(docklet_auto_login), NULL, 0, 0, NULL);
112 break; 114 break;
181 break; 183 break;
182 } 184 }
183 185
184 gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, G_CALLBACK(gaim_core_quit), NULL, 0, 0, 0); 186 gaim_new_item_from_stock(menu, _("Quit"), GTK_STOCK_QUIT, G_CALLBACK(gaim_core_quit), NULL, 0, 0, 0);
185 187
188 #ifdef _WIN32
189 g_signal_connect(menu, "leave-notify-event", G_CALLBACK(docklet_menu_leave), NULL);
190 #endif
186 gtk_widget_show_all(menu); 191 gtk_widget_show_all(menu);
187 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); 192 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
188 } 193 }
189 194
190 static gboolean docklet_blink_icon() { 195 static gboolean
196 docklet_blink_icon()
197 {
191 if (status == online_pending) { 198 if (status == online_pending) {
192 if (status == icon) { 199 if (status == icon) {
193 /* last icon was the right one... let's change it */ 200 /* last icon was the right one... let's change it */
194 icon = online; 201 icon = online;
195 } else { 202 } else {
207 } else { 214 } else {
208 /* no messages, stop blinking */ 215 /* no messages, stop blinking */
209 return FALSE; 216 return FALSE;
210 } 217 }
211 218
212 if(tray_ops->update_icon) 219 if (ui_ops->update_icon)
213 tray_ops->update_icon(icon); 220 ui_ops->update_icon(icon);
214 221
215 return TRUE; /* keep blinking */ 222 return TRUE; /* keep blinking */
216 } 223 }
217 224
218 static gboolean docklet_update_status() { 225 static gboolean
226 docklet_update_status()
227 {
219 enum docklet_status oldstatus; 228 enum docklet_status oldstatus;
220 229
221 oldstatus = status; 230 oldstatus = status;
222 231
223 if (gaim_connections_get_all()) { 232 if (gaim_connections_get_all()) {
243 } 252 }
244 253
245 /* update the icon if we changed status */ 254 /* update the icon if we changed status */
246 if (status != oldstatus) { 255 if (status != oldstatus) {
247 icon = status; 256 icon = status;
248 if(tray_ops->update_icon) 257 if (ui_ops->update_icon)
249 tray_ops->update_icon(icon); 258 ui_ops->update_icon(icon);
250 259
251 /* and schedule the blinker function if messages are pending */ 260 /* and schedule the blinker function if messages are pending */
252 if (status == online_pending || status == away_pending) { 261 if (status == online_pending || status == away_pending) {
253 g_timeout_add(500, docklet_blink_icon, NULL); 262 g_timeout_add(500, docklet_blink_icon, NULL);
254 } 263 }
255 } 264 }
265
256 return FALSE; /* for when we're called by the glib idle handler */ 266 return FALSE; /* for when we're called by the glib idle handler */
257 } 267 }
258 268
259 static void gaim_signon(GaimConnection *gc, void *data) { 269 void
260 docklet_update_status(); 270 docklet_flush_queue()
261 } 271 {
262 272 if (unread_message_queue) {
263 static void gaim_signoff(GaimConnection *gc, void *data) { 273 purge_away_queue(&unread_message_queue);
264 /* do this when idle so that if the prpl was connecting 274 }
265 and was cancelled, we register that connecting_count 275 }
266 has returned to 0 */ 276
267 /* no longer necessary because Chip decided that us plugins 277 void
268 * didn't need to know if an account was connecting or not 278 docklet_remove_callbacks()
269 * g_idle_add(docklet_update_status, &docklet); */ 279 {
270 docklet_update_status(); 280 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "removing callbacks");
271 } 281
272 282 while (g_source_remove_by_user_data(&handle)) {
273 static void gaim_connecting(GaimAccount *account, void *data) { 283 gaim_debug(GAIM_DEBUG_INFO, NULL, ".");
274 docklet_update_status(); 284 }
275 } 285
276 286 gaim_debug(GAIM_DEBUG_INFO, NULL, "\n");
277 static void gaim_away(GaimConnection *gc, char *state, char *message, void *data) { 287 }
278 /* we only support global away. this is the way it is, ok? */ 288
279 docklet_update_status(); 289 /* public code */
280 } 290
281 291 void
282 static void gaim_im_recv(GaimConnection *gc, char **who, char **what, void *data) { 292 docklet_clicked(int button_type)
283 /* if message queuing while away is enabled, this event could be the first 293 {
284 message so we need to see if the status (and hence icon) needs changing.
285 do this when idle so that all message processing is completed, queuing
286 etc, before we run. */
287 g_idle_add(docklet_update_status, NULL);
288 }
289
290 /* static void gaim_buddy_signon(GaimConnection *gc, char *who, void *data) {
291 }
292
293 static void gaim_buddy_signoff(GaimConnection *gc, char *who, void *data) {
294 }
295
296 static void gaim_buddy_away(GaimConnection *gc, char *who, void *data) {
297 }
298
299 static void gaim_buddy_back(GaimConnection *gc, char *who, void *data) {
300 }
301
302 static void gaim_new_conversation(char *who, void *data) {
303 } */
304
305 /*
306 * Public Code
307 */
308 void docklet_clicked(int button_type) {
309 switch (button_type) { 294 switch (button_type) {
310 case 1: 295 case 1:
311 if (unread_message_queue) { 296 if (unread_message_queue) {
312 docklet_flush_queue(); 297 docklet_flush_queue();
313 docklet_update_status(); 298 g_idle_add(docklet_update_status, &handle);
314 } else { 299 } else {
315 gaim_gtk_blist_docklet_toggle(); 300 gaim_gtk_blist_docklet_toggle();
316 } 301 }
317 break; 302 break;
318 case 2: 303 case 2:
329 docklet_menu(); 314 docklet_menu();
330 break; 315 break;
331 } 316 }
332 } 317 }
333 318
334 void docklet_embedded() { 319 void
335 gaim_debug(GAIM_DEBUG_INFO, "docklet", "Tray Icon: embedded\n"); 320 docklet_embedded()
321 {
336 gaim_gtk_blist_docklet_add(); 322 gaim_gtk_blist_docklet_add();
337 } 323
338 324 docklet_update_status();
339 void docklet_flush_queue() { 325 if (ui_ops->update_icon)
340 if (unread_message_queue) { 326 ui_ops->update_icon(icon);
341 purge_away_queue(&unread_message_queue); 327 }
342 } 328
343 } 329 void
344 330 docklet_remove(gboolean visible)
345 331 {
346 /* Set Platform Dependent Code */ 332 if (visible)
347 void docklet_set_tray_ops(struct gaim_tray_ops *ops) { 333 gaim_gtk_blist_docklet_remove();
348 tray_ops = ops; 334
349 } 335 docklet_flush_queue();
350 336 }
351 337
352 /* 338 void
353 * PLUGIN CODE 339 docklet_set_ui_ops(struct docklet_ui_ops *ops)
354 */ 340 {
341 ui_ops = ops;
342 }
343
344 /* callbacks */
345
346 static void
347 gaim_signon(GaimConnection *gc, void *data)
348 {
349 docklet_update_status();
350 }
351
352 static void
353 gaim_signoff(GaimConnection *gc, void *data)
354 {
355 /* do this when idle so that if the prpl was connecting
356 and was cancelled, we register that connecting_count
357 has returned to 0 */
358 /* no longer necessary because Chip decided that us plugins
359 didn't need to know if an account was connecting or not
360 g_idle_add(docklet_update_status, &docklet); */
361 docklet_update_status();
362 }
363
364 static void
365 gaim_connecting(GaimAccount *account, void *data)
366 {
367 docklet_update_status();
368 }
369
370 static void
371 gaim_away(GaimConnection *gc, char *state, char *message, void *data)
372 {
373 /* we only support global away. this is the way it is, ok? */
374 docklet_update_status();
375 }
376
377 static void
378 gaim_im_recv(GaimConnection *gc, char **who, char **what, void *data)
379 {
380 /* if message queuing while away is enabled, this event could be the first
381 message so we need to see if the status (and hence icon) needs changing.
382 do this when idle so that all message processing is completed, queuing
383 etc, before we run. */
384 g_idle_add(docklet_update_status, &handle);
385 }
386
387 /* static void gaim_buddy_signon(GaimConnection *gc, char *who, void *data) {
388 }
389
390 static void gaim_buddy_signoff(GaimConnection *gc, char *who, void *data) {
391 }
392
393 static void gaim_buddy_away(GaimConnection *gc, char *who, void *data) {
394 }
395
396 static void gaim_buddy_back(GaimConnection *gc, char *who, void *data) {
397 }
398
399 static void gaim_new_conversation(char *who, void *data) {
400 } */
401
402 /* plugin glue */
403
404 #define DOCKLET_PLUGIN_ID "gtk-docklet"
355 405
356 static gboolean 406 static gboolean
357 plugin_load(GaimPlugin *plugin) 407 plugin_load(GaimPlugin *plugin)
358 { 408 {
359 trayicon_init(); 409 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "plugin loaded\n");
360 if(tray_ops->create) 410
361 tray_ops->create(); 411 handle = plugin;
362 412
363 gaim_prefs_add_none("/plugins/gtk/docklet"); 413 docklet_ui_init();
364 gaim_prefs_add_bool("/plugins/gtk/docklet/queue_messages", FALSE); 414 if (ui_ops->create)
365 415 ui_ops->create();
366 docklet_update_status();
367 if(tray_ops->update_icon)
368 tray_ops->update_icon(icon);
369 416
370 gaim_signal_connect(plugin, event_signon, gaim_signon, NULL); 417 gaim_signal_connect(plugin, event_signon, gaim_signon, NULL);
371 gaim_signal_connect(plugin, event_signoff, gaim_signoff, NULL); 418 gaim_signal_connect(plugin, event_signoff, gaim_signoff, NULL);
372 gaim_signal_connect(plugin, event_connecting, gaim_connecting, NULL); 419 gaim_signal_connect(plugin, event_connecting, gaim_connecting, NULL);
373 gaim_signal_connect(plugin, event_away, gaim_away, NULL); 420 gaim_signal_connect(plugin, event_away, gaim_away, NULL);
376 gaim_signal_connect(plugin, event_buddy_signoff, gaim_buddy_signoff, NULL); 423 gaim_signal_connect(plugin, event_buddy_signoff, gaim_buddy_signoff, NULL);
377 gaim_signal_connect(plugin, event_buddy_away, gaim_buddy_away, NULL); 424 gaim_signal_connect(plugin, event_buddy_away, gaim_buddy_away, NULL);
378 gaim_signal_connect(plugin, event_buddy_back, gaim_buddy_back, NULL); 425 gaim_signal_connect(plugin, event_buddy_back, gaim_buddy_back, NULL);
379 gaim_signal_connect(plugin, event_new_conversation, gaim_new_conversation, NULL); */ 426 gaim_signal_connect(plugin, event_new_conversation, gaim_new_conversation, NULL); */
380 427
381 gaim_debug(GAIM_DEBUG_INFO, "docklet", "Plugin loaded\n"); 428 gaim_prefs_add_none("/plugins/gtk/docklet");
429 gaim_prefs_add_bool("/plugins/gtk/docklet/queue_messages", FALSE);
382 430
383 return TRUE; 431 return TRUE;
384 } 432 }
385 433
386 static gboolean 434 static gboolean
387 plugin_unload(GaimPlugin *plugin) 435 plugin_unload(GaimPlugin *plugin)
388 { 436 {
389 gaim_gtk_blist_docklet_remove(); 437 if (ui_ops->destroy)
390 docklet_flush_queue(); 438 ui_ops->destroy();
439
391 /* XXX: do this while gaim has no other way to toggle the global mute */ 440 /* XXX: do this while gaim has no other way to toggle the global mute */
392 gaim_gtk_sound_set_mute(FALSE); 441 gaim_gtk_sound_set_mute(FALSE);
393 442 docklet_remove_callbacks();
394 if(tray_ops->destroy) 443
395 tray_ops->destroy(); 444 gaim_debug(GAIM_DEBUG_INFO, "tray icon", "plugin unloaded\n");
396
397 gaim_debug(GAIM_DEBUG_INFO, "docklet", "Plugin unloaded\n");
398 445
399 return TRUE; 446 return TRUE;
400 } 447 }
401 448
402 static GtkWidget * 449 static GtkWidget *
403 get_config_frame(GaimPlugin *plugin) 450 plugin_config_frame(GaimPlugin *plugin)
404 { 451 {
405 GtkWidget *frame; 452 GtkWidget *frame;
406 GtkWidget *vbox, *hbox; 453 GtkWidget *vbox, *hbox;
407 GtkWidget *toggle; 454 GtkWidget *toggle;
408 static const char *qmpref = "/plugins/gtk/docklet/queue_messages"; 455 static const char *qmpref = "/plugins/gtk/docklet/queue_messages";
423 return frame; 470 return frame;
424 } 471 }
425 472
426 static GaimGtkPluginUiInfo ui_info = 473 static GaimGtkPluginUiInfo ui_info =
427 { 474 {
428 get_config_frame 475 plugin_config_frame
429 }; 476 };
430 477
431 static GaimPluginInfo info = 478 static GaimPluginInfo info =
432 { 479 {
433 2, /**< api_version */ 480 2, /**< api_version */
441 N_("System Tray Icon"), /**< name */ 488 N_("System Tray Icon"), /**< name */
442 VERSION, /**< version */ 489 VERSION, /**< version */
443 /** summary */ 490 /** summary */
444 N_("Displays an icon for Gaim in the system tray."), 491 N_("Displays an icon for Gaim in the system tray."),
445 /** description */ 492 /** description */
446 N_("Interacts with a Notification Area applet (in GNOME, KDE or " 493 N_("Displays a system tray icon (in GNOME, KDE or Windows for example) "
447 "Windows for example) to display the current status of Gaim, allow " 494 "to show the current status of Gaim, allow fast access to commonly "
448 "fast access to commonly used functions, and to toggle display of " 495 "used functions, and to toggle display of the buddy list or login "
449 "the buddy list or login window. Also allows messages to be queued " 496 "window. Also allows messages to be queued until the icon is "
450 "until the icon is clicked, similar to ICQ."), 497 "clicked, similar to ICQ."),
451 "Robert McQueen <robot101@debian.org>", /**< author */ 498 "Robert McQueen <robot101@debian.org>", /**< author */
452 WEBSITE, /**< homepage */ 499 WEBSITE, /**< homepage */
453 500
454 plugin_load, /**< load */ 501 plugin_load, /**< load */
455 plugin_unload, /**< unload */ 502 plugin_unload, /**< unload */
458 &ui_info, /**< ui_info */ 505 &ui_info, /**< ui_info */
459 NULL /**< extra_info */ 506 NULL /**< extra_info */
460 }; 507 };
461 508
462 static void 509 static void
463 init_plugin(GaimPlugin *plugin) 510 plugin_init(GaimPlugin *plugin)
464 { 511 {
465 } 512 }
466 513
467 GAIM_INIT_PLUGIN(docklet, init_plugin, info) 514 GAIM_INIT_PLUGIN(docklet, plugin_init, info)