[geary] Start notifying of new mail at session startup: Bug #714644



commit 6783c2ce632cd1cc949e74395e0139c882758e67
Author: Mohamed Ibrahim <mohamed ib md gmail com>
Date:   Thu Jun 26 13:31:43 2014 -0700

    Start notifying of new mail at session startup: Bug #714644
    
    Geary can now be configured to notify of new mail at startup.  When
    the user logs in, Geary will autostart with a hidden window and
    notify of new mail as usual.  When Geary is formally executed by
    the user the Geary window simply appears.
    
    In this mode, if the user closes the window Geary will return to its
    hidden state.  Quit must be used to close the process.

 THANKS                                        |    1 +
 cmake/FindIntltool.cmake                      |    7 ++
 desktop/CMakeLists.txt                        |    2 +
 desktop/geary-autostart.desktop.in            |   15 ++++
 desktop/org.yorba.geary.gschema.xml           |    5 ++
 po/POTFILES.in                                |    1 +
 src/CMakeLists.txt                            |    1 +
 src/client/application/autostart-manager.vala |   90 +++++++++++++++++++++++++
 src/client/application/geary-application.vala |    6 ++-
 src/client/application/geary-args.vala        |    2 +
 src/client/application/geary-config.vala      |    6 ++
 src/client/application/geary-controller.vala  |    7 ++-
 src/client/components/main-window.vala        |    3 +
 src/client/dialogs/preferences-dialog.vala    |    3 +
 ui/preferences.glade                          |   21 ++++++
 15 files changed, 168 insertions(+), 2 deletions(-)
---
diff --git a/THANKS b/THANKS
index 1028885..007ab81 100644
--- a/THANKS
+++ b/THANKS
@@ -17,6 +17,7 @@ Michael George <mdgeorge cs cornell edu>
 Michael Gratton <mike vee net>
 Sven Hagemann <sven rednose nl>
 Mathias Hasselmann <mathias openismus com>
+Mohamed Ibrahim <mohamed ib md gmail com>
 Timo Kluck <tkluck infty nl>
 Charles Lehner <rdm cel celehner com>
 Avi Levy <avi w levy gmail com>
diff --git a/cmake/FindIntltool.cmake b/cmake/FindIntltool.cmake
index 700a9bc..ac45ce9 100644
--- a/cmake/FindIntltool.cmake
+++ b/cmake/FindIntltool.cmake
@@ -19,5 +19,12 @@ if (INTLTOOL_MERGE_FOUND)
         )
         install (FILES ${CMAKE_CURRENT_BINARY_DIR}/geary.desktop DESTINATION 
${CMAKE_INSTALL_PREFIX}/share/applications) 
     endmacro (INTLTOOL_MERGE_DESKTOP desktop_id po_dir)
+    macro (INTLTOOL_MERGE_AUTOSTART_DESKTOP desktop_id po_dir)
+        add_custom_target (geary-autostart.desktop ALL
+            ${INTLTOOL_MERGE_EXECUTABLE} --desktop-style ${CMAKE_SOURCE_DIR}/${po_dir}
+                ${CMAKE_CURRENT_SOURCE_DIR}/${desktop_id}.desktop.in ${desktop_id}.desktop
+        )
+        install (FILES ${CMAKE_CURRENT_BINARY_DIR}/geary-autostart.desktop DESTINATION 
${CMAKE_INSTALL_PREFIX}/share/applications)
+    endmacro (INTLTOOL_MERGE_AUTOSTART_DESKTOP desktop_id po_dir)
 endif (INTLTOOL_MERGE_FOUND)
 
diff --git a/desktop/CMakeLists.txt b/desktop/CMakeLists.txt
index e0214b4..e37988f 100644
--- a/desktop/CMakeLists.txt
+++ b/desktop/CMakeLists.txt
@@ -8,10 +8,12 @@ include (FindIntltool)
 include (FindDesktopFileValidate)
 if (INTLTOOL_MERGE_FOUND)
     INTLTOOL_MERGE_DESKTOP (geary po)
+    INTLTOOL_MERGE_AUTOSTART_DESKTOP (geary-autostart po)
     
     if (DESKTOP_VALIDATE)
         if (DESKTOP_FILE_VALIDATE_FOUND)
             VALIDATE_DESKTOP_FILE (geary)
+            VALIDATE_DESKTOP_FILE (geary-autostart)
         else (DESKTOP_FILE_VALIDATE_FOUND)
             message (FATAL_ERROR "desktop-file-validate must be installed to validate generated .desktop 
file")
         endif (DESKTOP_FILE_VALIDATE_FOUND)
diff --git a/desktop/geary-autostart.desktop.in b/desktop/geary-autostart.desktop.in
new file mode 100644
index 0000000..7ded47f
--- /dev/null
+++ b/desktop/geary-autostart.desktop.in
@@ -0,0 +1,15 @@
+[Desktop Entry]
+_Name=Geary
+_GenericName=Mail Client
+_X-GNOME-FullName=Geary Mail
+_Comment=Send and receive email
+_Keywords=Email;E-mail;Mail;
+Icon=geary
+TryExec=geary
+Exec=geary --hidden
+Type=Application
+Terminal=false
+Categories=GNOME;GTK;Network;Email;
+MimeType=x-scheme-handler/mailto;
+StartupNotify=true
+NoDisplay=true
diff --git a/desktop/org.yorba.geary.gschema.xml b/desktop/org.yorba.geary.gschema.xml
index 022a094..b619d13 100644
--- a/desktop/org.yorba.geary.gschema.xml
+++ b/desktop/org.yorba.geary.gschema.xml
@@ -59,6 +59,11 @@
         <summary>show notifications for new mail</summary>
         <description>True to show notification bubbles.</description>
     </key>
+    <key name="startup-notifications" type="b">
+        <default>false</default>
+        <summary>notify of new mail at startup</summary>
+        <description>True to notify of new mail at startup.</description>
+    </key>
     <key name="ask-open-attachment" type="b">
         <default>true</default>
         <summary>ask when opening an attachment</summary>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4e11a57..8679e35 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,6 @@
 [encoding: UTF-8]
 desktop/geary.desktop.in
+desktop/geary-autostart.desktop.in
 src/client/accounts/account-dialog-account-list-pane.vala
 src/client/accounts/account-dialog-add-edit-pane.vala
 src/client/accounts/account-dialog-pane.vala
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d08f30a..54e10da 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -291,6 +291,7 @@ engine/util/util-trillian.vala
 )
 
 set(CLIENT_SRC
+client/application/autostart-manager.vala
 client/application/geary-action-adapter.vala
 client/application/geary-application.vala
 client/application/geary-args.vala
diff --git a/src/client/application/autostart-manager.vala b/src/client/application/autostart-manager.vala
new file mode 100644
index 0000000..466b56c
--- /dev/null
+++ b/src/client/application/autostart-manager.vala
@@ -0,0 +1,90 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+/*
+ * A simple class for manipulating autostarting Geary as a hidden application through a simple
+ * desktop file at $HOME/.config/autostart/geary.desktop
+ */
+public class AutostartManager : Object {
+    private const string AUTOSTART_FOLDER = "autostart";
+    private const string AUTOSTART_DESKTOP_FILE = "geary-autostart.desktop";
+
+    private File startup_file; // Startup '.desktop' file
+
+    public AutostartManager() {
+        startup_file = File.new_for_path(Environment.get_user_config_dir()).get_child(AUTOSTART_FOLDER)
+            .get_child(AUTOSTART_DESKTOP_FILE);
+        
+        // Connect startup-notifications option callback
+        GearyApplication.instance.config.settings.changed[Configuration.STARTUP_NOTIFICATIONS_KEY].connect(
+            on_startup_notification_change);
+    }
+
+    /**
+     * Returns the system-wide autostart desktop file
+     */
+    public File? get_autostart_desktop_file() {
+        File? install_dir = GearyApplication.instance.get_install_dir();
+        File desktop_file = (install_dir != null)
+            ? install_dir.get_child("share").get_child("applications").get_child(AUTOSTART_DESKTOP_FILE)
+            : 
File.new_for_path(GearyApplication.SOURCE_ROOT_DIR).get_child("build").get_child("desktop").get_child(AUTOSTART_DESKTOP_FILE);
+        
+        return desktop_file.query_exists() ? desktop_file : null;
+    }
+
+    /**
+     * Deletes the desktop file from autostart directory.
+     */
+    public void delete_startup_file() {
+        if (startup_file.query_exists()) {
+            try {
+                startup_file.delete();
+            } catch (Error err) {
+                message("Failed to delete startup file: %s", err.message);
+            }
+        }
+    }
+
+    /**
+     * Creates .desktop file in autostart directory (usually '$HOME/.config/autostart/') if no one exists.
+     */
+    public void create_startup_file() {
+        if (startup_file.query_exists())
+            return;
+        
+        try {
+            File autostart_dir = startup_file.get_parent();
+            if (!autostart_dir.query_exists())
+                autostart_dir.make_directory_with_parents();
+            File? autostart = get_autostart_desktop_file();
+            if (autostart == null) {
+                message("Autostart file is not installed!");
+            } else {
+                autostart.copy(startup_file, 0);
+            }
+        } catch (Error err) {
+            message("Failed to create startup file: %s", err.message);
+        }
+    }
+   
+    /**
+     * Callback for startup notification option changes.
+     */
+    public void on_startup_notification_change() {
+        if (GearyApplication.instance.config.startup_notifications)
+            create_startup_file();
+        else
+            delete_startup_file();
+    }
+    
+    /*
+     * A convenience method. The purpose of this method is to synchronize the state of startup notifications 
setting
+     * with the actual state of the file, so it's not misleading for the user (the option is checked while 
the file doesn't exist)
+     */
+    public void sync_with_config() {
+        GearyApplication.instance.config.startup_notifications = startup_file.query_exists(); 
+    }
+}
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index 5c9d827..ee10326 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -154,7 +154,11 @@ public class GearyApplication : Gtk.Application {
         if (controller == null || controller.main_window == null)
             return false;
         
-        controller.main_window.present();
+        if (!controller.main_window.get_realized())
+            controller.main_window.show_all();
+        else
+            controller.main_window.present();
+        
         return true;
     }
     
diff --git a/src/client/application/geary-args.vala b/src/client/application/geary-args.vala
index 1cbbea5..a26a9c8 100644
--- a/src/client/application/geary-args.vala
+++ b/src/client/application/geary-args.vala
@@ -7,6 +7,7 @@
 namespace Args {
 
 private const OptionEntry[] options = {
+    { "hidden", 0, 0, OptionArg.NONE, ref hidden_startup, N_("Start Geary with hidden main window"), null },
     { "debug", 'd', 0, OptionArg.NONE, ref log_debug, N_("Output debugging information"), null },
     { "log-conversations", 0, 0, OptionArg.NONE, ref log_conversations, N_("Log conversation monitoring"), 
null },
     { "log-deserializer", 0, 0, OptionArg.NONE, ref log_deserializer, N_("Log network deserialization"), 
null },
@@ -26,6 +27,7 @@ private const OptionEntry[] options = {
     { null }
 };
 
+public bool hidden_startup = false;
 public bool log_debug = false;
 public bool log_network = false;
 public bool log_serializer = false;
diff --git a/src/client/application/geary-config.vala b/src/client/application/geary-config.vala
index ad42a21..2e84304 100644
--- a/src/client/application/geary-config.vala
+++ b/src/client/application/geary-config.vala
@@ -16,6 +16,7 @@ public class Configuration {
     public const string SPELL_CHECK_KEY = "spell-check";
     public const string PLAY_SOUNDS_KEY = "play-sounds";
     public const string SHOW_NOTIFICATIONS_KEY = "show-notifications";
+    public const string STARTUP_NOTIFICATIONS_KEY = "startup-notifications";
     public const string ASK_OPEN_ATTACHMENT_KEY = "ask-open-attachment";
     public const string COMPOSE_AS_HTML_KEY = "compose-as-html";
     
@@ -63,6 +64,11 @@ public class Configuration {
     public bool show_notifications {
         get { return settings.get_boolean(SHOW_NOTIFICATIONS_KEY); }
     }
+
+    public bool startup_notifications {
+        get { return settings.get_boolean(STARTUP_NOTIFICATIONS_KEY); }
+        set { set_boolean(STARTUP_NOTIFICATIONS_KEY, value); }
+    }
     
     private const string CLOCK_FORMAT_KEY = "clock-format";
     private const string TIME_FORMAT_KEY = "time-format";
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index aa9c01c..2c4b4f8 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -79,6 +79,8 @@ public class GearyController : Geary.BaseObject {
     
     public Geary.App.ConversationMonitor? current_conversations { get; private set; default = null; }
     
+    public AutostartManager? autostart_manager { get; private set; default = null; }
+
     private Geary.Account? current_account = null;
     private Gee.HashMap<Geary.Account, Geary.App.EmailStore> email_stores
         = new Gee.HashMap<Geary.Account, Geary.App.EmailStore>();
@@ -218,6 +220,9 @@ public class GearyController : Geary.BaseObject {
         
         main_window.conversation_list_view.grab_focus();
         
+        // instantiate here to ensure that Config is initialized and ready
+        autostart_manager = new AutostartManager();
+        
         // Start Geary.
         try {
             yield Geary.Engine.instance.open_async(GearyApplication.instance.get_user_data_directory(), 
@@ -916,7 +921,7 @@ public class GearyController : Geary.BaseObject {
      */
     private void display_main_window_if_ready() {
         if (did_attempt_open_all_accounts() && !upgrade_dialog.visible &&
-            !cancellable_open_account.is_cancelled())
+            !cancellable_open_account.is_cancelled() && !Args.hidden_startup)
             main_window.show_all();
     }
     
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index cd50bce..7809dab 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -96,6 +96,9 @@ public class MainWindow : Gtk.ApplicationWindow {
     }
     
     private bool on_delete_event() {
+        if (Args.hidden_startup || GearyApplication.instance.config.startup_notifications)
+            return hide_on_delete();
+        
         GearyApplication.instance.exit();
         
         return true;
diff --git a/src/client/dialogs/preferences-dialog.vala b/src/client/dialogs/preferences-dialog.vala
index 4df1d9d..30fb0d7 100644
--- a/src/client/dialogs/preferences-dialog.vala
+++ b/src/client/dialogs/preferences-dialog.vala
@@ -21,9 +21,12 @@ public class PreferencesDialog : Object {
         config.bind(Configuration.SPELL_CHECK_KEY, builder.get_object("spell_check"), "active");
         config.bind(Configuration.PLAY_SOUNDS_KEY, builder.get_object("play_sounds"), "active");
         config.bind(Configuration.SHOW_NOTIFICATIONS_KEY, builder.get_object("show_notifications"), 
"active");
+        config.bind(Configuration.STARTUP_NOTIFICATIONS_KEY, builder.get_object("startup_notifications"), 
"active");
     }
     
     public void run() {
+        // Sync startup notification option with file state
+        GearyApplication.instance.controller.autostart_manager.sync_with_config();
         dialog.show_all();
         dialog.run();
         dialog.destroy();
diff --git a/ui/preferences.glade b/ui/preferences.glade
index c6ccab4..2342747 100644
--- a/ui/preferences.glade
+++ b/ui/preferences.glade
@@ -211,6 +211,27 @@
               </packing>
             </child>
             <child>
+              <object class="GtkCheckButton" id="startup_notifications">
+                <property name="label" translatable="yes">Notify of new mail at start_up</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="margin_left">12</property>
+                <property name="margin_right">5</property>
+                <property name="margin_top">5</property>
+                <property name="margin_bottom">5</property>
+                <property name="use_underline">True</property>
+                <property name="xalign">0</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">9</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
               <placeholder/>
             </child>
           </object>


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