Remove unneeded Windows-specific code path in Notification plugin's trayicon popup...
[claws.git] / src / plugins / notification / notification_trayicon.c
1 /* Notification plugin for Claws-Mail
2  * Copyright (C) 2005-2007 Holger Berndt and the Claws Mail Team.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /* This module is of course inspired by the trayicon plugin which is
19  * shipped with Claws-Mail, copyrighted by the Claws-Mail Team. */
20
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #  include "claws-features.h"
24 #endif
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28
29 #ifdef NOTIFICATION_TRAYICON
30
31 #include "notification_trayicon.h"
32 #include "notification_prefs.h"
33 #include "notification_core.h"
34 #include "notification_hotkeys.h"
35 #include "notification_pixbuf.h"
36 #include "notification_foldercheck.h"
37
38 #include "main.h"
39 #include "account.h"
40 #include "mainwindow.h"
41 #include "prefs_common.h"
42 #include "alertpanel.h"
43 #include "gtk/menu.h"
44 #ifndef USE_NEW_ADDRBOOK
45     #include "addressbook.h"
46     #include "addrindex.h"
47 #else
48     #include "addressbook-dbus.h"
49 #endif
50
51 #include "gtk/manage_window.h"
52 #include "common/utils.h"
53 #include "gtk/gtkutils.h"
54
55 static GdkPixbuf* notification_trayicon_create(void);
56
57 static void notification_trayicon_on_popup_menu(GtkStatusIcon*,guint,
58                                                 guint,gpointer);
59 static gboolean notification_trayicon_on_size_changed(GtkStatusIcon*,
60                                                       gint, gpointer);
61
62 static void trayicon_get_all_cb(GtkAction*, gpointer);
63 static void trayicon_compose_cb(GtkAction*, gpointer);
64 static void trayicon_compose_acc_cb(GtkMenuItem*, gpointer);
65 static void trayicon_addressbook_cb(GtkAction*, gpointer);
66 static void trayicon_exit_cb(GtkAction*,gpointer);
67 static void trayicon_toggle_offline_cb(GtkAction*,gpointer);
68 #ifdef HAVE_LIBNOTIFY
69 static void trayicon_toggle_notify_cb(GtkAction*,gpointer);
70 #endif
71
72 #ifdef HAVE_LIBNOTIFY
73 #include <libnotify/notify.h>
74
75 #ifndef NOTIFY_CHECK_VERSION
76 # define NOTIFY_CHECK_VERSION(a,b,c) 0
77 #endif
78
79 typedef struct {
80   gint count;
81   gint num_mail;
82   gint num_news;
83   gint num_calendar;
84   gint num_rss;
85   gchar *msg_path;
86   NotifyNotification *notification;
87   GError *error;
88 } NotificationTrayiconPopup;
89
90 static NotificationTrayiconPopup popup;
91
92 static gboolean notification_trayicon_popup_add_msg(MsgInfo*,
93                                                     NotificationFolderType);
94 static gboolean notification_trayicon_popup_create(MsgInfo*,
95                                                    NotificationFolderType);
96 static void popup_timeout_fun(NotifyNotification*, gpointer);
97 static void notification_trayicon_popup_free_func(gpointer);
98 static void notification_trayicon_popup_default_action_cb(NotifyNotification*,
99                                                           const char*,void*);
100 static gchar* notification_trayicon_popup_assemble_summary(void);
101 static gchar* notification_trayicon_popup_assemble_body(MsgInfo*);
102 static void   notification_trayicon_popup_count_msgs(NotificationFolderType);
103
104 G_LOCK_DEFINE_STATIC(trayicon_popup);
105
106 #endif
107
108 static GtkStatusIcon *trayicon;
109 static gboolean updating_menu = FALSE;
110 static GtkWidget *traymenu_popup;
111
112 static GtkActionEntry trayicon_popup_menu_entries[] = {
113         {"SysTrayiconPopup", NULL, "SysTrayiconPopup" },
114         {"SysTrayiconPopup/GetMail", NULL, N_("_Get Mail"), NULL, NULL, G_CALLBACK(trayicon_get_all_cb) },
115         {"SysTrayiconPopup/---", NULL, "---" },
116         {"SysTrayiconPopup/Email", NULL, N_("_Email"), NULL, NULL, G_CALLBACK(trayicon_compose_cb) },
117         {"SysTrayiconPopup/EmailAcc", NULL, N_("E_mail from account"), NULL, NULL, NULL },
118         {"SysTrayiconPopup/OpenAB", NULL, N_("Open A_ddressbook"), NULL, NULL, G_CALLBACK(trayicon_addressbook_cb) },
119         {"SysTrayiconPopup/Exit", NULL, N_("E_xit Claws Mail"), NULL, NULL, G_CALLBACK(trayicon_exit_cb) },
120 };
121
122 static GtkToggleActionEntry trayicon_popup_toggle_menu_entries[] =
123 {
124         {"SysTrayiconPopup/ToggleOffline",              NULL, N_("_Work Offline"), NULL, NULL, G_CALLBACK(trayicon_toggle_offline_cb) },
125 #ifdef HAVE_LIBNOTIFY
126         {"SysTrayiconPopup/ShowBubbles", NULL, N_("Show Trayicon Notifications"), NULL, NULL, G_CALLBACK(trayicon_toggle_notify_cb) },
127 #endif
128 };
129
130
131 void notification_trayicon_msg(MsgInfo *msginfo)
132 {
133 #ifndef HAVE_LIBNOTIFY
134   return;
135
136 #else
137   FolderType ftype;
138   NotificationFolderType nftype;
139   gchar *uistr;
140
141   nftype = F_TYPE_MAIL;
142
143   if(!msginfo || !notify_config.trayicon_enabled ||
144      !notify_config.trayicon_popup_enabled ||
145      !MSG_IS_NEW(msginfo->flags))
146     return;
147
148   if(notify_config.trayicon_folder_specific) {
149     guint id;
150     GSList *list;
151     gchar *identifier;
152     gboolean found = FALSE;
153
154     if(!(msginfo->folder))
155       return;
156
157     identifier = folder_item_get_identifier(msginfo->folder);
158
159     id =
160       notification_register_folder_specific_list
161       (TRAYICON_SPECIFIC_FOLDER_ID_STR);
162     list = notification_foldercheck_get_list(id);
163     for(; (list != NULL) && !found; list = g_slist_next(list)) {
164       gchar *list_identifier;
165       FolderItem *list_item = (FolderItem*) list->data;
166
167       list_identifier = folder_item_get_identifier(list_item);
168       if(!strcmp2(list_identifier, identifier))
169         found = TRUE;
170
171       g_free(list_identifier);
172     }
173     g_free(identifier);
174
175     if(!found)
176       return;
177   } /* folder specific */
178
179   ftype = msginfo->folder->folder->klass->type;
180
181   G_LOCK(trayicon_popup);
182   /* Check out which type to notify about */
183   switch(ftype) {
184   case F_MH:
185   case F_MBOX:
186   case F_MAILDIR:
187   case F_IMAP:
188     nftype = F_TYPE_MAIL;
189     break;
190   case F_NEWS:
191     nftype = F_TYPE_NEWS;
192     break;
193   case F_UNKNOWN:
194     if((uistr = msginfo->folder->folder->klass->uistr) == NULL) {
195       G_UNLOCK(trayicon_popup);
196       return;
197     }
198     else if(!strcmp(uistr, "vCalendar"))
199       nftype = F_TYPE_CALENDAR;
200     else if(!strcmp(uistr, "RSSyl"))
201       nftype = F_TYPE_RSS;
202     else {
203       debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
204       G_UNLOCK(trayicon_popup);
205       return;
206     }
207     break;
208   default:
209     debug_print("Notification Plugin: Unknown folder type %d\n",ftype);
210     G_UNLOCK(trayicon_popup);
211     return;
212   }
213
214
215   notification_trayicon_popup_add_msg(msginfo, nftype);
216
217   G_UNLOCK(trayicon_popup);
218
219 #endif /* HAVE_LIBNOTIFY */
220 }
221
222 void notification_trayicon_destroy(void)
223 {
224   if(trayicon) {
225     gtk_status_icon_set_visible(trayicon, FALSE);
226     g_object_unref(trayicon);
227     trayicon = NULL;
228   }
229 }
230
231 void notification_update_trayicon()
232 {
233   gchar *buf;
234   static GdkPixbuf *old_icon = NULL;
235   GdkPixbuf *new_icon;
236   gint offset;
237   NotificationMsgCount count;
238   GSList *list;
239
240   if(!notify_config.trayicon_enabled)
241     return;
242
243   if(notify_config.trayicon_folder_specific) {
244     guint id;
245     id =
246       notification_register_folder_specific_list
247       (TRAYICON_SPECIFIC_FOLDER_ID_STR);
248     list = notification_foldercheck_get_list(id);
249   }
250   else
251     list = NULL;
252
253   notification_core_get_msg_count(list, &count);
254
255   if(!trayicon) {
256
257 #ifdef NOTIFICATION_HOTKEYS
258     notification_hotkeys_update_bindings();
259 #endif
260
261     old_icon = notification_trayicon_create();
262     if(!trayicon) {
263       debug_print("Notification plugin: Could not create trayicon\n");
264       return;
265     }
266   }
267
268   /* Tooltip */
269   buf = g_strdup_printf(_("New %d, Unread: %d, Total: %d"),
270                         count.new_msgs, count.unread_msgs,
271                         count.total_msgs);
272   gtk_status_icon_set_tooltip_text(trayicon, buf);
273
274   g_free(buf);
275
276   /* Pixmap */
277   (prefs_common_get_prefs()->work_offline) ? (offset = 1) : (offset = 0);
278
279   if((count.new_msgs > 0) && (count.unreadmarked_msgs > 0))
280     new_icon =
281       notification_pixbuf_get(NOTIFICATION_TRAYICON_NEWMARKEDMAIL+offset);
282   else if(count.new_msgs > 0)
283     new_icon =
284       notification_pixbuf_get(NOTIFICATION_TRAYICON_NEWMAIL+offset);
285   else if(count.unreadmarked_msgs > 0)
286     new_icon =
287       notification_pixbuf_get(NOTIFICATION_TRAYICON_UNREADMARKEDMAIL+offset);
288   else if(count.unread_msgs > 0)
289     new_icon =
290       notification_pixbuf_get(NOTIFICATION_TRAYICON_UNREADMAIL+offset);
291   else
292     new_icon =
293       notification_pixbuf_get(NOTIFICATION_TRAYICON_NOMAIL+offset);
294
295   if(new_icon != old_icon) {
296     gtk_status_icon_set_from_pixbuf(trayicon, new_icon);
297     old_icon = new_icon;
298   }
299 }
300
301 gboolean notification_trayicon_main_window_close(gpointer source, gpointer data)
302 {
303   if(!notify_config.trayicon_enabled)
304     return FALSE;
305
306   if(source) {
307     gboolean *close_allowed = (gboolean*)source;
308
309     if(notify_config.trayicon_close_to_tray) {
310       MainWindow *mainwin = mainwindow_get_mainwindow();
311
312       *close_allowed = FALSE;
313       if(mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window)))
314         main_window_hide(mainwin);
315     }
316   }
317   return FALSE;
318 }
319
320 gboolean notification_trayicon_main_window_got_iconified(gpointer source,
321                                                          gpointer data)
322 {
323   MainWindow *mainwin = mainwindow_get_mainwindow();
324
325   if(!notify_config.trayicon_enabled)
326     return FALSE;
327
328   if(notify_config.trayicon_hide_when_iconified &&
329      mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window))
330      && !gtk_window_get_skip_taskbar_hint(GTK_WINDOW(mainwin->window))) {
331     gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mainwin->window), TRUE);
332   }
333   return FALSE;
334 }
335
336 gboolean notification_trayicon_account_list_changed(gpointer source,
337                                                     gpointer data)
338 {
339   GList *cur_ac;
340         GtkWidget *menu, *submenu;
341   GtkWidget *menuitem;
342   PrefsAccount *ac_prefs;
343
344   GList *account_list = account_get_list();
345
346   if(!notify_config.trayicon_enabled)
347     return FALSE;
348
349         menu = gtk_ui_manager_get_widget(gtkut_ui_manager(), "/Menus/SysTrayiconPopup/EmailAcc");
350         gtk_widget_show(menu);
351
352         gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu), NULL);
353         submenu = gtk_menu_new();
354
355   for(cur_ac = account_list; cur_ac != NULL; cur_ac = cur_ac->next) {
356     ac_prefs = (PrefsAccount *)cur_ac->data;
357
358     menuitem = gtk_menu_item_new_with_label
359       (ac_prefs->account_name ? ac_prefs->account_name
360        : _("Untitled"));
361     gtk_widget_show(menuitem);
362                 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
363     g_signal_connect(G_OBJECT(menuitem), "activate",
364                      G_CALLBACK(trayicon_compose_acc_cb),
365                      ac_prefs);
366   }
367         gtk_widget_show(submenu);
368         gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu), submenu);
369   return FALSE;
370 }
371
372 static GdkPixbuf* notification_trayicon_create(void)
373 {
374   GdkPixbuf *trayicon_nomail;
375         GtkActionGroup *action_group;
376
377   trayicon_nomail = notification_pixbuf_get(NOTIFICATION_TRAYICON_NOMAIL);
378
379   notification_trayicon_destroy();
380
381   trayicon = gtk_status_icon_new_from_pixbuf(trayicon_nomail);
382
383   g_signal_connect(G_OBJECT(trayicon), "activate",
384                    G_CALLBACK(notification_trayicon_on_activate), NULL);
385   g_signal_connect(G_OBJECT(trayicon), "popup-menu",
386                    G_CALLBACK(notification_trayicon_on_popup_menu), NULL);
387   g_signal_connect(G_OBJECT(trayicon), "size-changed",
388                    G_CALLBACK(notification_trayicon_on_size_changed), NULL);
389
390   /* Popup-Menu */
391         action_group = cm_menu_create_action_group("SysTrayiconPopup", trayicon_popup_menu_entries,
392                                                                                                                                                                                  G_N_ELEMENTS(trayicon_popup_menu_entries), NULL);
393         gtk_action_group_add_toggle_actions(action_group, trayicon_popup_toggle_menu_entries,
394                                                                                                                                                         G_N_ELEMENTS(trayicon_popup_toggle_menu_entries), NULL);
395
396         MENUITEM_ADDUI("/Menus", "SysTrayiconPopup", "SysTrayiconPopup", GTK_UI_MANAGER_MENU)
397         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "GetMail", "SysTrayiconPopup/GetMail", GTK_UI_MANAGER_MENUITEM)
398         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator1", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
399         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Email", "SysTrayiconPopup/Email", GTK_UI_MANAGER_MENUITEM)
400         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "EmailAcc", "SysTrayiconPopup/EmailAcc", GTK_UI_MANAGER_MENU)
401         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator2", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
402         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "OpenAB", "SysTrayiconPopup/OpenAB", GTK_UI_MANAGER_MENUITEM)
403         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator3", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
404         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "ToggleOffline", "SysTrayiconPopup/ToggleOffline", GTK_UI_MANAGER_MENUITEM)
405 #ifdef HAVE_LIBNOTIFY
406         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "ShowBubbles", "SysTrayiconPopup/ShowBubbles", GTK_UI_MANAGER_MENUITEM)
407 #endif
408         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Separator4", "SysTrayiconPopup/---", GTK_UI_MANAGER_SEPARATOR)
409         MENUITEM_ADDUI("/Menus/SysTrayiconPopup", "Exit", "SysTrayiconPopup/Exit", GTK_UI_MANAGER_MENUITEM)
410
411         traymenu_popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
412                                 gtk_ui_manager_get_widget(gtkut_ui_manager(), "/Menus/SysTrayiconPopup")));
413
414
415   return trayicon_nomail;
416 }
417
418 void notification_trayicon_on_activate(GtkStatusIcon *status_icon, gpointer user_data)
419 {
420   notification_toggle_hide_show_window();
421 }
422
423 static void notification_trayicon_on_popup_menu(GtkStatusIcon *status_icon,
424                                                 guint button, guint activate_time,
425                                                 gpointer user_data)
426 {
427   MainWindow *mainwin = mainwindow_get_mainwindow();
428
429   if(!mainwin)
430     return;
431
432   /* tell callbacks to skip any event */
433   updating_menu = TRUE;
434   /* initialize checkitems according to current states */
435         cm_toggle_menu_set_active("SysTrayiconPopup/ToggleOffline", prefs_common_get_prefs()->work_offline);
436 #ifdef HAVE_LIBNOTIFY
437         cm_toggle_menu_set_active("SysTrayiconPopup/ShowBubbles", notify_config.trayicon_popup_enabled);
438 #endif
439         cm_menu_set_sensitive("SysTrayiconPopup/GetMail", mainwin->lock_count == 0);
440
441   updating_menu = FALSE;
442
443   gtk_menu_popup(GTK_MENU(traymenu_popup), NULL, NULL, NULL, NULL,
444                  button, activate_time);
445 }
446
447 static gboolean notification_trayicon_on_size_changed(GtkStatusIcon *icon,
448                                                       gint size,
449                                                       gpointer user_data)
450 {
451   notification_update_msg_counts(NULL);
452   return FALSE;
453 }
454
455 /* popup menu callbacks */
456 static void trayicon_get_all_cb(GtkAction *action, gpointer data)
457 {
458   MainWindow *mainwin = mainwindow_get_mainwindow();
459   inc_all_account_mail_cb(mainwin, 0, NULL);
460 }
461
462 static void trayicon_compose_cb(GtkAction *action, gpointer data)
463 {
464   MainWindow *mainwin = mainwindow_get_mainwindow();
465   compose_mail_cb(mainwin, 0, NULL);
466 }
467
468 static void trayicon_compose_acc_cb(GtkMenuItem *menuitem, gpointer data)
469 {
470   compose_new((PrefsAccount *)data, NULL, NULL);
471 }
472
473 static void trayicon_addressbook_cb(GtkAction *action, gpointer data)
474 {
475 #ifndef USE_NEW_ADDRBOOK
476     addressbook_open(NULL);
477 #else
478     GError* error = NULL;
479
480     addressbook_dbus_open(FALSE, &error);
481     if (error) {
482         g_warning("%s", error->message);
483         g_error_free(error);
484     }
485 #endif
486 }
487
488 static void trayicon_toggle_offline_cb(GtkAction *action, gpointer data)
489 {
490   /* toggle offline mode if menu checkitem has been clicked */
491   if(!updating_menu) {
492     MainWindow *mainwin = mainwindow_get_mainwindow();
493     main_window_toggle_work_offline(mainwin, !prefs_common_get_prefs()->work_offline, TRUE);
494   }
495 }
496
497 #ifdef HAVE_LIBNOTIFY
498 static void trayicon_toggle_notify_cb(GtkAction *action, gpointer data)
499 {
500   if(!updating_menu) {
501     notify_config.trayicon_popup_enabled = !notify_config.trayicon_popup_enabled;
502   }
503 }
504 #endif
505
506 static void app_exit_cb(MainWindow *mainwin, guint action, GtkWidget *widget)
507 {
508   if(prefs_common_get_prefs()->confirm_on_exit) {
509     if(alertpanel(_("Exit"), _("Exit Claws Mail?"),
510                   GTK_STOCK_CANCEL, GTK_STOCK_OK,
511                   NULL) != G_ALERTALTERNATE) {
512       return;
513     }
514     manage_window_focus_in(mainwin->window, NULL, NULL);
515   }
516
517   if (prefs_common_get_prefs()->clean_on_exit) {
518     if (!main_window_empty_trash(mainwin, prefs_common_get_prefs()->ask_on_clean, TRUE))
519       return;
520   }
521
522   app_will_exit(NULL, mainwin);
523 }
524
525 static void trayicon_exit_cb(GtkAction *action, gpointer data)
526 {
527   MainWindow *mainwin = mainwindow_get_mainwindow();
528
529   if(mainwin->lock_count == 0) {
530     app_exit_cb(mainwin, 0, NULL);
531   }
532 }
533
534 #ifdef HAVE_LIBNOTIFY
535 static gboolean notification_trayicon_popup_add_msg(MsgInfo *msginfo,
536                                                     NotificationFolderType nftype)
537 {
538   gchar *summary;
539   gchar *utf8_str;
540   gboolean retval;
541   GdkPixbuf *pixbuf;
542
543   g_return_val_if_fail(msginfo, FALSE);
544
545   if(!popup.notification)
546     return notification_trayicon_popup_create(msginfo,nftype);
547
548   /* Count messages */
549   notification_trayicon_popup_count_msgs(nftype);
550
551   if(popup.msg_path) {
552     g_free(popup.msg_path);
553     popup.msg_path = NULL;
554   }
555
556   summary  = notification_trayicon_popup_assemble_summary();
557   utf8_str = notification_trayicon_popup_assemble_body(msginfo);
558
559   /* make sure we show a logo on many msg arrival */
560   pixbuf = notification_pixbuf_get(NOTIFICATION_CM_LOGO_64x64);
561   if(pixbuf)
562     notify_notification_set_icon_from_pixbuf(popup.notification, pixbuf);
563
564   retval = notify_notification_update(popup.notification, summary,
565                                       utf8_str, NULL);
566   g_free(summary);
567   g_free(utf8_str);
568   if(!retval) {
569     debug_print("Notification Plugin: Failed to update notification.\n");
570     return FALSE;
571   }
572   /* Show the popup */
573   notify_notification_set_hint_string(popup.notification, "desktop-entry", "claws-mail");
574   if(!notify_notification_show(popup.notification, &(popup.error))) {
575     debug_print("Notification Plugin: Failed to send updated notification: "
576                 "%s\n", popup.error->message);
577     g_clear_error(&(popup.error));
578     return FALSE;
579   }
580
581   debug_print("Notification Plugin: Popup successfully modified "
582               "with libnotify.\n");
583
584   return TRUE;
585 }
586
587 static gboolean notification_trayicon_popup_create(MsgInfo *msginfo,
588                                                    NotificationFolderType nftype)
589 {
590   gchar *summary = NULL;
591   gchar *utf8_str = NULL;
592   GdkPixbuf *pixbuf;
593   GList *caps = NULL;
594   gboolean support_actions = FALSE;
595
596   /* init libnotify if necessary */
597   if(!notify_is_initted()) {
598     if(!notify_init("claws-mail")) {
599       debug_print("Notification Plugin: Failed to initialize libnotify. "
600                   "No popups will be shown.\n");
601       return FALSE;
602     }
603   }
604
605   /* Count messages */
606   notification_trayicon_popup_count_msgs(nftype);
607
608   summary  = notification_trayicon_popup_assemble_summary();
609   utf8_str = notification_trayicon_popup_assemble_body(msginfo);
610
611 #if NOTIFY_CHECK_VERSION(0, 7, 0)
612   popup.notification = notify_notification_new(summary, utf8_str, NULL);
613 #else
614   popup.notification = notify_notification_new(summary, utf8_str, NULL, NULL);
615   notify_notification_attach_to_status_icon(popup.notification, trayicon);
616 #endif
617
618   g_free(summary);
619   g_free(utf8_str);
620
621   caps = notify_get_server_caps();
622     if(caps != NULL) {
623       GList *c;
624       for(c = caps; c != NULL; c = c->next) {
625         if(strcmp((char*)c->data, "actions") == 0 ) {
626           support_actions = TRUE;
627           break;
628         }
629       }
630
631     g_list_foreach(caps, (GFunc)g_free, NULL);
632     g_list_free(caps);
633   }
634
635   /* Default action */
636   if (support_actions)
637     notify_notification_add_action(popup.notification,
638                                    "default", _("Present main window"),
639                                    (NotifyActionCallback)
640                                    notification_trayicon_popup_default_action_cb,
641                                    GINT_TO_POINTER(nftype),
642                                    notification_trayicon_popup_free_func);
643
644   if(popup.notification == NULL) {
645     debug_print("Notification Plugin: Failed to create a new notification.\n");
646     return FALSE;
647   }
648
649   /* Icon */
650   pixbuf = NULL;
651 #ifndef USE_NEW_ADDRBOOK
652   if(msginfo && msginfo->from) {
653     gchar *icon_path;
654     icon_path = addrindex_get_picture_file(msginfo->from);
655     if(is_file_exist(icon_path)) {
656       GError *error = NULL;
657       gint w, h;
658
659       gdk_pixbuf_get_file_info(icon_path, &w, &h);
660       if((w > 64) || (h > 64))
661         pixbuf = gdk_pixbuf_new_from_file_at_scale(icon_path,
662                                                    64, 64, TRUE, &error);
663       else
664         pixbuf = gdk_pixbuf_new_from_file(icon_path, &error);
665
666       if(!pixbuf) {
667         debug_print("Could not load picture file: %s\n",
668                     error ? error->message : "no details");
669         g_error_free(error);
670       }
671     }
672     else
673       debug_print("Picture path does not exist: %s\n",icon_path);
674     g_free(icon_path);
675   }
676 #endif
677   if(!pixbuf)
678     pixbuf = g_object_ref(notification_pixbuf_get(NOTIFICATION_CM_LOGO_64x64));
679
680   if(pixbuf) {
681     notify_notification_set_icon_from_pixbuf(popup.notification, pixbuf);
682     g_object_unref(pixbuf);
683   }
684   else /* This is not fatal */
685     debug_print("Notification plugin: Icon could not be loaded.\n");
686
687   /* timeout */
688   notify_notification_set_timeout(popup.notification, notify_config.trayicon_popup_timeout);
689
690   /* Category */
691   notify_notification_set_category(popup.notification, "email.arrived");
692
693   /* get notified on bubble close */
694   g_signal_connect(G_OBJECT(popup.notification), "closed", G_CALLBACK(popup_timeout_fun), NULL);
695
696   /* Show the popup */
697   notify_notification_set_hint_string(popup.notification, "desktop-entry", "claws-mail");
698   if(!notify_notification_show(popup.notification, &(popup.error))) {
699     debug_print("Notification Plugin: Failed to send notification: %s\n",
700                 popup.error->message);
701     g_clear_error(&(popup.error));
702     g_object_unref(G_OBJECT(popup.notification));
703     popup.notification = NULL;
704     return FALSE;
705   }
706
707   /* Store path to message */
708   if(nftype == F_TYPE_MAIL) {
709     if(msginfo && msginfo->folder) {
710       gchar *ident;
711       ident = folder_item_get_identifier(msginfo->folder);
712       popup.msg_path = g_strdup_printf("%s%s%u", ident,G_DIR_SEPARATOR_S,
713                                        msginfo->msgnum);
714       g_free(ident);
715     }
716     else
717       popup.msg_path = NULL;
718   }
719
720   debug_print("Notification Plugin: Popup created with libnotify.\n");
721
722   return TRUE;
723 }
724
725 static void popup_timeout_fun(NotifyNotification *nn, gpointer data)
726 {
727   G_LOCK(trayicon_popup);
728
729   g_object_unref(G_OBJECT(popup.notification));
730
731   popup.notification = NULL;
732   g_clear_error(&(popup.error));
733
734   popup.count = 0;
735   popup.num_mail = 0;
736   popup.num_news = 0;
737   popup.num_calendar = 0;
738   popup.num_rss = 0;
739
740   if(popup.msg_path) {
741     g_free(popup.msg_path);
742     popup.msg_path = NULL;
743   }
744
745   G_UNLOCK(trayicon_popup);
746 }
747
748 static void notification_trayicon_popup_free_func(gpointer data)
749 {
750   if(popup.msg_path) {
751     g_free(popup.msg_path);
752     popup.msg_path = NULL;
753   }
754
755   debug_print("Freed notification data\n");
756 }
757
758 static void notification_trayicon_popup_default_action_cb(NotifyNotification
759                                                           *notification,
760                                                           const char *action,
761                                                           void *user_data)
762 {
763   if(strcmp("default", action))
764     return;
765
766   MainWindow *mainwin;
767   mainwin = mainwindow_get_mainwindow();
768   if(mainwin) {
769     NotificationFolderType nftype;
770
771     /* Let mainwindow pop up */
772     notification_show_mainwindow(mainwin);
773     /* If there is only one new mail message, jump to this message */
774     nftype = (NotificationFolderType)GPOINTER_TO_INT(user_data);
775     if((popup.count == 1) && (nftype == F_TYPE_MAIL)) {
776       gchar *select_str;
777       G_LOCK(trayicon_popup);
778       select_str = g_strdup(popup.msg_path);
779       G_UNLOCK(trayicon_popup);
780       debug_print("Notification plugin: Select message %s\n", select_str);
781       mainwindow_jump_to(select_str, FALSE);
782       g_free(select_str);
783     }
784   }
785 }
786
787 static void notification_trayicon_popup_count_msgs(NotificationFolderType nftype)
788 {
789   switch(nftype) {
790   case F_TYPE_MAIL:
791     popup.num_mail++;
792     break;
793   case F_TYPE_NEWS:
794     popup.num_news++;
795     break;
796   case F_TYPE_CALENDAR:
797     popup.num_calendar++;
798     break;
799   case F_TYPE_RSS:
800     popup.num_rss++;
801     break;
802   default:
803     debug_print("Notification plugin: Unknown folder type\n");
804     return;
805   }
806   popup.count++;
807 }
808
809 /* The returned value has to be freed by the caller */
810 static gchar* notification_trayicon_popup_assemble_summary(void)
811 {
812   gchar *summary = NULL;
813
814   if(popup.count == 1) {
815     if(popup.num_mail)
816       summary = g_strdup(_("New mail message"));
817     else if(popup.num_news)
818       summary = g_strdup(_("New news post"));
819     else if(popup.num_calendar)
820       summary = g_strdup(_("New calendar message"));
821     else
822       summary = g_strdup(_("New article in RSS feed"));
823   } /* One new message */
824   else {
825     summary = g_strdup(_("New messages arrived"));
826   } /* Many new messages */
827
828   return summary;
829 }
830
831 /* The returned value has to be freed by the caller */
832 static gchar* notification_trayicon_popup_assemble_body(MsgInfo *msginfo)
833 {
834   gchar *utf8_str;
835
836   if(popup.count == 1) {
837     if(popup.num_mail || popup.num_news) {
838       gchar *from;
839       gchar *subj;
840       gchar *text;
841           gchar *foldname = NULL;
842
843       from = notification_libnotify_sanitize_str(msginfo->from ?
844                                                  msginfo->from :
845                                                  _("(No From)"));
846       subj = notification_libnotify_sanitize_str(msginfo->subject ?
847                                                  msginfo->subject :
848                                                  _("(No Subject)"));
849         if (notify_config.trayicon_display_folder_name) {
850         foldname = notification_libnotify_sanitize_str(msginfo->folder->path);
851         text = g_strconcat(from,"\n\n", subj, "\n\n", foldname, NULL);
852         }
853     else
854         text = g_strconcat(from, "\n\n",subj, NULL);
855
856
857       /* Make sure text is valid UTF8 */
858       utf8_str = notification_validate_utf8_str(text);
859       g_free(text);
860
861       if(from) g_free(from);
862       if(subj) g_free(subj);
863           if(foldname) g_free(foldname);
864     }
865     else if(popup.num_calendar) {
866       utf8_str = g_strdup(_("A new calendar message arrived"));
867     }
868     else {
869       utf8_str = g_strdup(_("A new article in a RSS feed arrived"));
870     }
871   } /* One message */
872
873   else {
874     gchar *msg;
875     gchar *tmp;
876     gboolean str_empty = TRUE;
877
878     utf8_str = g_strdup("");
879
880     if(popup.num_mail) {
881       msg = g_strdup_printf(ngettext("%d new mail message arrived",
882                                      "%d new mail messages arrived",
883                             popup.num_mail),
884                             popup.num_mail);
885       tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
886       g_free(msg);
887       g_free(utf8_str);
888       utf8_str = tmp;
889       str_empty = FALSE;
890     }
891     if(popup.num_news) {
892       msg = g_strdup_printf(ngettext("%d new news post arrived",
893                                      "%d new news posts arrived",
894                             popup.num_news),
895                             popup.num_news);
896       tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
897       g_free(msg);
898       g_free(utf8_str);
899       utf8_str = tmp;
900       str_empty = FALSE;
901     }
902     if(popup.num_calendar) {
903       msg = g_strdup_printf(ngettext("%d new calendar message arrived",
904                                      "%d new calendar messages arrived",
905                             popup.num_calendar),
906                             popup.num_calendar);
907       tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
908       g_free(msg);
909       g_free(utf8_str);
910       utf8_str = tmp;
911       str_empty = FALSE;
912     }
913     if(popup.num_rss) {
914       msg = g_strdup_printf(ngettext("%d new article in RSS feeds arrived",
915                                      "%d new articles in RSS feeds arrived",
916                             popup.num_rss),
917                             popup.num_rss);
918       tmp = g_strdup_printf("%s%s%s",utf8_str,str_empty?"":"\n",msg);
919       g_free(msg);
920       g_free(utf8_str);
921       utf8_str = tmp;
922       str_empty = FALSE;
923     }
924   } /* Many messages */
925
926   return utf8_str;
927 }
928
929 #endif /* HAVE_LIBNOTIFY */
930
931 gboolean notification_trayicon_is_available(void)
932 {
933         gboolean is_available;
934         is_available = FALSE;
935
936         if(trayicon) {
937                 if(gtk_status_icon_is_embedded(trayicon) &&
938                          gtk_status_icon_get_visible(trayicon))
939                         is_available = TRUE;
940         }
941
942         return is_available;
943 }
944
945 #endif /* NOTIFICATION_TRAYICON */