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 guint hook_f_item;
69 static guint hook_m_info;
70 static guint hook_offline;
71 static guint hook_mw_close;
72 static guint hook_got_iconified;
73 static guint hook_account;
74 static guint 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 defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON) || defined(NOTIFICATION_INDICATOR)
159 notification_update_msg_counts(NULL);
161 if(notify_config.urgency_hint)
162 notification_update_msg_counts(NULL);
165 /* Check if the folder types is to be notified about */
166 ftype = update_data->item->folder->klass->type;
167 uistr = update_data->item->folder->klass->uistr;
168 if(!notify_include_folder_type(ftype, uistr))
171 if(update_data->update_flags & F_ITEM_UPDATE_MSGCNT) {
172 #ifdef NOTIFICATION_BANNER
173 notification_update_banner();
175 #if defined(NOTIFICATION_POPUP) || defined(NOTIFICATION_COMMAND)
176 notification_new_unnotified_msgs(update_data);
182 static gboolean my_folder_update_hook(gpointer source, gpointer data)
184 FolderUpdateData *hookdata;
186 g_return_val_if_fail(source != NULL, FALSE);
189 #if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON)
190 if(hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM)
191 notification_update_msg_counts(hookdata->item);
193 notification_update_msg_counts(NULL);
201 static gboolean my_msginfo_update_hook(gpointer source, gpointer data)
203 return notification_notified_hash_msginfo_update((MsgInfoUpdate*)source);
206 gint plugin_init(gchar **error)
211 /* No be able to test against new-contacts */
212 if(!check_plugin_version(MAKE_NUMERIC_VERSION(3,8,1,46),
213 VERSION_NUMERIC, _("Notification"), error))
216 /* Check if threading is enabled */
217 if(!g_thread_supported()) {
218 *error = g_strdup(_("The Notification plugin needs threading support."));
222 hook_f_item = hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST,
223 my_folder_item_update_hook, NULL);
224 if(hook_f_item == (guint) -1) {
225 *error = g_strdup(_("Failed to register folder item update hook in the "
226 "Notification plugin"));
230 hook_f = hooks_register_hook(FOLDER_UPDATE_HOOKLIST,
231 my_folder_update_hook, NULL);
232 if(hook_f == (guint) -1) {
233 *error = g_strdup(_("Failed to register folder update hook in the "
234 "Notification plugin"));
235 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
240 hook_m_info = hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
241 my_msginfo_update_hook, NULL);
242 if(hook_m_info == (guint) -1) {
243 *error = g_strdup(_("Failed to register msginfo update hook in the "
244 "Notification plugin"));
245 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
246 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
250 hook_offline = hooks_register_hook(OFFLINE_SWITCH_HOOKLIST,
251 my_offline_switch_hook, NULL);
252 if(hook_offline == (guint) -1) {
253 *error = g_strdup(_("Failed to register offline switch hook in the "
254 "Notification plugin"));
255 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
256 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
257 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
261 hook_mw_close = hooks_register_hook(MAIN_WINDOW_CLOSE,
262 my_main_window_close_hook, NULL);
263 if(hook_mw_close == (guint) -1) {
264 *error = g_strdup(_("Failed to register main window close hook in the "
265 "Notification plugin"));
266 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
267 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
268 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
269 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
273 hook_got_iconified = hooks_register_hook(MAIN_WINDOW_GOT_ICONIFIED,
274 my_main_window_got_iconified_hook,
276 if(hook_got_iconified == (guint) -1) {
277 *error = g_strdup(_("Failed to register got iconified hook in the "
278 "Notification plugin"));
279 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
280 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
281 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
282 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
283 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
287 hook_account = hooks_register_hook(ACCOUNT_LIST_CHANGED_HOOKLIST,
288 my_account_list_changed_hook, NULL);
289 if (hook_account == (guint) -1) {
290 *error = g_strdup(_("Failed to register account list changed hook in the "
291 "Notification plugin"));
292 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
293 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
294 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
295 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
296 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
297 hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
301 hook_theme_changed = hooks_register_hook(THEME_CHANGED_HOOKLIST, my_update_theme_hook, NULL);
302 if(hook_theme_changed == (guint)-1) {
303 *error = g_strdup(_("Failed to register theme change hook int the "
304 "Notification plugin"));
305 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
306 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
307 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
308 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
309 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
310 hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
311 hooks_unregister_hook(ACCOUNT_LIST_CHANGED_HOOKLIST, hook_account);
316 prefs_set_default(notify_param);
317 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
318 prefs_read_config(notify_param, "NotificationPlugin", rcpath, NULL);
321 /* Folder specific stuff */
322 notification_foldercheck_read_array();
324 notification_notified_hash_startup_init();
328 #ifdef NOTIFICATION_BANNER
329 notification_update_banner();
331 #ifdef NOTIFICATION_LCDPROC
332 notification_lcdproc_connect();
334 #ifdef NOTIFICATION_TRAYICON
335 if(notify_config.trayicon_enabled &&
336 notify_config.trayicon_hide_at_startup && claws_is_starting()) {
337 MainWindow *mainwin = mainwindow_get_mainwindow();
339 g_idle_add(trayicon_startup_idle,NULL);
340 if(mainwin && gtk_widget_get_visible(GTK_WIDGET(mainwin->window)))
341 main_window_hide(mainwin);
342 main_set_show_at_startup(FALSE);
345 my_account_list_changed_hook(NULL,NULL);
347 if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread)
348 notification_update_msg_counts(NULL);
350 #ifdef NOTIFICATION_HOTKEYS
351 notification_hotkeys_update_bindings();
354 debug_print("Notification plugin loaded\n");
359 gboolean plugin_done(void)
361 hooks_unregister_hook(FOLDER_ITEM_UPDATE_HOOKLIST, hook_f_item);
362 hooks_unregister_hook(FOLDER_UPDATE_HOOKLIST, hook_f);
363 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, hook_m_info);
364 hooks_unregister_hook(OFFLINE_SWITCH_HOOKLIST, hook_offline);
365 hooks_unregister_hook(MAIN_WINDOW_CLOSE, hook_mw_close);
366 hooks_unregister_hook(MAIN_WINDOW_GOT_ICONIFIED, hook_got_iconified);
367 hooks_unregister_hook(ACCOUNT_LIST_CHANGED_HOOKLIST, hook_account);
368 hooks_unregister_hook(THEME_CHANGED_HOOKLIST, hook_theme_changed);
370 notify_save_config();
374 /* foldercheck cleanup */
375 notification_foldercheck_write_array();
376 notification_free_folder_specific_array();
378 #ifdef NOTIFICATION_BANNER
379 notification_collected_msgs_free(banner_collected_msgs);
380 banner_collected_msgs = NULL;
381 notification_banner_destroy();
383 #ifdef NOTIFICATION_LCDPROC
384 notification_lcdproc_disconnect();
386 #ifdef NOTIFICATION_TRAYICON
387 notification_trayicon_destroy();
389 #ifdef NOTIFICATION_INDICATOR
390 notification_indicator_destroy();
392 notification_core_free();
394 #ifdef HAVE_LIBNOTIFY
395 if(notify_is_initted())
399 #ifdef NOTIFICATION_HOTKEYS
400 notification_hotkeys_unbind_all();
403 notification_pixbuf_free_all();
405 debug_print("Notification plugin unloaded\n");
407 /* Returning FALSE here means that g_module_close() will not be called on the plugin.
408 * This is necessary, as needed libraries are not designed to be unloaded. */
412 const gchar *plugin_name(void)
414 return _("Notification");
417 const gchar *plugin_desc(void)
419 return _("This plugin provides various ways "
420 "to notify the user of new and unread email.\n"
421 "The plugin is extensively configurable in the "
422 "plugins section of the preferences dialog.\n\n"
423 "Feedback to <berndth@gmx.de> is welcome.");
426 const gchar *plugin_type(void)
431 const gchar *plugin_licence(void)
436 const gchar *plugin_version(void)
441 struct PluginFeature *plugin_provides(void)
443 static struct PluginFeature features[] =
444 { {PLUGIN_NOTIFIER, N_("Various tools")},
445 {PLUGIN_NOTHING, NULL}};
449 #ifdef NOTIFICATION_BANNER
450 void notification_update_banner(void)
452 notification_collected_msgs_free(banner_collected_msgs);
453 banner_collected_msgs = NULL;
455 if(notify_config.banner_show != NOTIFY_BANNER_SHOW_NEVER) {
457 GSList *folder_list = NULL;
459 if(notify_config.banner_folder_specific) {
460 id = notification_register_folder_specific_list
461 (BANNER_SPECIFIC_FOLDER_ID_STR);
462 folder_list = notification_foldercheck_get_list(id);
465 if(!(notify_config.banner_folder_specific && (folder_list == NULL)))
466 banner_collected_msgs =
467 notification_collect_msgs(notify_config.banner_include_unread,
468 notify_config.banner_folder_specific ?
469 folder_list : NULL, notify_config.banner_max_msgs);
472 notification_banner_show(banner_collected_msgs);
476 #ifdef NOTIFICATION_TRAYICON
477 static gboolean trayicon_startup_idle(gpointer data)
479 /* if the trayicon is not available,
480 simulate click on it to show mainwindow */
481 if(!notification_trayicon_is_available())
482 notification_trayicon_on_activate(NULL,data);