[geary/mjog/plugin-support: 5/5] Convert Notification.Desktop to a plugin



commit b28595067268ed9280f6cb660faac00fc05e2fb9
Author: Michael Gratton <mike vee net>
Date:   Fri Sep 27 02:51:05 2019 +1000

    Convert Notification.Desktop to a plugin
    
    Rename to DesktopNotifications and use Plugins.Notification as the base
    class. Add a plugin config file. Add build config to build the plugin.
    Update Plugins.Notification class to suit the requirements of this
    plugin better.

 po/POTFILES.in                                     |   3 +-
 src/client/application/application-controller.vala |  11 +--
 .../application/application-plugin-manager.vala    |  16 +++-
 src/client/application/geary-application.vala      |  31 ++++++-
 src/client/meson.build                             |   3 +-
 .../desktop-notifications.plugin.in                |   5 +
 .../desktop-notifications.vala}                    | 102 ++++++++++-----------
 .../plugin/desktop-notifications/meson.build       |  24 +++++
 src/client/plugin/meson.build                      |  25 +++++
 src/client/plugin/plugin-notification.vala         |   7 +-
 src/meson.build                                    |   1 +
 11 files changed, 159 insertions(+), 69 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4cb50a03..dc81032e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -80,9 +80,10 @@ src/client/folder-list/folder-list-tree.vala
 src/client/notification/in-app-notification.vala
 src/client/notification/libmessagingmenu.vala
 src/client/notification/new-messages-indicator.vala
-src/client/notification/notification-desktop.vala
 src/client/notification/null-indicator.vala
 src/client/notification/unity-launcher.vala
+src/client/plugin/desktop-notifications/desktop-notifications.vala
+src/client/plugin/desktop-notifications/desktop-notifications.desktop.in
 src/client/plugin/plugin-notification.vala
 src/client/sidebar/sidebar-branch.vala
 src/client/sidebar/sidebar-common.vala
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index 717930a6..ccf33407 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -127,9 +127,6 @@ public class Application.Controller : Geary.BaseObject {
         get; private set;
     }
 
-    /** Desktop notifications for the application. */
-    public Notification.Desktop notifications { get; private set; }
-
     /** Avatar store for the application. */
     public Application.AvatarStore avatars {
         get; private set; default = new Application.AvatarStore();
@@ -321,12 +318,6 @@ public class Application.Controller : Geary.BaseObject {
 
         this.unity_launcher = new UnityLauncher(this.plugin_manager.notifications);
 
-        this.notifications = new Notification.Desktop(
-            this.plugin_manager.notifications,
-            this.application,
-            cancellable
-        );
-
         this.main_window.conversation_list_view.grab_focus();
 
         // initialize revokable
@@ -553,7 +544,7 @@ public class Application.Controller : Geary.BaseObject {
         Geary.ServiceProblemReport? service_report =
             report as Geary.ServiceProblemReport;
         if (service_report != null && service_report.service.protocol == SMTP) {
-            this.notifications.set_error_notification(
+            this.application.send_error_notification(
                 /// Notification title.
                 _("A problem occurred sending email for %s").printf(
                     service_report.account.display_name
diff --git a/src/client/application/application-plugin-manager.vala 
b/src/client/application/application-plugin-manager.vala
index 85421982..58951b19 100644
--- a/src/client/application/application-plugin-manager.vala
+++ b/src/client/application/application-plugin-manager.vala
@@ -15,6 +15,7 @@ public class Application.PluginManager : GLib.Object {
 
     private Peas.Engine engine;
     private Peas.ExtensionSet? notification_extensions = null;
+    private bool is_shutdown = false;
 
 
     public PluginManager(GLib.File app_plugin_dir) {
@@ -32,13 +33,22 @@ public class Application.PluginManager : GLib.Object {
                 (extension as Plugin.Notification).activate();
             });
         this.notification_extensions.extension_removed.connect((info, extension) => {
-                (extension as Plugin.Notification).deactivate();
+                (extension as Plugin.Notification).deactivate(this.is_shutdown);
             });
 
         // Load built-in plugins by default
         foreach (Peas.PluginInfo info in this.engine.get_plugin_list()) {
-            if (info.is_builtin()) {
-                this.engine.load_plugin(info);
+            try {
+                info.is_available();
+                if (info.is_builtin()) {
+                    debug("Loading built-in plugin: %s", info.get_name());
+                    this.engine.load_plugin(info);
+                } else {
+                    debug("Not loading plugin: %s", info.get_name());
+                }
+            } catch (GLib.Error err) {
+                warning("Plugin %s not available: %s",
+                        info.get_name(), err.message);
             }
         }
     }
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index f09da89d..5746ad0c 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -161,6 +161,9 @@ public class GearyApplication : Gtk.Application {
     private const int64 USEC_PER_SEC = 1000000;
     private const int64 FORCE_SHUTDOWN_USEC = 5 * USEC_PER_SEC;
 
+    private const string ERROR_NOTIFICATION_ID = "error";
+
+
 
     /** Object returned by {@link get_runtime_information}. */
     public struct RuntimeDetail {
@@ -265,6 +268,7 @@ public class GearyApplication : Gtk.Application {
     private GLib.Cancellable controller_cancellable = new GLib.Cancellable();
     private Components.Inspector? inspector = null;
     private Geary.Nonblocking.Mutex controller_mutex = new Geary.Nonblocking.Mutex();
+    private GLib.Notification? error_notification = null;
 
 
     /**
@@ -625,7 +629,8 @@ public class GearyApplication : Gtk.Application {
     public GLib.File get_app_plugins_dir() {
         return (is_installed)
             ? GLib.File.new_for_path(_PLUGINS_DIR)
-            : GLib.File.new_for_path(BUILD_ROOT_DIR).get_child("src");
+            : GLib.File.new_for_path(BUILD_ROOT_DIR)
+                  .get_child("src").get_child("client").get_child("plugin");
     }
 
     /** Displays a URI on the current active window, if any. */
@@ -701,6 +706,30 @@ public class GearyApplication : Gtk.Application {
         Posix.exit(1);
     }
 
+    /**
+     * Displays an error notification.
+     *
+     * Use _very_ sparingly.
+     */
+    internal void send_error_notification(string summary, string body) {
+        if (this.error_notification != null) {
+            clear_error_notification();
+        }
+
+        GLib.Notification error = new GLib.Notification(summary);
+        error.set_body(body);
+        error.set_icon(
+            new GLib.ThemedIcon("%s-symbolic".printf(GearyApplication.APP_ID))
+        );
+        send_notification(ERROR_NOTIFICATION_ID, error);
+        this.error_notification = error;
+    }
+
+    internal void clear_error_notification() {
+        this.error_notification = null;
+        withdraw_notification(ERROR_NOTIFICATION_ID);
+    }
+
     // Presents a main window. If the controller is not open, opens it
     // first.
     private async void present() {
diff --git a/src/client/meson.build b/src/client/meson.build
index 6e0e3d7f..015d28eb 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -84,7 +84,6 @@ geary_client_vala_sources = files(
   'folder-list/folder-list-search-branch.vala',
   'folder-list/folder-list-special-grouping.vala',
 
-  'notification/notification-desktop.vala',
   'notification/in-app-notification.vala',
   'notification/libmessagingmenu.vala',
   'notification/new-messages-indicator.vala',
@@ -175,3 +174,5 @@ geary_client_dep = declare_dependency(
   link_with: geary_client_lib,
   include_directories: include_directories('.'),
 )
+
+subdir('plugin')
diff --git a/src/client/plugin/desktop-notifications/desktop-notifications.plugin.in 
b/src/client/plugin/desktop-notifications/desktop-notifications.plugin.in
new file mode 100644
index 00000000..837778b9
--- /dev/null
+++ b/src/client/plugin/desktop-notifications/desktop-notifications.plugin.in
@@ -0,0 +1,5 @@
+[Plugin]
+Module=libdesktop-notifications.so
+Name=Desktop Notifications
+Description=Displays desktop notifications when new email is delivered
+Builtin=true
diff --git a/src/client/notification/notification-desktop.vala 
b/src/client/plugin/desktop-notifications/desktop-notifications.vala
similarity index 70%
rename from src/client/notification/notification-desktop.vala
rename to src/client/plugin/desktop-notifications/desktop-notifications.vala
index 057321ce..752569fc 100644
--- a/src/client/notification/notification-desktop.vala
+++ b/src/client/plugin/desktop-notifications/desktop-notifications.vala
@@ -1,80 +1,79 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2019 Michael Gratton <mike vee net>.
  *
  * This software is licensed under the GNU Lesser General Public License
- * (version 2.1 or later).  See the COPYING file in this distribution.
+ * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
+[ModuleInit]
+public void peas_register_types(TypeModule module) {
+    Peas.ObjectModule obj = module as Peas.ObjectModule;
+    obj.register_extension_type(
+        typeof(Plugin.Notification),
+        typeof(Plugin.DesktopNotifications)
+    );
+}
+
 /**
  * Manages standard desktop application notifications.
  */
-public class Notification.Desktop : Geary.BaseObject {
+public class Plugin.DesktopNotifications : Notification {
 
 
     public const Geary.Email.Field REQUIRED_FIELDS =
         Geary.Email.Field.ORIGINATORS | Geary.Email.Field.SUBJECT;
 
+    public override Application.NotificationContext context {
+        get; construct set;
+    }
+
+    public override GearyApplication application {
+        get; construct set;
+    }
+
     private const string ARRIVED_ID = "email-arrived";
-    private const string ERROR_ID = "error";
 
-    private weak Application.NotificationContext monitor;
-    private weak GearyApplication application;
     private GLib.Notification? arrived_notification = null;
-    private GLib.Notification? error_notification = null;
-    private GLib.Cancellable load_cancellable;
-
+    private GLib.Cancellable? cancellable = null;
 
-    public Desktop(Application.NotificationContext monitor,
-                   GearyApplication application,
-                   GLib.Cancellable load_cancellable) {
-        this.monitor = monitor;
-        this.application = application;
-        this.load_cancellable = load_cancellable;
 
-        this.monitor.add_required_fields(REQUIRED_FIELDS);
-        this.monitor.new_messages_arrived.connect(on_new_messages_arrived);
+    public override void activate() {
+        debug("Activating plugin");
+        this.context.add_required_fields(REQUIRED_FIELDS);
+        this.context.new_messages_arrived.connect(on_new_messages_arrived);
+        this.cancellable = new GLib.Cancellable();
     }
 
-    ~Desktop() {
-        this.load_cancellable.cancel();
-        this.monitor.new_messages_arrived.disconnect(on_new_messages_arrived);
-    }
+    public override void deactivate(bool is_shutdown) {
+        debug("Deactivating plugin");
+        this.cancellable.cancel();
+        this.context.new_messages_arrived.disconnect(on_new_messages_arrived);
+        this.context.remove_required_fields(REQUIRED_FIELDS);
 
-    public void clear_all_notifications() {
-        clear_arrived_notification();
-        clear_error_notification();
+        // Keep existing notifications if shutting down since they are
+        // persistent, but revoke if the plugin is being disabled.
+        if (!is_shutdown) {
+            clear_arrived_notification();
+        }
     }
 
-    public void clear_arrived_notification() {
+    private void clear_arrived_notification() {
         this.application.withdraw_notification(ARRIVED_ID);
         this.arrived_notification = null;
     }
 
-    public void set_error_notification(string summary, string body) {
-        // Only one error at a time, guys.  (This means subsequent errors will
-        // be dropped.  Since this is only used for one thing now, that's ok,
-        // but it means in the future, a more robust system will be needed.)
-        if (this.error_notification == null) {
-            this.error_notification = issue_notification(
-                ERROR_ID, summary, body, null, null
-            );
-        }
-    }
-
-    public void clear_error_notification() {
-        this.error_notification = null;
-        this.application.withdraw_notification(ERROR_ID);
-    }
-
     private void on_new_messages_arrived(Geary.Folder folder,
                                          int total,
                                          int added) {
+        debug("new mail!");
         if (added == 1 &&
-            monitor.last_new_message_folder != null &&
-            monitor.last_new_message != null) {
+            this.context.last_new_message_folder != null &&
+            this.context.last_new_message != null) {
             this.notify_one_message.begin(
-                monitor.last_new_message_folder,
-                monitor.last_new_message,
-                this.load_cancellable
+                this.context.last_new_message_folder,
+                this.context.last_new_message,
+                this.cancellable
             );
         } else if (added > 0) {
             notify_new_mail(folder, added);
@@ -82,8 +81,7 @@ public class Notification.Desktop : Geary.BaseObject {
     }
 
     private void notify_new_mail(Geary.Folder folder, int added) {
-        if (this.application.config.show_notifications &&
-            this.monitor.should_notify_new_messages(folder)) {
+        if (this.context.should_notify_new_messages(folder)) {
             string body = ngettext(
                 /// Notification body text for new email when no other
                 /// new messages are already awaiting.
@@ -92,7 +90,7 @@ public class Notification.Desktop : Geary.BaseObject {
 
             int total = 0;
             try {
-                total = monitor.get_new_message_count(folder);
+                total = this.context.get_new_message_count(folder);
             } catch (Geary.EngineError.NOT_FOUND err) {
                 // All good
             }
@@ -120,17 +118,17 @@ public class Notification.Desktop : Geary.BaseObject {
         Geary.RFC822.MailboxAddress? originator =
             Util.Email.get_primary_originator(email);
         if (this.application.config.show_notifications &&
-            this.monitor.should_notify_new_messages(folder) &&
+            this.context.should_notify_new_messages(folder) &&
             originator != null) {
             Application.ContactStore contacts =
-                this.monitor.get_contact_store(folder.account);
+                this.context.get_contact_store(folder.account);
             Application.Contact contact = yield contacts.load(
                 originator, cancellable
             );
 
             int count = -1;
             try {
-                count = monitor.get_new_message_count(folder);
+                count = this.context.get_new_message_count(folder);
             } catch (Geary.EngineError.NOT_FOUND err) {
                 // All good
             }
diff --git a/src/client/plugin/desktop-notifications/meson.build 
b/src/client/plugin/desktop-notifications/meson.build
new file mode 100644
index 00000000..06b9b8e8
--- /dev/null
+++ b/src/client/plugin/desktop-notifications/meson.build
@@ -0,0 +1,24 @@
+
+plugin_name = 'desktop-notifications'
+
+plugin_src = join_paths(plugin_name + '.vala')
+plugin_data = join_paths(plugin_name + '.plugin')
+plugin_dest = join_paths(plugins_dir, plugin_name)
+
+shared_module(
+  plugin_name,
+  sources: plugin_src,
+  dependencies: plugin_dependencies,
+  c_args: plugin_cflags,
+  install: true,
+  install_dir: plugin_dest
+)
+
+i18n.merge_file(
+  input: plugin_data + '.in',
+  output: plugin_data,
+  type: 'desktop',
+  po_dir: po_dir,
+  install: true,
+  install_dir: plugin_dest
+)
diff --git a/src/client/plugin/meson.build b/src/client/plugin/meson.build
new file mode 100644
index 00000000..4826545b
--- /dev/null
+++ b/src/client/plugin/meson.build
@@ -0,0 +1,25 @@
+#
+# Builds individual plugins. The client's plugin classes themselves
+# are built at the next directory back up the tree.
+#
+
+plugin_dependencies = [
+  folks,
+  gdk,
+  geary_client_dep,
+  geary_engine_dep,
+  gee,
+  gmime,
+  goa,
+  gtk,
+  javascriptcoregtk,
+  libhandy,
+  libmath,
+  libpeas,
+  libsoup,
+  webkit2gtk,
+]
+
+plugin_cflags = geary_c_options
+
+subdir('desktop-notifications')
diff --git a/src/client/plugin/plugin-notification.vala b/src/client/plugin/plugin-notification.vala
index 92e825fc..98357031 100644
--- a/src/client/plugin/plugin-notification.vala
+++ b/src/client/plugin/plugin-notification.vala
@@ -15,10 +15,15 @@ public abstract class Plugin.Notification : Geary.BaseObject {
         get; construct set;
     }
 
+    /** The application instance containing the plugin. */
+    public abstract GearyApplication application {
+        get; construct set;
+    }
+
     /* Invoked to activate the plugin, after loading. */
     public abstract void activate();
 
     /* Invoked to deactivate the plugin, prior to unloading */
-    public abstract void deactivate();
+    public abstract void deactivate(bool is_shutdown);
 
 }
diff --git a/src/meson.build b/src/meson.build
index 050e2368..4f8c4fa3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -72,6 +72,7 @@ geary_bin_dependencies = [
   javascriptcoregtk,
   libhandy,
   libmath,
+  libpeas,
   libsoup,
   webkit2gtk,
 ]


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