1 /* Notification plugin for Claws-Mail
2 * Copyright (C) 2005-2007 Holger Berndt
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.
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.
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/>.
20 # include "claws-features.h"
24 #include <glib/gi18n.h>
26 #include "common/claws.h"
27 #include "common/version.h"
28 #include "common/utils.h"
29 #include "common/defs.h"
31 #include "common/hooks.h"
33 #include "mainwindow.h"
35 #include "gtk/gtkutils.h"
37 #include "notification_plugin.h"
38 #include "notification_core.h"
39 #include "notification_prefs.h"
40 #include "notification_banner.h"
41 #include "notification_lcdproc.h"
42 #include "notification_trayicon.h"
43 #include "notification_indicator.h"
44 #include "notification_hotkeys.h"
45 #include "notification_foldercheck.h"
46 #include "notification_pixbuf.h"
50 # include <libnotify/notify.h>
54 static gboolean my_folder_item_update_hook(gpointer, gpointer);
55 static gboolean my_folder_update_hook(gpointer, gpointer);
56 static gboolean my_msginfo_update_hook(gpointer, gpointer);
57 static gboolean my_offline_switch_hook(gpointer, gpointer);
58 static gboolean my_main_window_close_hook(gpointer, gpointer);
59 static gboolean my_main_window_got_iconified_hook(gpointer, gpointer);
60 static gboolean my_account_list_changed_hook(gpointer, gpointer);
61 static gboolean my_update_theme_hook(gpointer, gpointer);
63 #ifdef NOTIFICATION_TRAYICON
64 static gboolean trayicon_startup_idle(gpointer);
67 static gulong hook_f_item;
69 static gulong hook_m_info;
70 static gulong hook_offline;
71 static gulong hook_mw_close;
72 static gulong hook_got_iconified;
73 static gulong hook_account;
74 static gulong hook_theme_changed;
76 #ifdef NOTIFICATION_BANNER
77 static GSList* banner_collected_msgs;
80 void notification_update_urgency_hint(void)
83 mainwin = mainwindow_get_mainwindow();
85 NotificationMsgCount count;
88 if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread) {
89 notification_core_get_msg_count(NULL, &count);
90 if(notify_config.urgency_hint_new)
91 active = (active || (count.new_msgs > 0));
92 if(notify_config.urgency_hint_unread)
93 active = (active || (count.unread_msgs > 0));
95 gtk_window_set_urgency_hint(GTK_WINDOW(mainwin->window), active);
99 static gboolean my_account_list_changed_hook(gpointer source,
102 gboolean retVal = FALSE;
104 #ifdef NOTIFICATION_TRAYICON
105 notification_update_msg_counts(NULL);
106 retVal = notification_trayicon_account_list_changed(source, data);
112 static gboolean my_update_theme_hook(gpointer source, gpointer data)
114 notification_pixbuf_free_all();
115 #ifdef NOTIFICATION_TRAYICON
116 notification_update_trayicon();
121 static gboolean my_main_window_got_iconified_hook(gpointer source,
124 gboolean retVal = FALSE;
125 #ifdef NOTIFICATION_TRAYICON
126 notification_update_msg_counts(NULL);
127 retVal = notification_trayicon_main_window_got_iconified(source, data);
132 static gboolean my_main_window_close_hook(gpointer source, gpointer data)
134 gboolean retVal = FALSE;
135 #ifdef NOTIFICATION_TRAYICON
136 notification_update_msg_counts(NULL);
137 retVal = notification_trayicon_main_window_close(source, data);
142 static gboolean my_offline_switch_hook(gpointer source, gpointer data)
144 #ifdef NOTIFICATION_TRAYICON
145 notification_update_msg_counts(NULL);
150 static gboolean my_folder_item_update_hook(gpointer source, gpointer data)
152 FolderItemUpdateData *update_data = source;
156 g_return_val_if_fail(source != NULL, FALSE);
158 if (folder_has_parent_of_type(update_data->item, F_DRAFT))
161 #if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON) || defined(NOTIFICATION_INDICATOR)
162 notification_update_msg_counts(NULL);
164 if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread)
165 notification_update_msg_counts(NULL);
168 /* Check if the folder types is to be notified about */
169 ftype = update_data->item->folder->klass->type;
170 uistr = update_data->item->folder->klass->uistr;
171 if(!notify_include_folder_type(ftype, uistr))
174 if(update_data->update_flags & F_ITEM_UPDATE_MSGCNT) {
175 #ifdef NOTIFICATION_BANNER
176 notification_update_banner();
178 #if defined(NOTIFICATION_POPUP) || defined(NOTIFICATION_COMMAND)
179 notification_new_unnotified_msgs(update_data);
185 static gboolean my_folder_update_hook(gpointer source, gpointer data)
187 FolderUpdateData *hookdata;
189 g_return_val_if_fail(source != NULL, FALSE);
192 #if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON)
193 if(hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM)
194 notification_update_msg_counts(hookdata->item);
196 notification_update_msg_counts(NULL);
204 static gboolean my_msginfo_update_hook(gpointer source, gpointer data)
206 return notification_notified_hash_msginfo_update((MsgInfoUpdate*)source);
209 gint plugin_init(gchar **error)
214 /* No be able to test against new-contacts */
215 if(!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
216 VERSION_NUMERIC, _("Notification"), error))
219 /* Check if threading is enabled */
220 if(!g_thread_supported()) {
221 *error = g_strdup(_("The Notification plugin needs threading support."));
225 hook_f_item = hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST,
226 my_folder_item_update_hook, NULL);
227 if(hook_f_item == 0) {
228 *error = g_strdup(_("Failed to register folder item update hook in the "
229 "Notification plugin"));
233 hook_f = hooks_register_hook(FOLDER_UPDATE_HOOKLIST,
234 my_folder_update_hook, NULL);
236 *error = g_strdup(_("Failed to register folder update hook in the "
237 "Notification plugin"));
238 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
243 hook_m_info = hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
244 my_msginfo_update_hook, NULL);
245 if(hook_m_info == 0) {
246 *error = g_strdup(_("Failed to register msginfo update hook in the "
247 "Notification plugin"));
248 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
249 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
253 hook_offline = hooks_register_hook(OFFLINE_SWITCH_HOOKLIST,
254 my_offline_switch_hook, NULL);
255 if(hook_offline == 0) {
256 *error = g_strdup(_("Failed to register offline switch hook in the "
257 "Notification plugin"));
258 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
259 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
260 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
264 hook_mw_close = hooks_register_hook(MAIN_WINDOW_CLOSE,
265 my_main_window_close_hook, NULL);
266 if(hook_mw_close == 0) {
267 *error = g_strdup(_("Failed to register main window close hook in the "
268 "Notification plugin"));
269 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
270 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
271 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
272 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
276 hook_got_iconified = hooks_register_hook(MAIN_WINDOW_GOT_ICONIFIED,
277 my_main_window_got_iconified_hook,
279 if(hook_got_iconified == 0) {
280 *error = g_strdup(_("Failed to register got iconified hook in the "
281 "Notification plugin"));
282 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
283 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
284 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
285 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
286 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
290 hook_account = hooks_register_hook(ACCOUNT_LIST_CHANGED_HOOKLIST,
291 my_account_list_changed_hook, NULL);
292 if (hook_account == 0) {
293 *error = g_strdup(_("Failed to register account list changed hook in the "
294 "Notification plugin"));
295 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
296 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
297 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
298 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
299 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
300 hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
304 hook_theme_changed = hooks_register_hook(THEME_CHANGED_HOOKLIST, my_update_theme_hook, NULL);
305 if(hook_theme_changed == 0) {
306 *error = g_strdup(_("Failed to register theme change hook in the "
307 "Notification plugin"));
308 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
309 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
310 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
311 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
312 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
313 hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
314 hooks_unregister_hook(ACCOUNT_LIST_CHANGED_HOOKLIST, hook_account);
319 prefs_set_default(notify_param);
320 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
321 prefs_read_config(notify_param, "NotificationPlugin", rcpath, NULL);
324 /* Folder specific stuff */
325 notification_foldercheck_read_array();
327 notification_notified_hash_startup_init();
331 #ifdef NOTIFICATION_INDICATOR
332 notification_indicator_setup();
334 #ifdef NOTIFICATION_BANNER
335 notification_update_banner();
337 #ifdef NOTIFICATION_LCDPROC
338 notification_lcdproc_connect();
340 #ifdef NOTIFICATION_TRAYICON
341 if(notify_config.trayicon_enabled &&
342 notify_config.trayicon_hide_at_startup && claws_is_starting()) {
343 MainWindow *mainwin = mainwindow_get_mainwindow();
345 g_idle_add(trayicon_startup_idle,NULL);
346 if(mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window)))
347 main_window_hide(mainwin);
348 main_set_show_at_startup(FALSE);
351 my_account_list_changed_hook(NULL,NULL);
353 if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread)
354 notification_update_msg_counts(NULL);
356 #ifdef NOTIFICATION_HOTKEYS
357 notification_hotkeys_update_bindings();
360 debug_print("Notification plugin loaded\n");
365 gboolean plugin_done(void)
367 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
368 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
369 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
370 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
371 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
372 hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
373 hooks_unregister_hook(ACCOUNT_LIST_CHANGED_HOOKLIST, hook_account);
374 hooks_unregister_hook(THEME_CHANGED_HOOKLIST, hook_theme_changed);
376 notify_save_config();
380 /* foldercheck cleanup */
381 notification_foldercheck_write_array();
382 notification_free_folder_specific_array();
384 #ifdef NOTIFICATION_BANNER
385 notification_collected_msgs_free(banner_collected_msgs);
386 banner_collected_msgs = NULL;
387 notification_banner_destroy();
389 #ifdef NOTIFICATION_LCDPROC
390 notification_lcdproc_disconnect();
392 #ifdef NOTIFICATION_TRAYICON
393 notification_trayicon_destroy();
395 #ifdef NOTIFICATION_INDICATOR
396 notification_indicator_destroy();
398 notification_core_free();
400 #ifdef HAVE_LIBNOTIFY
401 if(notify_is_initted())
405 #ifdef NOTIFICATION_HOTKEYS
406 notification_hotkeys_unbind_all();
409 notification_pixbuf_free_all();
411 debug_print("Notification plugin unloaded\n");
413 /* Returning FALSE here means that g_module_close() will not be called on the plugin.
414 * This is necessary, as needed libraries are not designed to be unloaded. */
418 const gchar *plugin_name(void)
420 return _("Notification");
423 const gchar *plugin_desc(void)
425 return _("This plugin provides various ways "
426 "to notify the user of new and unread email.\n"
427 "The plugin is extensively configurable in the "
428 "plugins section of the preferences dialog.\n\n"
429 "Feedback to <berndth@gmx.de> is welcome.");
432 const gchar *plugin_type(void)
437 const gchar *plugin_licence(void)
442 const gchar *plugin_version(void)
447 struct PluginFeature *plugin_provides(void)
449 static struct PluginFeature features[] =
450 { {PLUGIN_NOTIFIER, N_("Various tools")},
451 {PLUGIN_NOTHING, NULL}};
455 #ifdef NOTIFICATION_BANNER
456 void notification_update_banner(void)
458 notification_collected_msgs_free(banner_collected_msgs);
459 banner_collected_msgs = NULL;
461 if(notify_config.banner_show != NOTIFY_BANNER_SHOW_NEVER) {
463 GSList *folder_list = NULL;
465 if(notify_config.banner_folder_specific) {
466 id = notification_register_folder_specific_list
467 (BANNER_SPECIFIC_FOLDER_ID_STR);
468 folder_list = notification_foldercheck_get_list(id);
471 if(!(notify_config.banner_folder_specific && (folder_list == NULL)))
472 banner_collected_msgs =
473 notification_collect_msgs(notify_config.banner_include_unread,
474 notify_config.banner_folder_specific ?
475 folder_list : NULL, notify_config.banner_max_msgs);
478 notification_banner_show(banner_collected_msgs);
482 #ifdef NOTIFICATION_TRAYICON
483 static gboolean trayicon_startup_idle(gpointer data)
485 /* if the trayicon is not available,
486 simulate click on it to show mainwindow */
487 if(!notification_trayicon_is_available())
488 notification_trayicon_on_activate(NULL,data);