[balsa/information_#63] desktop notifications enhancements and clean-up




commit 73180b82721687af9e726a10b06fa0701f1ce974
Author: Albrecht Dreß <albrecht dress netcologne de>
Date:   Thu Dec 23 12:27:12 2021 +0100

    desktop notifications enhancements and clean-up
    
    Changes in this branch include:
    * do not re-use the same GNotification so Balsa can display more than
    one at a time
    * drop libbalsa_information_parented() which was used in one place only
    * optionally add a button to the notification so the user may
    hide/disable further instances, and store the choices in the config
    * add the option for hiding to a few notifications
    * simplify initialisation
    * fix wrong warning re. a broken Autocrypt: header (see issue #63)
    
    Details:
    * libbalsa/information.[ch]: re-write the desktop notifications module
    * libbalsa/mailbox_imap.c: add option to hide the warning re. an IMAP
    server not supporting server-side threading
    * src/ab-main.c, srac/main.c: use the new simplified initialisation
    * src/balsa-app.[ch]: make the function to check if any identity uses
    Autocrypt public
    * src/balsa-message.c: remove autocrypt_in_use() shifted to balsa-app;
    add option to hide notification re. an untrusted signature
    * src/balsa-mime-widget-crypto.c: fix false positive re. broken
    Autocrypt header, correct message may be hidden
    * src/mailbox-node.c, src/main-window.c: replace
    libbalsa_information_parented()
    * src/save-restore.c: save list of hidden notifications
    
    Signed-off-by: Albrecht Dreß <albrecht dress netcologne de>

 libbalsa/information.c         | 206 +++++++++++++++++++++++++++--------------
 libbalsa/information.h         |  72 +++++++++++---
 libbalsa/mailbox_imap.c        |   4 +-
 src/ab-main.c                  |  35 +------
 src/balsa-app.c                |  17 ++++
 src/balsa-app.h                |   3 +
 src/balsa-message.c            |  34 ++-----
 src/balsa-mime-widget-crypto.c |  12 ++-
 src/mailbox-node.c             |   3 +-
 src/main-window.c              |  10 +-
 src/main.c                     |  35 +------
 src/save-restore.c             |   3 +
 12 files changed, 251 insertions(+), 183 deletions(-)
---
diff --git a/libbalsa/information.c b/libbalsa/information.c
index 456772c50..d5931ebf1 100644
--- a/libbalsa/information.c
+++ b/libbalsa/information.c
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /* Balsa E-Mail Client
  *
- * Copyright (C) 1997-2016 Stuart Parmenter and others,
+ * Copyright (C) 1997-2021 Stuart Parmenter and others,
  *                         See the file AUTHORS for a list.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -22,33 +22,132 @@
 # include "config.h"
 #endif                          /* HAVE_CONFIG_H */
 #include "information.h"
-#include "libbalsa.h"
+#include "libbalsa-conf.h"
 #include <string.h>
+#include <glib/gi18n.h>
 
-static GNotification *notification;
+static GApplication *notify_app = NULL;
+static const gchar *notify_title = NULL;
+static const gchar *id_base = NULL;
+static GHashTable *hide_ids = NULL;
+static gint serial = 0;
 
-static void
-lbi_notification_parent_weak_notify(gpointer data, GObject * parent)
+
+static void libbalsa_information_varg(LibBalsaInformationType  type,
+                                                                         const gchar             *hide_id,
+                                                                         const gchar             *fmt,
+                                                                         va_list                  ap);
+static void add_hide_id(GSimpleAction *simple,
+                                               GVariant      *parameter,
+                                               gpointer       user_data);
+
+
+void
+libbalsa_information_init(GApplication *application, const gchar *title, const gchar *notification_id)
+{
+       GActionEntry actions[] = {
+               { "hide-notify", add_hide_id, "s", NULL, NULL },
+       };
+       gint hide_cnt;
+       gchar **hide_list;
+
+       g_return_if_fail(G_IS_APPLICATION(application) && (title != NULL) && (notification_id != NULL));
+
+       g_action_map_add_action_entries(G_ACTION_MAP(application), actions, 1, NULL);
+       notify_app = application;
+       notify_title = title;
+       id_base = notification_id;
+       hide_ids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+       libbalsa_conf_push_group("Notifications");
+       libbalsa_conf_get_vector_with_default("hide", &hide_cnt, &hide_list, NULL);
+       if (hide_list != NULL) {
+               gint n;
+
+               for (n = 0; hide_list[n] != NULL; n++) {
+                       g_hash_table_add(hide_ids, hide_list[n]);
+               }
+               g_free(hide_list);      /* note: strings consumed by the hash table */
+       }
+       libbalsa_conf_pop_group();
+}
+
+void
+libbalsa_information_save_cfg(void)
+{
+       if (g_hash_table_size(hide_ids) > 0U) {
+               gchar **ids;
+               guint count;
+
+               libbalsa_conf_push_group("Notifications");
+               ids = (gchar **) g_hash_table_get_keys_as_array(hide_ids, &count);
+               libbalsa_conf_set_vector("hide", (int) count, (const gchar **) ids);
+               g_free(ids);
+               libbalsa_conf_pop_group();
+       }
+}
+
+void
+libbalsa_information(LibBalsaInformationType type,
+                                        const gchar *fmt, ...)
 {
-    if (notification == NULL)
-        return;
+       va_list va_args;
 
-    g_object_set_data(G_OBJECT(notification), "send", GINT_TO_POINTER(FALSE));
-    g_signal_emit_by_name(notification, "notify", NULL);
+       va_start(va_args, fmt);
+       libbalsa_information_varg(type, NULL, fmt, va_args);
+       va_end(va_args);
 }
 
 void
-libbalsa_information_varg(GtkWindow *parent, LibBalsaInformationType type,
-                          const char *fmt, va_list ap)
+libbalsa_information_may_hide(LibBalsaInformationType type,
+                                                         const gchar *hide_id, const gchar *fmt, ...)
 {
-    gchar *msg;
-    const gchar *icon_str;
-    gboolean send;
+       va_list va_args;
 
-    if (notification == NULL)
-        return;
+       va_start(va_args, fmt);
+       libbalsa_information_varg(type, hide_id, fmt, va_args);
+       va_end(va_args);
+}
+
+void
+libbalsa_information_shutdown(void)
+{
+       gint last_serial;
+
+       if (hide_ids != NULL) {
+               g_hash_table_destroy(hide_ids);
+               hide_ids = NULL;
+       }
+
+       /* withdraw the last notification sent... */
+       last_serial = g_atomic_int_get(&serial);
+       if (last_serial > 0) {
+               gchar *id;
+
+               id = g_strdup_printf("%s%d", id_base, last_serial - 1);
+               g_application_withdraw_notification(notify_app, id);
+               g_free(id);
+       }
+       notify_app = NULL;              /* ...so calling libbalsa_information() later will fail */
+}
+
+static void
+libbalsa_information_varg(LibBalsaInformationType type,
+                                                 const gchar *hide_id,
+                                                 const gchar *fmt, va_list ap)
+{
+       GNotification *notification;
+       gchar *msg;
+       gchar *id;
+       const gchar *icon_str;
 
-    g_return_if_fail(fmt != NULL);
+       g_return_if_fail(G_IS_APPLICATION(notify_app) && (notify_title != NULL) && (id_base != NULL) && (fmt 
!= NULL));
+
+       msg = g_strdup_vprintf(fmt, ap);
+       if ((hide_id != NULL) && g_hash_table_contains(hide_ids, hide_id)) {
+               g_debug("hide notification with id '%s': %s", hide_id, msg);
+               g_free(msg);
+               return;
+       }
 
     switch (type) {
     case LIBBALSA_INFORMATION_MESSAGE:
@@ -65,57 +164,30 @@ libbalsa_information_varg(GtkWindow *parent, LibBalsaInformationType type,
         break;
     }
 
-    if (icon_str != NULL) {
-        GIcon *icon;
-
-       icon = g_themed_icon_new(icon_str);
-       g_notification_set_icon(notification, icon);
-       g_object_unref(icon);
-    }
-
-    msg = g_strdup_vprintf(fmt, ap);
-    g_notification_set_body(notification, msg);
-    send = msg[0] != '\0';
-    g_free(msg);
-
-    g_object_set_data(G_OBJECT(notification), "send", GINT_TO_POINTER(send));
-    g_signal_emit_by_name(notification, "notify", NULL);
-
-    if (parent != NULL) {
-        /* Close with parent if earlier. */
-        g_object_weak_ref(G_OBJECT(parent),
-                          lbi_notification_parent_weak_notify, NULL);
-    }
+       notification = g_notification_new(notify_title);
+       if (icon_str != NULL) {
+               GIcon *icon;
+
+               icon = g_themed_icon_new(icon_str);
+               g_notification_set_icon(notification, icon);
+               g_object_unref(icon);
+       }
+
+       g_notification_set_body(notification, msg);
+       if (hide_id != NULL) {
+               g_notification_add_button_with_target(notification,
+                       _("do not show again"), "app.hide-notify", "s", hide_id);
+       }
+       g_free(msg);
+
+       id = g_strdup_printf("%s%d", id_base, g_atomic_int_add(&serial, 1));
+       g_application_send_notification(notify_app, id, notification);
+       g_free(id);
+       g_object_unref(notification);
 }
 
-void
-libbalsa_information(LibBalsaInformationType type,
-                     const char *fmt, ...)
-{
-    va_list va_args;
-
-    va_start(va_args, fmt);
-    libbalsa_information_varg(NULL, type, fmt, va_args);
-    va_end(va_args);
-}
-
-void
-libbalsa_information_parented(GtkWindow *parent, LibBalsaInformationType type,
-                              const char *fmt, ...)
-{
-    va_list va_args;
-
-    va_start(va_args, fmt);
-    libbalsa_information_varg(parent, type, fmt, va_args);
-    va_end(va_args);
-}
-
-GNotification *
-libbalsa_notification_new(const gchar *title)
+static void
+add_hide_id(GSimpleAction *simple, GVariant *parameter, gpointer G_GNUC_UNUSED user_data)
 {
-    notification = g_notification_new(title);
-
-    g_object_add_weak_pointer(G_OBJECT(notification), (gpointer *) &notification);
-
-    return notification;
+       g_hash_table_add(hide_ids, g_variant_dup_string(parameter, NULL));
 }
diff --git a/libbalsa/information.h b/libbalsa/information.h
index 3caa99835..786cf9743 100644
--- a/libbalsa/information.h
+++ b/libbalsa/information.h
@@ -1,7 +1,7 @@
 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
 /* Balsa E-Mail Client
  *
- * Copyright (C) 1997-2016 Stuart Parmenter and others,
+ * Copyright (C) 1997-2021 Stuart Parmenter and others,
  *                         See the file AUTHORS for a list.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,9 @@
 #ifndef __LIBBALSA_INFORMATION_H__
 #define __LIBBALSA_INFORMATION_H__
 
-#include <gtk/gtk.h>
-#include <stdarg.h>
+
+#include <gio/gio.h>
+
 
 enum _LibBalsaInformationType {
     LIBBALSA_INFORMATION_MESSAGE,
@@ -35,17 +36,64 @@ enum _LibBalsaInformationType {
 typedef enum _LibBalsaInformationType LibBalsaInformationType;
 
 
-void libbalsa_information(LibBalsaInformationType type,
-                          const char *fmt, ...)
+/** \brief Initialise Balsa's desktop notifications
+ *
+ * \param[in] application the Balsa GApplication
+ * \param[in] title the notification title
+ * \param[in] notification_id the notification ID prefix (a unique serial number is added to each 
notification)
+ *
+ * Note that this function also loads the list of Balsa's notification identifiers which shall be hidden.  
No other function from
+ * this module shall be called before calling this function.
+ */
+void libbalsa_information_init(GApplication *application,
+                                                          const gchar  *title,
+                                                          const gchar  *notification_id);
+
+/** \brief Display a desktop notification
+ *
+ * \param[in] type notification type, select the icon
+ * \param[in] fmt printf()-like format string
+ * \param[in] ... additional parameters according to the format string
+ */
+void libbalsa_information(LibBalsaInformationType  type,
+                                                 const gchar             *fmt,
+                                                 ...)
        G_GNUC_PRINTF(2, 3);
-void libbalsa_information_parented(GtkWindow *parent,
-                                   LibBalsaInformationType type,
-                                   const char *fmt, ...)
+
+/** \brief Display a desktop notification which the user may hide
+ *
+ * \param[in] type notification type, select the icon
+ * \param[in] hide_id Balsa's notification identifier, shall not contain the ";" character
+ * \param[in] fmt printf()-like format string
+ * \param[in] ... additional parameters according to the format string
+ *
+ * If the passed notification identifier is in the list of identifiers which shall be hidden the function is 
a no-op.  Otherwise,
+ * it behaves as libbalsa_information(), but adds a button "do not show again" to the notification.  If the 
user clicks the button,
+ * the passed notification identifier is added to an internal exclusion list which is saved in the config 
when
+ * libbalsa_information_save_cfg() is called.
+ */
+void libbalsa_information_may_hide(LibBalsaInformationType  type,
+                                                                  const gchar             *hide_id,
+                                                                  const gchar             *fmt,
+                                                                  ...)
        G_GNUC_PRINTF(3, 4);
-void libbalsa_information_varg(GtkWindow *parent,
-                               LibBalsaInformationType type,
-                               const char *fmt, va_list ap);
 
-GNotification * libbalsa_notification_new(const gchar *title);
+/** \brief Save the list of Balsa's notification identifiers which shall be hidden
+ *
+ * The list is stored in the main config file in the section "Notifications".
+ */
+void libbalsa_information_save_cfg(void);
+
+/** \brief Shut down Balsa's desktop notifications
+ *
+ * If any notifications have been transmitted, the very last one (i.e. Balsa's shutdown message) is 
withdrawn.
+ *
+ * \note When using org.freedesktop.Notifications as backend for desktop notifications, a notification can 
be withdrawn only if the
+ *              backend reported its internal id back to Balsa.  If the time between sending the 
notification by calling
+ *              libbalsa_information() or libbalsa_information_may_hide() and the call to this function is 
too short, the notification is
+ *              hidden by the backend after a time-out or when the user clicks on it.
+ */
+void libbalsa_information_shutdown(void);
+
 
 #endif
diff --git a/libbalsa/mailbox_imap.c b/libbalsa/mailbox_imap.c
index 2d49aef07..a342e21e4 100644
--- a/libbalsa/mailbox_imap.c
+++ b/libbalsa/mailbox_imap.c
@@ -3225,8 +3225,8 @@ libbalsa_mailbox_imap_set_threading(LibBalsaMailbox *mailbox,
                 g_node_copy(imap_mbox_handle_get_thread_root(mimap->handle));
             break;
         } else 
-            libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                            _("Server-side threading not supported."));
+            libbalsa_information_may_hide(LIBBALSA_INFORMATION_WARNING,
+               "LBIMAP_SSTH", _("Server-side threading not supported."));
         /* fall through */
     case LB_MAILBOX_THREADING_FLAT:
         if(filter) {
diff --git a/src/ab-main.c b/src/ab-main.c
index 725291c5f..90afddc94 100644
--- a/src/ab-main.c
+++ b/src/ab-main.c
@@ -1063,38 +1063,6 @@ libbalsa_dialog_flags(void)
 
 #define BALSA_AB_NOTIFICATION "balsa-ab-notification"
 
-static void
-balsa_ab_notification_notify_cb(GNotification *notification, GApplication *application)
-{
-    gboolean send;
-
-    send = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), "send"));
-    if (send) {
-        g_application_send_notification(application,
-                                        BALSA_AB_NOTIFICATION, notification);
-    } else {
-        g_application_withdraw_notification(application, BALSA_AB_NOTIFICATION);
-    }
-}
-
-static void
-balsa_ab_notification_shutdown_cb(GApplication *application, GNotification *notification)
-{
-    g_object_unref(notification);
-}
-
-static void
-balsa_ab_setup_libbalsa_notification(GApplication *application)
-{
-    GNotification *notification;
-
-    notification = libbalsa_notification_new("BalsaAb");
-    g_signal_connect(notification, "notify",
-                     G_CALLBACK(balsa_ab_notification_notify_cb), application);
-    g_signal_connect(application, "shutdown",
-                     G_CALLBACK(balsa_ab_notification_shutdown_cb), notification);
-}
-
 int
 main(int argc, char *argv[])
 {
@@ -1124,7 +1092,8 @@ main(int argc, char *argv[])
 #endif
 
     bab_init();
-    balsa_ab_setup_libbalsa_notification((GApplication *) application);
+    libbalsa_information_init(G_APPLICATION(application),
+       _("Balsa Address Book"), BALSA_AB_NOTIFICATION);
     g_mime_init();
     libbalsa_parser_options_init();
 
diff --git a/src/balsa-app.c b/src/balsa-app.c
index f50e747e3..7c227cda4 100644
--- a/src/balsa-app.c
+++ b/src/balsa-app.c
@@ -940,3 +940,20 @@ balsa_quote_regex_new(void)
 
     return g_regex_ref(regex);
 }
+
+gboolean
+balsa_autocrypt_in_use(void)
+{
+       gboolean result = FALSE;
+#ifdef ENABLE_AUTOCRYPT
+       GList *ident;
+
+       for (ident = balsa_app.identities; !result && (ident != NULL); ident = ident->next) {
+                LibBalsaIdentity *identity = LIBBALSA_IDENTITY(ident->data);
+                AutocryptMode autocrypt_mode = libbalsa_identity_get_autocrypt_mode(identity);
+               result = autocrypt_mode != AUTOCRYPT_DISABLE;
+       }
+#endif  /* ENABLE_AUTOCRYPT */
+       return result;
+}
+
diff --git a/src/balsa-app.h b/src/balsa-app.h
index 49a16bed4..2d51b2a36 100644
--- a/src/balsa-app.h
+++ b/src/balsa-app.h
@@ -403,4 +403,7 @@ void  balsa_remove_children_mailbox_nodes(BalsaMailboxNode * mbnode);
 
 GRegex *balsa_quote_regex_new(void);
 
+/* return TRUE iff Balsa is built with Autocrypt support and any identity uses it */
+gboolean balsa_autocrypt_in_use(void);
+
 #endif                         /* __BALSA_APP_H__ */
diff --git a/src/balsa-message.c b/src/balsa-message.c
index a024f8639..628b879c8 100644
--- a/src/balsa-message.c
+++ b/src/balsa-message.c
@@ -147,10 +147,6 @@ static GdkPixbuf * get_crypto_content_icon(LibBalsaMessageBody * body,
                                           const gchar * content_type,
                                           gchar ** icon_title);
 
-#ifdef ENABLE_AUTOCRYPT
-static inline gboolean autocrypt_in_use(void);
-#endif
-
 G_DEFINE_TYPE(BalsaPartInfo, balsa_part_info, G_TYPE_OBJECT)
 
 static void
@@ -1179,7 +1175,7 @@ balsa_message_set(BalsaMessage * balsa_message, LibBalsaMailbox * mailbox, guint
 
 #ifdef ENABLE_AUTOCRYPT
     /* check for Autocrypt information if the message is new only */
-    if (is_new && autocrypt_in_use()) {
+    if (is_new && balsa_autocrypt_in_use()) {
        GError *error = NULL;
 
        autocrypt_from_message(message, &error);
@@ -2963,13 +2959,13 @@ libbalsa_msg_try_mp_signed(LibBalsaMessage * message, LibBalsaMessageBody *body,
            break;
        case LIBBALSA_MSG_PROTECT_SIGN_NOTRUST:
            if (g_mime_gpgme_sigstat_protocol(body->parts->next->sig_info) == GPGME_PROTOCOL_CMS)
-               libbalsa_information
-                   (LIBBALSA_INFORMATION_MESSAGE,
+               libbalsa_information_may_hide
+                   (LIBBALSA_INFORMATION_MESSAGE, "SIG_NOTRUST",
                     _("Detected a good signature with insufficient "
                       "validity"));
            else
-               libbalsa_information
-                   (LIBBALSA_INFORMATION_MESSAGE,
+               libbalsa_information_may_hide
+                   (LIBBALSA_INFORMATION_MESSAGE, "SIG_NOTRUST",
                     _("Detected a good signature with insufficient "
                       "validity/trust"));
            break;
@@ -3093,8 +3089,8 @@ libbalsa_msg_part_2440(LibBalsaMessage * message, LibBalsaMessageBody * body,
         if ((g_mime_gpgme_sigstat_summary(body->sig_info) & GPGME_SIGSUM_VALID) == GPGME_SIGSUM_VALID) {
                g_debug("%s: detected a good signature", __func__);
         } else {
-            libbalsa_information
-               (LIBBALSA_INFORMATION_MESSAGE,
+            libbalsa_information_may_hide
+               (LIBBALSA_INFORMATION_MESSAGE, "SIG_NOTRUST",
                 _("Detected a good signature with insufficient "
                   "validity/trust"));
         }
@@ -3321,22 +3317,6 @@ balsa_message_find_in_message(BalsaMessage * balsa_message)
     }
 }
 
-#ifdef ENABLE_AUTOCRYPT
-static inline gboolean
-autocrypt_in_use(void)
-{
-       gboolean result = FALSE;
-       GList *ident;
-
-       for (ident = balsa_app.identities; !result && (ident != NULL); ident = ident->next) {
-                LibBalsaIdentity *identity = LIBBALSA_IDENTITY(ident->data);
-                AutocryptMode autocrypt_mode = libbalsa_identity_get_autocrypt_mode(identity);
-               result = autocrypt_mode != AUTOCRYPT_DISABLE;
-       }
-       return result;
-}
-#endif
-
 /*
  * Getters
  */
diff --git a/src/balsa-mime-widget-crypto.c b/src/balsa-mime-widget-crypto.c
index fd12095e8..3ff4f3e6e 100644
--- a/src/balsa-mime-widget-crypto.c
+++ b/src/balsa-mime-widget-crypto.c
@@ -144,9 +144,15 @@ balsa_mime_widget_signature_widget(LibBalsaMessageBody * mime_body,
                        g_signal_connect(button, "clicked", G_CALLBACK(on_key_import_button), NULL);
                        gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
                } else if (libbalsa_message_get_headers(mime_body->message)->autocrypt_hdr_present) {
-                       libbalsa_information(LIBBALSA_INFORMATION_WARNING,
-                               _("The message contains an Autocrypt header, but it is either broken "
-                                 "or the signature has been created using a different key."));
+                       if (balsa_autocrypt_in_use()) {
+                               libbalsa_information(LIBBALSA_INFORMATION_WARNING,
+                                       _("The message contains an Autocrypt header, but it is either broken "
+                                         "or the signature has been created using a different key."));
+                       } else {
+                               libbalsa_information_may_hide(LIBBALSA_INFORMATION_MESSAGE, "ACRYPT_OFF",
+                                       _("The message contains an Autocrypt header which is ignored as none "
+                                         "of your identities has Autocrypt support enabled."));
+                       }
                }
 #endif
             button = gtk_button_new_with_mnemonic(_("_Search key server for this key"));
diff --git a/src/mailbox-node.c b/src/mailbox-node.c
index 03dd11189..e43a4ee6b 100644
--- a/src/mailbox-node.c
+++ b/src/mailbox-node.c
@@ -960,8 +960,7 @@ mb_filter_cb(GtkWidget * widget, BalsaMailboxNode * mbnode)
           problems of infinite recursion (when one mailbox being
           filtered is also the destination of the filter action (eg a
           copy)). So let's see that later :) */
-       libbalsa_information_parented(GTK_WINDOW(balsa_app.main_window),
-               LIBBALSA_INFORMATION_MESSAGE, _("You can apply filters only on mailbox"));
+       libbalsa_information(LIBBALSA_INFORMATION_MESSAGE, _("You can apply filters only on mailbox"));
 }
 
 static void
diff --git a/src/main-window.c b/src/main-window.c
index e20a90b56..e013e7ea5 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -1098,10 +1098,12 @@ quit_activated(GSimpleAction * action,
     GdkEventAny e = { GDK_DELETE, NULL, 0 };
 
     e.window = gtk_widget_get_window(GTK_WIDGET(window));
-    libbalsa_information_parented(NULL, /* to outlive the window */
-                                  LIBBALSA_INFORMATION_MESSAGE,
-                                  _("Balsa closes files and connections."
-                                    " Please wait…"));
+    libbalsa_information(LIBBALSA_INFORMATION_MESSAGE,
+       _("Balsa closes files and connections. Please wait…"));
+    /* note: add a small delay to ensure that the notification ID has been
+     * reported back to us if we use the org.freedesktop.Notifications
+     * interface - otherwise, it is apparently impossible to withdraw it. */
+    g_usleep(1000);
     while(gtk_events_pending())
         gtk_main_iteration_do(FALSE);
     gdk_event_put((GdkEvent*)&e);
diff --git a/src/main.c b/src/main.c
index 3fc45220d..cc4c532d0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -474,40 +474,9 @@ balsa_check_open_compose_window(void)
     return FALSE;
 }
 
-/*
- * Set up GNotification for libbalsa
- */
 
 #define BALSA_NOTIFICATION "balsa-notification"
 
-static void
-balsa_notification_notify_cb(GNotification *notification,
-                             GParamSpec *pspec,
-                             GApplication *application)
-{
-    gboolean send;
-
-    send = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(notification), "send"));
-    if (send) {
-        g_application_send_notification(application,
-                                        BALSA_NOTIFICATION, notification);
-    } else {
-        g_application_withdraw_notification(application, BALSA_NOTIFICATION);
-    }
-}
-
-static void
-balsa_setup_libbalsa_notification(GApplication *application)
-{
-    GNotification *notification;
-
-    notification = libbalsa_notification_new("Balsa");
-    g_signal_connect(notification, "notify",
-                     G_CALLBACK(balsa_notification_notify_cb), application);
-    g_signal_connect_swapped(application, "shutdown",
-                             G_CALLBACK(g_object_unref), notification);
-}
-
 /* -------------------------- main --------------------------------- */
 static void
 balsa_startup_cb(GApplication *application,
@@ -543,7 +512,7 @@ balsa_startup_cb(GApplication *application,
     balsa_app_init();
 
     /* Initialize libbalsa */
-    balsa_setup_libbalsa_notification(application);
+    libbalsa_information_init(application, "Balsa", BALSA_NOTIFICATION);
     libbalsa_init();
     libbalsa_filters_set_url_mapper(balsa_find_mailbox_by_url);
     libbalsa_filters_set_filter_list(&balsa_app.filters);
@@ -586,7 +555,7 @@ balsa_shutdown_cb(void)
     libbalsa_conf_drop_all();
     accel_map_save();
     libbalsa_imap_server_close_all_connections();
-    libbalsa_information(LIBBALSA_INFORMATION_MESSAGE, "%s", "");
+    libbalsa_information_shutdown();
 }
 
 static void
diff --git a/src/save-restore.c b/src/save-restore.c
index 223fe6390..0c5bae90a 100644
--- a/src/save-restore.c
+++ b/src/save-restore.c
@@ -1542,6 +1542,9 @@ config_save(void)
     save_mru(balsa_app.fcc_mru,    "FccMRU");
     save_mru(balsa_app.pipe_cmds,  "PipeCommands");
 
+    /* disabled desktop notifications */
+    libbalsa_information_save_cfg();
+
     libbalsa_conf_sync();
     return TRUE;
 }                              /* config_global_save */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]