[balsa/77-notification] notification improvements: play sound, basic system tray icon support
- From: Albrecht Dreß <albrecht src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [balsa/77-notification] notification improvements: play sound, basic system tray icon support
- Date: Tue, 10 May 2022 18:50:14 +0000 (UTC)
commit 2e797f48acec50b2d7c8f7852cdd510f4d206003
Author: Albrecht Dreß <albrecht dress netcologne de>
Date: Tue May 10 20:50:05 2022 +0200
notification improvements: play sound, basic system tray icon support
See issue #77 for further details.
This branch implements the following improvements/extensions:
(1) New messages sound
Balsa had an option for playing a sound when new messages arrive, which
was a no-op. Make this option functional, and unify playing sound
(requires libcanberra).
(2) Basic System Tray Icon support
Add an option to display a System Tray icon which
- changes the colour when new messages arrived,
- shows/hides the Balsa main window on primary click,
- shows a simple menu on secondary click.
(requires libxapp, not supported by all desktop environments/wm's).
Details:
- configure.ac, meson.build, meson_options.txt: add option to enable
systray support
- images/Makefile.am, images/meson.build, images/balsa_attention.png:
add/install red Balsa icon (i.e. new messages)
- libbalsa/Makefile.am, libbalsa/meson.build, libbalsa/system-tray.[ch]:
implement system tray icon support
- libbalsa/libbalsa.[ch]: implement helper to play sound using canberra
- libbalsa/filter.c: use new helper to play filter sound
- src/balsa-app.[ch]: drop unused notify_new_mail_icon, add and
initialise enable_systray_icon, new_mail_sound_file
- src/save-restore.c: adjust save/restore of notify_new_mail_icon,
enable_systray_icon, new_mail_sound_file
- src/adjust prefs dialogue re. notify_new_mail_icon,
enable_systray_icon, new_mail_sound_file
- src/main-window.c: use system tray, add sound and system tray to new
messages notification handler
Signed-off-by: Albrecht Dreß <albrecht dress netcologne de>
configure.ac | 20 +++++-
images/Makefile.am | 1 +
images/balsa_attention.png | Bin 0 -> 7951 bytes
images/meson.build | 1 +
libbalsa/Makefile.am | 2 +
libbalsa/filter.c | 15 ++---
libbalsa/libbalsa.c | 22 +++++++
libbalsa/libbalsa.h | 4 ++
libbalsa/meson.build | 2 +
libbalsa/system-tray.c | 142 ++++++++++++++++++++++++++++++++++++++++
libbalsa/system-tray.h | 55 ++++++++++++++++
meson.build | 12 ++++
meson_options.txt | 7 +-
src/balsa-app.c | 11 +++-
src/balsa-app.h | 12 ++--
src/main-window.c | 104 ++++++++++++++++++++++++++++-
src/pref-manager.c | 158 +++++++++++++++++++++++++++++++++++----------
src/save-restore.c | 22 +++++--
18 files changed, 528 insertions(+), 62 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index ba4cf446f..59db71c9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -65,9 +65,14 @@ AC_ARG_ENABLE([autocrypt],
[build with Autocrypt support (see https://autocrypt.org/), default=no, requires
sqlite3)]),
[autocrypt=$enableval], [autocrypt=no])
+AC_ARG_ENABLE([systray],
+ AC_HELP_STRING([--enable-systray],
+ [enable System Tray Icon support, default=no, requires libxapp]),
+ [systray=$enableval], [systray=no])
+
AC_ARG_WITH(canberra,
AC_HELP_STRING([--with-canberra],
- [Use libcanberra-gtk3 for filter sounds (default=no)]),
+ [Use libcanberra-gtk3 for new messages and filter sounds (default=no)]),
[with_canberra=$withval],[with_canberra=no])
AC_ARG_WITH(compface,
@@ -321,6 +326,18 @@ else
AC_MSG_RESULT([no])
fi
+# System Tray icon support via libxapp
+AC_MSG_CHECKING(whether to build with System Tray Icon support)
+if test x"$systray" != xno ; then
+ AC_MSG_RESULT([yes])
+ PKG_CHECK_MODULES(SYSTRAY, [xapp])
+ AC_DEFINE(ENABLE_SYSTRAY,1,[If defined, enable System Tray Icon support])
+ BALSA_CFLAGS="$BALSA_CFLAGS $SYSTRAY_CFLAGS"
+ BALSA_LIBS="$BALSA_LIBS $SYSTRAY_LIBS"
+else
+ AC_MSG_RESULT([no])
+fi
+
# OpenLDAP configuration.
#
AC_MSG_CHECKING(whether to use LDAP)
@@ -653,6 +670,7 @@ echo " HTML widget: $use_html_widget"
echo " Use GNOME: $with_gnome"
echo " Use Canberra: $with_canberra"
echo " Use Autocrypt: $autocrypt"
+echo " System Tray Icon: $systray"
echo " Use LDAP: $with_ldap"
echo " Use GSS: $with_gss"
echo " Use SQLite: $with_sqlite"
diff --git a/images/Makefile.am b/images/Makefile.am
index 18bc73e15..e3b54917b 100644
--- a/images/Makefile.am
+++ b/images/Makefile.am
@@ -6,6 +6,7 @@ balsa_IMGS = \
attachment.png \
balsa-top.png \
balsa_icon.png \
+ balsa_attention.png \
balsa_logo.png
EXTRA_DIST = $(balsa_IMGS) \
diff --git a/images/balsa_attention.png b/images/balsa_attention.png
new file mode 100644
index 000000000..4cc76832d
Binary files /dev/null and b/images/balsa_attention.png differ
diff --git a/images/meson.build b/images/meson.build
index cf81c39e9..34448d199 100644
--- a/images/meson.build
+++ b/images/meson.build
@@ -10,6 +10,7 @@ balsa_imgs = [
'attachment.png',
'balsa-top.png',
'balsa_icon.png',
+ 'balsa_attention.png',
'balsa_logo.png'
]
diff --git a/libbalsa/Makefile.am b/libbalsa/Makefile.am
index 28ae1d2e3..3e72b6cd7 100644
--- a/libbalsa/Makefile.am
+++ b/libbalsa/Makefile.am
@@ -130,6 +130,8 @@ libbalsa_a_SOURCES = \
server-config.h \
smtp-server.c \
smtp-server.h \
+ system-tray.c \
+ system-tray.h \
source-viewer.c \
url.c \
url.h \
diff --git a/libbalsa/filter.c b/libbalsa/filter.c
index 2bbc7868a..565f88365 100644
--- a/libbalsa/filter.c
+++ b/libbalsa/filter.c
@@ -35,10 +35,6 @@
#include <ctype.h>
#include <string.h>
-#if HAVE_CANBERRA
-#include <canberra-gtk.h>
-#endif /* HAVE_CANBERRA */
-
#include "libbalsa.h"
#include "libbalsa_private.h"
@@ -249,13 +245,10 @@ libbalsa_filter_mailbox_messages(LibBalsaFilter * filt,
#if HAVE_CANBERRA
if (filt->sound) {
- GdkScreen *screen;
- gint rc;
-
- screen = gdk_screen_get_default();
- rc = ca_context_play(ca_gtk_context_get_for_screen(screen), 0,
- CA_PROP_MEDIA_FILENAME, filt->sound, NULL);
- g_debug("(%s) play %s, %s", __func__, filt->sound, ca_strerror(rc));
+ if (!libbalsa_play_sound(filt->sound, &err)) {
+ g_warning("%s: %s", __func__, (err != NULL) ? err->message : "unknown");
+ g_clear_error(&err);
+ }
}
#endif /* HAVE_CANBERRA */
if (filt->popup_text)
diff --git a/libbalsa/libbalsa.c b/libbalsa/libbalsa.c
index 6da54f574..ec5fb116a 100644
--- a/libbalsa/libbalsa.c
+++ b/libbalsa/libbalsa.c
@@ -43,6 +43,10 @@
#include <gtksourceview/gtksource.h>
#endif
+#if HAVE_CANBERRA
+#include <canberra-gtk.h>
+#endif
+
#include "misc.h"
#include "missing.h"
#include "x509-cert-widget.h"
@@ -695,6 +699,24 @@ libbalsa_source_view_new(gboolean highlight_phrases)
}
#endif /* HAVE_GTKSOURCEVIEW */
+#if HAVE_CANBERRA
+gboolean
+libbalsa_play_sound(const gchar *soundfile, GError **error)
+{
+ GdkScreen *screen;
+ gint rc;
+
+ g_return_val_if_fail(soundfile != NULL, FALSE);
+
+ screen = gdk_screen_get_default();
+ rc = ca_context_play(ca_gtk_context_get_for_screen(screen), 0, CA_PROP_MEDIA_FILENAME, soundfile,
NULL);
+ if (rc != 0) {
+ g_set_error(error, LIBBALSA_ERROR_QUARK, rc, _("Cannot play sound file “%s”: %s"), soundfile,
ca_strerror(rc));
+ }
+ return rc == 0;
+}
+#endif /* HAVE_CANBERRA */
+
/*
* Error domains for GError:
*/
diff --git a/libbalsa/libbalsa.h b/libbalsa/libbalsa.h
index 205da2510..0d048e047 100644
--- a/libbalsa/libbalsa.h
+++ b/libbalsa/libbalsa.h
@@ -190,4 +190,8 @@ GtkDialogFlags libbalsa_dialog_flags(void);
GtkWidget *libbalsa_source_view_new(gboolean highlight_phrases);
#endif /* HAVE_GTKSOURCEVIEW */
+#ifdef HAVE_CANBERRA
+gboolean libbalsa_play_sound(const gchar *soundfile, GError **error);
+#endif /* HAVE_CANBERRA*/
+
#endif /* __LIBBALSA_H__ */
diff --git a/libbalsa/meson.build b/libbalsa/meson.build
index c4945695e..14c31724f 100644
--- a/libbalsa/meson.build
+++ b/libbalsa/meson.build
@@ -128,6 +128,8 @@ libbalsa_a_sources = [
'smtp-server.c',
'smtp-server.h',
'source-viewer.c',
+ 'system-tray.c',
+ 'system-tray.h',
'url.c',
'url.h',
'geometry-manager.c',
diff --git a/libbalsa/system-tray.c b/libbalsa/system-tray.c
new file mode 100644
index 000000000..02a09d5f4
--- /dev/null
+++ b/libbalsa/system-tray.c
@@ -0,0 +1,142 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/* Balsa E-Mail Client
+ *
+ * Copyright (C) 1997-2022 Stuart Parmenter and others,
+ * See the file AUTHORS for a list.
+ *
+ * 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 2, 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 <https://www.gnu.org/licenses/>.
+ */
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#ifdef ENABLE_SYSTRAY
+
+#include <glib/gi18n.h>
+#include <libxapp/xapp-status-icon.h>
+#include "files.h"
+#include "system-tray.h"
+
+
+static XAppStatusIcon *status_icon;
+static gchar *icon_path[2] = {NULL, NULL};
+static gboolean icon_attention;
+static GtkMenu *icon_menu;
+static libbalsa_systray_cb_t icon_activate_cb;
+static gpointer icon_activate_cb_data;
+
+
+static void systray_cb_internal(XAppStatusIcon *icon,
+ guint button,
+ guint time,
+ gpointer user_data);
+
+
+void
+libbalsa_systray_icon_init(GtkMenu *menu, libbalsa_systray_cb_t activate_cb, gpointer activate_cb_data)
+{
+ g_return_if_fail(icon_path[0] == NULL);
+
+ icon_path[0] = balsa_pixmap_finder("balsa_icon.png");
+ icon_path[1] = balsa_pixmap_finder("balsa_attention.png");
+ icon_activate_cb = activate_cb;
+ icon_activate_cb_data = activate_cb_data;
+ if (menu != NULL) {
+ icon_menu = g_object_ref(menu);
+ }
+}
+
+
+void
+libbalsa_systray_icon_enable(gboolean enable)
+{
+ g_return_if_fail(icon_path[0] != NULL);
+
+ if (enable) {
+ if (status_icon == NULL) {
+ status_icon = xapp_status_icon_new();
+ if (icon_menu != NULL) {
+ xapp_status_icon_set_secondary_menu(status_icon, icon_menu);
+ }
+ if (icon_activate_cb != NULL) {
+ g_signal_connect(status_icon, "activate", G_CALLBACK(systray_cb_internal),
icon_activate_cb_data);
+ }
+ xapp_status_icon_set_visible(status_icon, TRUE);
+ icon_attention = TRUE;
+ libbalsa_systray_icon_attention(FALSE);
+ }
+ } else {
+ if (status_icon != NULL) {
+ g_object_unref(status_icon);
+ status_icon = NULL;
+ }
+ }
+}
+
+
+void
+libbalsa_systray_icon_attention(gboolean attention)
+{
+ g_return_if_fail(icon_path[0] != NULL);
+
+ if ((status_icon != NULL) && (attention != icon_attention)) {
+ icon_attention = attention;
+ if (attention) {
+ xapp_status_icon_set_icon_name(status_icon, icon_path[1]);
+ xapp_status_icon_set_tooltip_text(status_icon, _("Balsa: you have new mail"));
+ } else {
+ xapp_status_icon_set_icon_name(status_icon, icon_path[0]);
+ xapp_status_icon_set_tooltip_text(status_icon, _("Balsa"));
+ }
+ }
+}
+
+
+void
+libbalsa_systray_icon_destroy(void)
+{
+ size_t n;
+
+ if (icon_path[0] != NULL) {
+ icon_activate_cb = NULL;
+ if (icon_menu != NULL) {
+ g_object_unref(icon_menu);
+ icon_menu = NULL;
+ }
+ for (n = 0; n < G_N_ELEMENTS(icon_path); n++) {
+ g_free(icon_path[n]);
+ icon_path[n] = NULL;
+ }
+ if (status_icon != NULL) {
+ g_object_unref(status_icon);
+ status_icon = NULL;
+ }
+ }
+}
+
+
+static void
+systray_cb_internal(XAppStatusIcon G_GNUC_UNUSED *icon, guint button, guint G_GNUC_UNUSED time, gpointer
user_data)
+{
+ g_return_if_fail(status_icon != NULL);
+
+ if ((button == 1) && (icon_activate_cb != NULL)) {
+ icon_activate_cb(user_data);
+ }
+}
+
+
+#endif /* ENABLE_SYSTRAY */
diff --git a/libbalsa/system-tray.h b/libbalsa/system-tray.h
new file mode 100644
index 000000000..6bb0e1507
--- /dev/null
+++ b/libbalsa/system-tray.h
@@ -0,0 +1,55 @@
+/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
+/* Balsa E-Mail Client
+ *
+ * Copyright (C) 1997-2022 Stuart Parmenter and others,
+ * See the file AUTHORS for a list.
+ *
+ * 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 2, 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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SYSTEM_TRAY_H_
+#define _SYSTEM_TRAY_H_
+
+#ifndef BALSA_VERSION
+# error "Include config.h before this file."
+#endif
+
+
+#ifdef ENABLE_SYSTRAY
+
+
+#include <glib.h>
+
+
+G_BEGIN_DECLS
+
+
+typedef void (*libbalsa_systray_cb_t)(gpointer);
+
+
+void libbalsa_systray_icon_init(GtkMenu *menu,
+ libbalsa_systray_cb_t activate_cb,
+ gpointer activate_cb_data);
+void libbalsa_systray_icon_enable(gboolean enable);
+void libbalsa_systray_icon_attention(gboolean attention);
+void libbalsa_systray_icon_destroy(void);
+
+
+G_END_DECLS
+
+
+#endif /* ENABLE_SYSTRAY */
+
+
+#endif /* _SYSTEM_TRAY_H_ */
diff --git a/meson.build b/meson.build
index 601650cbd..b512edd7a 100644
--- a/meson.build
+++ b/meson.build
@@ -48,6 +48,7 @@ endif
gnome_desktop = get_option('gnome-desktop')
autocrypt = get_option('autocrypt')
+systray = get_option('systray')
canberra = get_option('canberra')
compface = get_option('compface')
gss = get_option('gss')
@@ -212,6 +213,17 @@ if autocrypt
balsa_deps += autocrypt_dep
endif
+# System Tray Icons
+if systray
+ systray_dep = dependency('xapp', required : true)
+ if systray_dep.found()
+ conf.set('ENABLE_SYSTRAY', 1, description : 'If defined, enable System Tray Icon support.')
+ else
+ error('*** You enabled System Tray Icon support but libxapp is not found.')
+ endif
+ balsa_deps += systray_dep
+endif
+
# OpenLDAP configuration.
#
if ldap != 'false'
diff --git a/meson_options.txt b/meson_options.txt
index 09bcf2af4..98859887e 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -16,7 +16,12 @@ option('fcntl',
option('autocrypt',
type : 'boolean',
value : false,
- description : 'build with Autocrypt support (see https://autocrypt.org/), (default=false), requires gpgme
and sqlite3')
+ description : 'build with Autocrypt support (see https://autocrypt.org/), (default=false), requires
sqlite3')
+
+option('systray',
+ type : 'boolean',
+ value : false,
+ description : 'enable System Tray Icon support, (default=false), requires libxapp')
option('canberra',
type : 'boolean',
diff --git a/src/balsa-app.c b/src/balsa-app.c
index 7c227cda4..88c07e589 100644
--- a/src/balsa-app.c
+++ b/src/balsa-app.c
@@ -412,9 +412,16 @@ balsa_app_init(void)
balsa_app.error_message = 0;
balsa_app.debug_message = 0;
- balsa_app.notify_new_mail_sound = 1;
+#ifdef HAVE_CANBERRA
+ balsa_app.notify_new_mail_sound = 0;
+ balsa_app.new_mail_sound_file = NULL;
+#endif
+
balsa_app.notify_new_mail_dialog = 0;
- balsa_app.notify_new_mail_icon = 1;
+
+#ifdef ENABLE_SYSTRAY
+ balsa_app.enable_systray_icon = 0;
+#endif
/* Local and IMAP */
balsa_app.local_scan_depth = 1;
diff --git a/src/balsa-app.h b/src/balsa-app.h
index 2d51b2a36..c9e2c4c37 100644
--- a/src/balsa-app.h
+++ b/src/balsa-app.h
@@ -167,14 +167,16 @@ extern struct BalsaApplication {
gint check_mail_timer;
gint check_mail_timer_id;
- /* This can be configured from the gnome control panel */
- /* It's here just in case some other app also uses the same */
- /* system wide sound event and you want Balsa to behave differently */
- /* There is no prefs setting for this item */
+#ifdef HAVE_CANBERRA
gint notify_new_mail_sound;
+ gchar *new_mail_sound_file;
+#endif
gint notify_new_mail_dialog;
- gint notify_new_mail_icon;
+
+#ifdef ENABLE_SYSTRAY
+ gint enable_systray_icon;
+#endif
/* automatically close mailboxes after XX minutes */
gboolean close_mailbox_auto;
diff --git a/src/main-window.c b/src/main-window.c
index e013e7ea5..a5c32749e 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -68,6 +68,7 @@
#include "toolbar-factory.h"
#include "libbalsa-progress.h"
#include "geometry-manager.h"
+#include "system-tray.h"
#include "filter.h"
#include "filter-funcs.h"
@@ -785,6 +786,11 @@ bw_is_active_notify(GObject * gobject, GParamSpec * pspec,
priv->new_mail_notification_sent = FALSE;
}
gtk_window_set_urgency_hint(gtk_window, FALSE);
+#ifdef ENABLE_SYSTRAY
+ if (balsa_app.enable_systray_icon) {
+ libbalsa_systray_icon_attention(FALSE);
+ }
+#endif
}
}
@@ -2254,6 +2260,65 @@ bw_enable_next_unread(BalsaWindow * window, gboolean has_unread_mailbox)
bw_action_set_enabled(window, "next-unread", has_unread_mailbox);
}
+#ifdef ENABLE_SYSTRAY
+static void
+on_systray_click(gpointer data)
+{
+ GtkWindow *window = GTK_WINDOW(data);
+
+ g_return_if_fail(window != NULL);
+ if (gtk_window_is_active(window)) {
+ gtk_window_iconify(window);
+ } else {
+ gtk_window_present_with_time(window, gtk_get_current_event_time());
+ }
+}
+
+static void
+on_systray_show_hide(GtkMenuItem G_GNUC_UNUSED *menuitem, gpointer user_data)
+{
+ /* process pending events, as otherwise the Balsa window will never be active... */
+ while (gtk_events_pending()) {
+ gtk_main_iteration();
+ }
+ on_systray_click(user_data);
+}
+
+static void
+on_systray_receive(GtkMenuItem G_GNUC_UNUSED *menuitem, gpointer user_data)
+{
+ if (g_atomic_int_get(&checking_mail) == 1) {
+ check_new_messages_real(BALSA_WINDOW(user_data), TRUE);
+ }
+}
+
+static void
+on_systray_new_msg(GtkMenuItem G_GNUC_UNUSED *menuitem, gpointer user_data)
+{
+ new_message_activated(NULL, NULL, user_data);
+}
+
+static void
+bw_init_systray(BalsaWindow *window)
+{
+ GtkWidget *menu;
+ GtkWidget *menuitem;
+
+ menu = gtk_menu_new();
+ menuitem = gtk_menu_item_new_with_label(_("Show/Hide"));
+ g_signal_connect(menuitem, "activate", G_CALLBACK(on_systray_show_hide), window);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ menuitem = gtk_menu_item_new_with_label(_("Check"));
+ g_signal_connect(menuitem, "activate", G_CALLBACK(on_systray_receive), window);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ menuitem = gtk_menu_item_new_with_label(_("Compose"));
+ g_signal_connect(menuitem, "activate", G_CALLBACK(on_systray_new_msg), window);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ gtk_widget_show_all(menu);
+ libbalsa_systray_icon_init(GTK_MENU(menu), on_systray_click, window);
+}
+#endif
+
GtkWidget *
balsa_window_new(GtkApplication *application)
{
@@ -2435,6 +2500,11 @@ balsa_window_new(GtkApplication *application)
g_timeout_add_seconds(30, (GSourceFunc) bw_close_mailbox_on_timer, window);
+#ifdef ENABLE_SYSTRAY
+ bw_init_systray(window);
+ libbalsa_systray_icon_enable(balsa_app.enable_systray_icon != 0);
+#endif
+
gtk_widget_show(GTK_WIDGET(window));
return GTK_WIDGET(window);
}
@@ -3198,6 +3268,10 @@ balsa_window_dispose(GObject * object)
G_OBJECT_CLASS(balsa_window_parent_class)->dispose(object);
balsa_unregister_pixmaps();
+
+#ifdef ENABLE_SYSTRAY
+ libbalsa_systray_icon_destroy();
+#endif
}
/*
@@ -3626,6 +3700,10 @@ bw_display_new_mail_notification(int num_new, int has_new)
GtkWindow *window = GTK_WINDOW(balsa_app.main_window);
BalsaWindowPrivate *priv =
balsa_window_get_instance_private(balsa_app.main_window);
+#ifdef HAVE_CANBERRA
+ static gint64 last_new_mail_sound = -1;
+ gint64 now;
+#endif
/* remove a running notification timeout task */
if (notify_ctx.timeout_id > 0U) {
@@ -3633,10 +3711,32 @@ bw_display_new_mail_notification(int num_new, int has_new)
notify_ctx.timeout_id = 0U;
}
- if (!balsa_app.notify_new_mail_dialog)
+ if (gtk_window_is_active(window))
return;
- if (gtk_window_is_active(window))
+#ifdef HAVE_CANBERRA
+ /* play sound if configured, but not too frequently (min. 30 seconds in between)*/
+ now = g_get_monotonic_time();
+ if ((balsa_app.notify_new_mail_sound != 0) && (balsa_app.new_mail_sound_file != NULL) &&
+ (now > (last_new_mail_sound + 30 * 1000000))) {
+ GError *error = NULL;
+
+ if (!libbalsa_play_sound(balsa_app.new_mail_sound_file, &error)) {
+ g_warning("%s: %s", __func__, (error != NULL) ? error->message : "unknown");
+ g_clear_error(&error);
+ } else {
+ last_new_mail_sound = now;
+ }
+ }
+#endif
+
+#ifdef ENABLE_SYSTRAY
+ if (balsa_app.enable_systray_icon) {
+ libbalsa_systray_icon_attention(TRUE);
+ }
+#endif
+
+ if (balsa_app.notify_new_mail_dialog == 0)
return;
gtk_window_set_urgency_hint(window, TRUE);
diff --git a/src/pref-manager.c b/src/pref-manager.c
index 1ca43cc4c..e8521cc51 100644
--- a/src/pref-manager.c
+++ b/src/pref-manager.c
@@ -44,6 +44,10 @@
#include "smtp-server.h"
#include "libbalsa-conf.h"
+#ifdef ENABLE_SYSTRAY
+#include "system-tray.h"
+#endif
+
#include <glib/gi18n.h>
#define NUM_ENCODING_MODES 3
@@ -87,8 +91,11 @@ typedef struct _PropertyUI {
GtkWidget *check_imap;
GtkWidget *check_imap_inbox;
GtkWidget *notify_new_mail_dialog;
+#ifdef HAVE_CANBERRA
GtkWidget *notify_new_mail_sound;
- GtkWidget *notify_new_mail_icon;
+ GtkWidget *new_mail_sound_file;
+ GtkWidget *new_mail_sound_play;
+#endif
GtkWidget *mdn_reply_clean_menu, *mdn_reply_notclean_menu;
GtkWidget *close_mailbox_auto;
@@ -99,6 +106,9 @@ typedef struct _PropertyUI {
GtkWidget *expunge_auto;
GtkWidget *expunge_minutes;
GtkWidget *action_after_move_menu;
+#ifdef ENABLE_SYSTRAY
+ GtkWidget *enable_systray_icon;
+#endif
GtkWidget *previewpane;
GtkWidget *layout_type;
@@ -464,12 +474,16 @@ apply_prefs(GtkDialog * pbox)
balsa_app.notify_new_mail_dialog =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
(pui->notify_new_mail_dialog));
+
+#ifdef HAVE_CANBERRA
balsa_app.notify_new_mail_sound =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
(pui->notify_new_mail_sound));
- balsa_app.notify_new_mail_icon =
- gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (pui->notify_new_mail_icon));
+ g_free(balsa_app.new_mail_sound_file);
+ balsa_app.new_mail_sound_file =
+ gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pui->new_mail_sound_file));
+#endif
+
balsa_app.mdn_reply_clean =
pm_combo_box_get_level(pui->mdn_reply_clean_menu);
balsa_app.mdn_reply_notclean =
@@ -519,6 +533,13 @@ apply_prefs(GtkDialog * pbox)
(pui->close_mailbox_minutes)) *
60;
+#ifdef ENABLE_SYSTRAY
+ balsa_app.enable_systray_icon =
+ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
+ (pui->enable_systray_icon));
+ libbalsa_systray_icon_enable(balsa_app.enable_systray_icon != 0);
+#endif
+
libbalsa_mailbox_set_filter(NULL, pui->filter);
balsa_app.expunge_on_close =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
@@ -715,12 +736,14 @@ set_prefs(void)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
(pui->notify_new_mail_dialog),
balsa_app.notify_new_mail_dialog);
+#ifdef HAVE_CANBERRA
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
(pui->notify_new_mail_sound),
balsa_app.notify_new_mail_sound);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (pui->notify_new_mail_icon),
- balsa_app.notify_new_mail_icon);
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(pui->new_mail_sound_file),
+ balsa_app.new_mail_sound_file);
+#endif
+
if (!balsa_app.check_imap)
gtk_widget_set_sensitive(GTK_WIDGET(pui->check_imap_inbox), FALSE);
@@ -739,6 +762,11 @@ set_prefs(void)
gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON(pui->close_mailbox_auto)));
+#ifdef ENABLE_SYSTRAY
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->enable_systray_icon),
+ balsa_app.enable_systray_icon);
+#endif
+
pui->filter = libbalsa_mailbox_get_filter(NULL);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->hide_deleted),
pui->filter & (1 << 0));
@@ -1728,6 +1756,47 @@ timer_modified_cb(GtkWidget * widget, GtkWidget * pbox)
properties_modified_cb(widget, pbox);
}
+#ifdef HAVE_CANBERRA
+static void
+sound_modified_cb(GtkWidget *widget, GtkWidget *pbox)
+{
+ gboolean newstate;
+
+ newstate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pui->notify_new_mail_sound));
+
+ gtk_widget_set_sensitive(pui->new_mail_sound_file, newstate);
+ if (newstate) {
+ gchar *soundfile;
+
+ soundfile = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pui->new_mail_sound_file));
+ gtk_widget_set_sensitive(pui->new_mail_sound_play, soundfile != NULL);
+ g_free(soundfile);
+ } else {
+ gtk_widget_set_sensitive(pui->new_mail_sound_play, FALSE);
+ }
+ properties_modified_cb(widget, pbox);
+}
+
+static void
+sound_play(GtkWidget G_GNUC_UNUSED *widget, gpointer G_GNUC_UNUSED data)
+{
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pui->notify_new_mail_sound))) {
+ gchar *soundfile;
+
+ soundfile = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pui->new_mail_sound_file));
+ if (soundfile != NULL) {
+ GError *error = NULL;
+
+ if (!libbalsa_play_sound(soundfile, &error)) {
+ libbalsa_information(LIBBALSA_INFORMATION_ERROR, "%s", (error != NULL) ?
error->message : _("unknown"));
+ g_clear_error(&error);
+ }
+ g_free(soundfile);
+ }
+ }
+}
+#endif /* HAVE_CANBERRA */
+
static void
send_timer_modified_cb(GtkWidget * widget, GtkWidget * pbox)
{
@@ -2106,7 +2175,6 @@ pm_grid_add_checking_group(GtkWidget * grid_widget)
gint row = pm_grid_get_next_row(grid);
GtkAdjustment *spinbutton_adj;
GtkWidget *label;
- GtkWidget *hbox;
pm_grid_attach(grid, pm_group_label(_("Checking")), 0, row, 3, 1);
@@ -2131,29 +2199,6 @@ pm_grid_add_checking_group(GtkWidget * grid_widget)
gtk_check_button_new_with_mnemonic(_("Check Inbox _only"));
pm_grid_attach(grid, pui->check_imap_inbox, 2, row, 2, 1);
- hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, COL_SPACING);
-
- label = gtk_label_new(_("When mail arrives:"));
- gtk_widget_set_halign(label, GTK_ALIGN_START);
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-
- pui->notify_new_mail_dialog =
- gtk_check_button_new_with_label(_("Display message"));
- gtk_box_pack_start(GTK_BOX(hbox), pui->notify_new_mail_dialog,
- FALSE, FALSE, 0);
-
- pui->notify_new_mail_sound =
- gtk_check_button_new_with_label(_("Play sound"));
- gtk_box_pack_start(GTK_BOX(hbox), pui->notify_new_mail_sound,
- FALSE, FALSE, 0);
-
- pui->notify_new_mail_icon =
- gtk_check_button_new_with_label(_("Show icon"));
- gtk_box_pack_start(GTK_BOX(hbox), pui->notify_new_mail_icon,
- FALSE, FALSE, 0);
-
- pm_grid_attach(grid, hbox, 1, ++row, 3, 1);
-
pui->quiet_background_check = gtk_check_button_new_with_label(
_("Do background check quietly (no messages in status bar)"));
pm_grid_attach(grid, pui->quiet_background_check, 1, ++row, 3, 1);
@@ -2173,6 +2218,35 @@ pm_grid_add_checking_group(GtkWidget * grid_widget)
pm_grid_set_next_row(grid, ++row);
}
+/*
+ * New messages notification group
+ */
+static void
+pm_grid_add_new_mail_notify_group(GtkWidget * grid_widget)
+{
+ GtkGrid *grid = (GtkGrid *) grid_widget;
+ gint row = pm_grid_get_next_row(grid);
+
+ pm_grid_attach(grid, pm_group_label(_("Notification about new messages")), 0, row, 3, 1);
+
+ pui->notify_new_mail_dialog = gtk_check_button_new_with_label(_("Display message"));
+ pm_grid_attach(grid, pui->notify_new_mail_dialog, 1, ++row, 1, 1);
+
+#ifdef HAVE_CANBERRA
+ pui->notify_new_mail_sound = gtk_check_button_new_with_label(_("Play sound"));
+ pm_grid_attach(grid, pui->notify_new_mail_sound, 1, ++row, 1, 1);
+
+ pui->new_mail_sound_file = gtk_file_chooser_button_new(_("New message sound"),
GTK_FILE_CHOOSER_ACTION_OPEN);
+ pm_grid_attach(grid, pui->new_mail_sound_file, 2, row, 1, 1);
+
+ pui->new_mail_sound_play = gtk_button_new_from_icon_name("media-playback-start",
GTK_ICON_SIZE_SMALL_TOOLBAR);
+ pm_grid_attach(grid, pui->new_mail_sound_play, 3, row, 1, 1);
+ gtk_widget_set_halign(pui->new_mail_sound_play, GTK_ALIGN_START);
+#endif
+
+ pm_grid_set_next_row(grid, ++row);
+}
+
/*
* MDN request group
*/
@@ -2935,6 +3009,11 @@ pm_grid_add_misc_group(GtkWidget * grid_widget)
pm_grid_attach_label(grid, 3, row, 1, 1, _("minutes"));
+#ifdef ENABLE_SYSTRAY
+ pui->enable_systray_icon =
+ pm_grid_attach_check(grid, 1, ++row, 3, 1, _("Enable System Tray Icon support"));
+#endif
+
pm_grid_set_next_row(grid, ++row);
}
@@ -3042,6 +3121,7 @@ pm_incoming_page(void)
GtkWidget *grid = pm_grid_new();
pm_grid_add_checking_group(grid);
+ pm_grid_add_new_mail_notify_group(grid);
pm_grid_add_mdn_group(grid);
return grid;
@@ -3430,11 +3510,14 @@ open_preferences_manager(GtkWidget * widget, gpointer data)
g_signal_connect(pui->notify_new_mail_dialog, "toggled",
G_CALLBACK(properties_modified_cb), property_box);
+#ifdef HAVE_CANBERRA
g_signal_connect(pui->notify_new_mail_sound, "toggled",
- G_CALLBACK(properties_modified_cb), property_box);
-
- g_signal_connect(pui->notify_new_mail_icon, "toggled",
- G_CALLBACK(properties_modified_cb), property_box);
+ G_CALLBACK(sound_modified_cb), property_box);
+ g_signal_connect(pui->new_mail_sound_file, "selection-changed",
+ G_CALLBACK(sound_modified_cb), property_box);
+ g_signal_connect(pui->new_mail_sound_play, "clicked",
+ G_CALLBACK(sound_play), property_box);
+#endif
g_signal_connect(pui->close_mailbox_auto, "toggled",
G_CALLBACK(mailbox_close_timer_modified_cb),
@@ -3443,6 +3526,11 @@ open_preferences_manager(GtkWidget * widget, gpointer data)
G_CALLBACK(mailbox_close_timer_modified_cb),
property_box);
+#ifdef ENABLE_SYSTRAY
+ g_signal_connect(pui->enable_systray_icon, "toggled",
+ G_CALLBACK(properties_modified_cb), property_box);
+#endif
+
g_signal_connect(pui->hide_deleted, "toggled",
G_CALLBACK(filter_modified_cb), property_box);
g_signal_connect(pui->expunge_on_close, "toggled",
diff --git a/src/save-restore.c b/src/save-restore.c
index 0c5bae90a..a020c61c2 100644
--- a/src/save-restore.c
+++ b/src/save-restore.c
@@ -980,10 +980,12 @@ config_global_load(void)
balsa_app.notify_new_mail_dialog =
d_get_gint("NewMailNotificationDialog", 0);
+#ifdef HAVE_CANBERRA
balsa_app.notify_new_mail_sound =
- d_get_gint("NewMailNotificationSound", 1);
- balsa_app.notify_new_mail_icon =
- d_get_gint("NewMailNotificationIcon", 1);
+ d_get_gint("NewMailNotificationSound", 0);
+ balsa_app.new_mail_sound_file =
+ libbalsa_conf_get_string("NewMailNotificationSoundFile");
+#endif
balsa_app.check_mail_upon_startup =
libbalsa_conf_get_bool("OnStartup=false");
balsa_app.check_mail_auto = libbalsa_conf_get_bool("Auto=false");
@@ -1140,6 +1142,11 @@ config_global_load(void)
/* This setting is now per address book */
libbalsa_conf_clean_key("AddressBookDistMode");
+#ifdef ENABLE_SYSTRAY
+ balsa_app.enable_systray_icon =
+ d_get_gint("EnableSystrayIcon", 0);
+#endif
+
libbalsa_conf_pop_group();
/* Toolbars */
@@ -1434,10 +1441,11 @@ config_save(void)
libbalsa_conf_set_int("NewMailNotificationDialog",
balsa_app.notify_new_mail_dialog);
+#ifdef HAVE_CANBERRA
libbalsa_conf_set_int("NewMailNotificationSound",
balsa_app.notify_new_mail_sound);
- libbalsa_conf_set_int("NewMailNotificationIcon",
- balsa_app.notify_new_mail_icon);
+ libbalsa_conf_set_string("NewMailNotificationSoundFile", balsa_app.new_mail_sound_file);
+#endif
libbalsa_conf_set_bool("OnStartup", balsa_app.check_mail_upon_startup);
libbalsa_conf_set_bool("Auto", balsa_app.check_mail_auto);
libbalsa_conf_set_int("AutoDelay", balsa_app.check_mail_timer);
@@ -1526,6 +1534,10 @@ config_save(void)
else
libbalsa_conf_clean_key("DefaultAddressBook");
+#ifdef ENABLE_SYSTRAY
+ libbalsa_conf_set_int("EnableSystrayIcon", balsa_app.enable_systray_icon);
+#endif
+
libbalsa_conf_pop_group();
/* Toolbars */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]