diff --git a/AUTHORS b/AUTHORS index dff6a207b..f2e3d0f1a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -353,3 +353,4 @@ contributors (in addition to the above; based on Changelog) Paul Wolneykien Quentin Rameau MatN + Jan Willamowius diff --git a/configure.ac b/configure.ac index 2e2c7bbe2..e4823e0c4 100644 --- a/configure.ac +++ b/configure.ac @@ -1213,7 +1213,7 @@ dnl Fancy: Webkit, curl, optionally libsoup-gnome dnl Litehtml a C++ compiler, glib, cairo, fontconfig, gumbo, curl dnl Libravatar: libcurl dnl Notification: optionally libnotify unity/messaging-menu -dnl libcanberra_gtk3 hotkey +dnl libcanberra_gtk3 hotkey libayatana-appindicator3 dnl Pdf-Viewer: libpoppler dnl Perl: sed perl dnl PGP/Core: libgpgme @@ -1420,6 +1420,14 @@ fi AC_SUBST(unity_CFLAGS) AC_SUBST(unity_LIBS) +dnl ayatana app indicator ******************************************************* +PKG_CHECK_MODULES(ayatanaappindicator, ayatana-appindicator3-0.1, HAVE_AYATANAAPPINDICATOR=yes, HAVE_AYATANAAPPINDICATOR=no) +if test x"$HAVE_AYATANAAPPINDICATOR" = xyes; then + AC_DEFINE(NOTIFICATION_AYATANA_INDICATOR, 1, [Activate support for Atayana app indicator]) +fi +AC_SUBST(ayatanaappindicator_CFLAGS) +AC_SUBST(ayatanaappindicator_LIBS) + dnl hotkeys ******************************************************************** PKG_CHECK_MODULES(CM_NP_HOTKEY, [gio-2.0 >= 2.15.6 gio-unix-2.0 >= 2.15.6], HAVE_HOTKEYS=yes, HAVE_HOTKEYS=no) if test x"$HAVE_HOTKEYS" = xyes; then @@ -1739,6 +1747,11 @@ if test x"$enable_notification_plugin" != xno; then else notification_missing_dependencies="$notification_missing_dependencies unity/messaging-menu" fi + if test x"$HAVE_AYATANAAPPINDICATOR" = xyes; then + notification_features="$notification_features libayatana-appindicator3" + else + notification_missing_dependencies="$notification_missing_dependencies libayatana-appindicator3" + fi if test x"$HAVE_LIBNOTIFY" = xyes; then notification_features="$notification_features libnotify" else diff --git a/po/POTFILES.in b/po/POTFILES.in index a05b546d7..73154dbd2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -126,6 +126,7 @@ src/plugins/managesieve/sieve_manager.c src/plugins/managesieve/sieve_plugin.c src/plugins/managesieve/sieve_prefs.c src/plugins/newmail/newmail.c +src/plugins/notification/notification_ayatana_indicator.c src/plugins/notification/notification_banner.c src/plugins/notification/notification_foldercheck.c src/plugins/notification/notification_lcdproc.c diff --git a/src/gtk/authors.h b/src/gtk/authors.h index 37724d989..a9fa182aa 100644 --- a/src/gtk/authors.h +++ b/src/gtk/authors.h @@ -336,6 +336,7 @@ static char *CONTRIBS_LIST[] = { "Rafal Weglarz", "Florian Weimer", "Martin Wicke", +"Jan Willamowius", "Paul Wolneykien", "Bob Woodside", "YAMAGUCHI", diff --git a/src/plugins/notification/Makefile.am b/src/plugins/notification/Makefile.am index 093feb478..cba485fef 100644 --- a/src/plugins/notification/Makefile.am +++ b/src/plugins/notification/Makefile.am @@ -1,4 +1,4 @@ -# Copyright 1999-2022 the Claws Mail team. +# Copyright 1999-2024 the Claws Mail team. # This file is part of Claws Mail package, and distributed under the # terms of the General Public License version 3 (or later). # See COPYING file for license details. @@ -40,6 +40,7 @@ notification_la_LIBADD = $(plugin_libadd) \ $(libnotify_LIBS) \ $(unity_LIBS) \ $(libcanberra_gtk3_LIBS) \ + $(ayatanaappindicator_LIBS) \ $(hotkey_lib_path) notification_la_CPPFLAGS = \ @@ -48,12 +49,15 @@ notification_la_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(GTK_CFLAGS) \ $(ENCHANT_CFLAGS) \ + $(ayatanaappindicator_CFLAGS) \ $(libnotify_CFLAGS) \ $(unity_CFLAGS) \ $(libcanberra_gtk3_CFLAGS) \ -Wall notification_la_SOURCES = \ + notification_ayatana_indicator.c \ + notification_ayatana_indicator.h \ notification_banner.c \ notification_banner.h \ notification_command.c \ diff --git a/src/plugins/notification/notification_ayatana_indicator.c b/src/plugins/notification/notification_ayatana_indicator.c new file mode 100644 index 000000000..d50c9bf44 --- /dev/null +++ b/src/plugins/notification/notification_ayatana_indicator.c @@ -0,0 +1,97 @@ +/* Notification plugin for Claws Mail + * Copyright (C) 2005-2024 Holger Berndt, Jan Willamowius and the Claws Mail Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +# include "claws-features.h" +#endif + +#include +#include + +#ifdef NOTIFICATION_AYATANA_INDICATOR + +#include "notification_indicator.h" +#include "notification_prefs.h" +#include "notification_core.h" + +//#include "folder.h" +#include "common/utils.h" + +#include "libayatana-appindicator/app-indicator.h" + +static AppIndicator *ayatana_indicator = NULL; +static GtkWidget *status = NULL; + +void notification_ayatana_indicator_enable(void) +{ + if(!notify_config.ayatana_indicator_enabled) + return; + + if (!ayatana_indicator) { + ayatana_indicator = app_indicator_new ("claws-mail", "mail-read-symbolic", APP_INDICATOR_CATEGORY_COMMUNICATIONS); + app_indicator_set_attention_icon_full(ayatana_indicator, "mail-read-symbolic", ""); + + // MUST have menu, otherwise indicator won't show up + GtkWidget *menu = gtk_menu_new (); + status = gtk_menu_item_new_with_label (""); /* filled later */ + g_signal_connect(G_OBJECT(status), "activate", G_CALLBACK(notification_toggle_hide_show_window), NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), status); + gtk_widget_show (status); + GtkWidget *quit = gtk_menu_item_new_with_label (_("Quit Claws Mail")); + g_signal_connect (quit, "activate", G_CALLBACK (gtk_main_quit), ayatana_indicator); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), quit); + gtk_widget_show (quit); + app_indicator_set_menu (ayatana_indicator, GTK_MENU (menu)); + } + app_indicator_set_status (ayatana_indicator, APP_INDICATOR_STATUS_ACTIVE); +} + +void notification_ayatana_indicator_disable(void) +{ + if (ayatana_indicator) { + // hide the indicator, don't destroy it, so it can be activated again later + app_indicator_set_status (ayatana_indicator, APP_INDICATOR_STATUS_PASSIVE); + } +} + +void notification_update_ayatana_indicator(void) +{ + NotificationMsgCount count; + GSList *list = NULL; + + if(!notify_config.ayatana_indicator_enabled || !ayatana_indicator) + return; + + notification_core_get_msg_count(list, &count); + + gchar * buf = g_strdup_printf(_("New %d, Unread: %d, Total: %d"), + count.new_msgs, count.unread_msgs, + count.total_msgs); + + gtk_menu_item_set_label(GTK_MENU_ITEM(status), buf); + if (count.new_msgs > 0) { + app_indicator_set_icon_full(ayatana_indicator, "indicator-messages-new", ""); + } else if (count.unread_msgs > 0) { + app_indicator_set_icon_full(ayatana_indicator, "mail-unread-symbolic", ""); + } else { + app_indicator_set_icon_full(ayatana_indicator, "mail-read-symbolic", ""); + } + g_free(buf); +} + +#endif /* NOTIFICATION_AYATANA_INDICATOR */ diff --git a/src/plugins/notification/notification_ayatana_indicator.h b/src/plugins/notification/notification_ayatana_indicator.h new file mode 100644 index 000000000..0fe722376 --- /dev/null +++ b/src/plugins/notification/notification_ayatana_indicator.h @@ -0,0 +1,34 @@ +/* Notification plugin for Claws Mail + * Copyright (C) 2005-2024 Holger Berndt, Jan Willamowius and the Claws Mail Team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NOTIFICATION_AYATANA_INDICATOR_H +#define NOTIFICATION_AYATANA_INDICATOR_H NOTIFICATION_AYATANA_INDICATOR_H + +#ifdef HAVE_CONFIG_H +# include "claws-features.h" +#endif + +#ifdef NOTIFICATION_AYATANA_INDICATOR + +#include + +void notification_update_ayatana_indicator(void); +void notification_ayatana_indicator_enable(void); +void notification_ayatana_indicator_disable(void); + +#endif /* NOTIFICATION_AYATANA_INDICATOR */ +#endif /* NOTIFICATION_AYATANA_INDICATOR_H */ diff --git a/src/plugins/notification/notification_core.c b/src/plugins/notification/notification_core.c index 3751fd366..5e28d0e35 100644 --- a/src/plugins/notification/notification_core.c +++ b/src/plugins/notification/notification_core.c @@ -38,6 +38,9 @@ #ifdef HAVE_LIBCANBERRA_GTK # include #endif +#ifdef NOTIFICATION_AYATANA_INDICATOR +# include "notification_ayatana_indicator.h" +#endif typedef struct { GSList *collected_msgs; @@ -125,6 +128,9 @@ void notification_update_msg_counts(FolderItem *removed_item) #ifdef NOTIFICATION_TRAYICON notification_update_trayicon(); #endif +#ifdef NOTIFICATION_AYATANA_INDICATOR + notification_update_ayatana_indicator(); +#endif #ifdef NOTIFICATION_INDICATOR notification_update_indicator(); #endif diff --git a/src/plugins/notification/notification_plugin.c b/src/plugins/notification/notification_plugin.c index d946a2eca..9b883cce9 100644 --- a/src/plugins/notification/notification_plugin.c +++ b/src/plugins/notification/notification_plugin.c @@ -37,6 +37,7 @@ #include "notification_plugin.h" #include "notification_core.h" #include "notification_prefs.h" +#include "notification_ayatana_indicator.h" #include "notification_banner.h" #include "notification_lcdproc.h" #include "notification_trayicon.h" @@ -162,7 +163,7 @@ static gboolean my_folder_item_update_hook(gpointer source, gpointer data) if (folder_has_parent_of_type(update_data->item, F_DRAFT)) return FALSE; -#if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON) || defined(NOTIFICATION_INDICATOR) +#if defined(NOTIFICATION_LCDPROC) || defined(NOTIFICATION_TRAYICON) || defined(NOTIFICATION_AYATANA_INDICATOR) || defined(NOTIFICATION_INDICATOR) notification_update_msg_counts(NULL); #else if(notify_config.urgency_hint_new || notify_config.urgency_hint_unread) @@ -326,6 +327,9 @@ gint plugin_init(gchar **error) notify_gtk_init(); +#ifdef NOTIFICATION_AYATANA_INDICATOR + notification_ayatana_indicator_enable(); +#endif #ifdef NOTIFICATION_INDICATOR notification_indicator_setup(); #endif @@ -379,6 +383,9 @@ gboolean plugin_done(void) notification_foldercheck_write_array(); notification_free_folder_specific_array(); +#ifdef NOTIFICATION_AYATANA_INDICATOR + notification_ayatana_indicator_disable(); +#endif #ifdef NOTIFICATION_BANNER notification_collected_msgs_free(banner_collected_msgs); banner_collected_msgs = NULL; diff --git a/src/plugins/notification/notification_prefs.c b/src/plugins/notification/notification_prefs.c index 172a41bed..6133a4cf0 100644 --- a/src/plugins/notification/notification_prefs.c +++ b/src/plugins/notification/notification_prefs.c @@ -43,6 +43,7 @@ #include "notification_command.h" #include "notification_lcdproc.h" #include "notification_trayicon.h" +#include "notification_ayatana_indicator.h" #include "notification_indicator.h" #ifdef GDK_WINDOWING_X11 @@ -165,6 +166,14 @@ typedef struct { NotifyTrayiconPage trayicon_page; #endif +#ifdef NOTIFICATION_AYATANA_INDICATOR +typedef struct { + PrefsPage page; + GtkWidget *ayatana_indicator_enabled; +}NotifyAtayanaIndicatorPage; +NotifyAtayanaIndicatorPage ayatana_indicator_page; +#endif + #ifdef NOTIFICATION_INDICATOR typedef struct { PrefsPage page; @@ -307,6 +316,10 @@ PrefParam #endif /* HAVE_LIBNOTIFY */ #endif +#ifdef NOTIFICATION_AYATANA_INDICATOR + { "ayatana_indicator_enabled", "FALSE", ¬ify_config.ayatana_indicator_enabled, P_BOOL, + NULL, NULL, NULL}, +#endif /* NOTIFICATION_AYATANA_INDICATOR */ #ifdef NOTIFICATION_INDICATOR { "indicator_enabled", "FALSE", ¬ify_config.indicator_enabled, P_BOOL, NULL, NULL, NULL}, @@ -379,6 +392,12 @@ static void notify_trayicon_popup_enable_set_sensitivity(GtkToggleButton*, #endif #endif +#ifdef NOTIFICATION_AYATANA_INDICATOR +static void notify_create_ayatana_indicator_page(PrefsPage*, GtkWindow*, gpointer); +static void notify_destroy_ayatana_indicator_page(PrefsPage*); +static void notify_save_ayatana_indicator(PrefsPage*); +#endif /* NOTIFICATION_AYATANA_INDICATOR */ + #ifdef NOTIFICATION_INDICATOR static void notify_create_indicator_page(PrefsPage*, GtkWindow*, gpointer); static void notify_destroy_indicator_page(PrefsPage*); @@ -519,6 +538,24 @@ void notify_gtk_init(void) } #endif /* NOTIFICATION_TRAYICON */ +#ifdef NOTIFICATION_AYATANA_INDICATOR + { + static gchar *ayatana_indicator_path[4]; + + ayatana_indicator_path[0] = _("Plugins"); + ayatana_indicator_path[1] = _("Notification"); + ayatana_indicator_path[2] = _("Atayana App Indicator"); + ayatana_indicator_path[3] = NULL; + + ayatana_indicator_page.page.path = ayatana_indicator_path; + ayatana_indicator_page.page.create_widget = notify_create_ayatana_indicator_page; + ayatana_indicator_page.page.destroy_widget = notify_destroy_ayatana_indicator_page; + ayatana_indicator_page.page.save_page = notify_save_ayatana_indicator; + ayatana_indicator_page.page.weight = 70.0; + prefs_gtk_register_page((PrefsPage*) &ayatana_indicator_page); + } +#endif /* NOTIFICATION_AYATANA_INDICATOR */ + #ifdef NOTIFICATION_INDICATOR { static gchar *indicator_path[4]; @@ -558,6 +595,9 @@ void notify_gtk_done(void) #ifdef NOTIFICATION_TRAYICON prefs_gtk_unregister_page((PrefsPage*) &trayicon_page); #endif +#ifdef NOTIFICATION_AYATANA_INDICATOR + prefs_gtk_unregister_page((PrefsPage*) &ayatana_indicator_page); +#endif #ifdef NOTIFICATION_INDICATOR prefs_gtk_unregister_page((PrefsPage*) &indicator_page); #endif @@ -1772,6 +1812,50 @@ static void notify_trayicon_popup_enable_set_sensitivity(GtkToggleButton *bu, #endif /* NOTIFICATION_TRAYICON */ +#ifdef NOTIFICATION_AYATANA_INDICATOR + +static void notify_create_ayatana_indicator_page(PrefsPage *page, GtkWindow *window, + gpointer data) +{ + GtkWidget *pvbox; + GtkWidget *vbox; + GtkWidget *checkbox; + + pvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 20); + gtk_container_set_border_width(GTK_CONTAINER(pvbox), 10); + + /* Enable indicator */ + checkbox = gtk_check_button_new_with_label(_("Enable Ayatana App Indicator")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), + notify_config.ayatana_indicator_enabled); + gtk_box_pack_start(GTK_BOX(pvbox), checkbox, FALSE, FALSE, 0); + ayatana_indicator_page.ayatana_indicator_enabled = checkbox; + + /* Container vbox for greying out everything */ + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); + gtk_box_pack_start(GTK_BOX(pvbox), vbox, FALSE, FALSE, 0); + + gtk_widget_show_all(pvbox); + ayatana_indicator_page.page.widget = pvbox; +} + +static void notify_destroy_ayatana_indicator_page(PrefsPage *page) +{ +} + +static void notify_save_ayatana_indicator(PrefsPage *page) +{ + notification_ayatana_indicator_disable(); + + notify_config.ayatana_indicator_enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ayatana_indicator_page.ayatana_indicator_enabled)); + + if(notify_config.ayatana_indicator_enabled) { + notification_ayatana_indicator_enable(); + notification_update_ayatana_indicator(); + } +} +#endif /* NOTIFICATION_AYATANA_INDICATOR */ + #ifdef NOTIFICATION_INDICATOR static void notify_create_indicator_page(PrefsPage *page, GtkWindow *window, diff --git a/src/plugins/notification/notification_prefs.h b/src/plugins/notification/notification_prefs.h index a80e39b1b..884cb51f9 100644 --- a/src/plugins/notification/notification_prefs.h +++ b/src/plugins/notification/notification_prefs.h @@ -100,6 +100,9 @@ typedef struct { gint trayicon_popup_timeout; #endif /* HAVE_LIBNOTIFY */ #endif /* Trayicon */ +#ifdef NOTIFICATION_AYATANA_INDICATOR + gboolean ayatana_indicator_enabled; +#endif /* NOTIFICATION_AYATANA_INDICATOR */ #ifdef NOTIFICATION_INDICATOR gboolean indicator_enabled; gboolean indicator_hide_minimized;