[geary/wip/gtkapp] Getting the basics in place for GtkApplication



commit edf2f4169620ac0814fd4fe59a9df5bee9016b75
Author: Charles Lindsay <chaz yorba org>
Date:   Tue Dec 3 17:47:13 2013 -0800

    Getting the basics in place for GtkApplication

 debian/control                                |    2 -
 src/CMakeLists.txt                            |    4 +-
 src/client/application/geary-application.vala |  179 ++++++++++++++++++------
 src/client/application/geary-config.vala      |    4 +-
 src/client/application/geary-controller.vala  |    6 +-
 src/client/components/main-window.vala        |    6 +-
 src/client/notification/libnotify.vala        |    2 +-
 src/client/util/util-yorba-application.vala   |  189 -------------------------
 8 files changed, 149 insertions(+), 243 deletions(-)
---
diff --git a/debian/control b/debian/control
index 441a048..0a01182 100644
--- a/debian/control
+++ b/debian/control
@@ -6,7 +6,6 @@ Build-Depends: debhelper (>= 8),
  libgee-0.8-dev (>= 0.8.5),
  libglib2.0-dev (>= 2.32.0),
  libgtk-3-dev (>= 3.6.0),
- libunique-3.0-dev (>= 3.0.0),
  libnotify-dev (>=0.7.5),
  libcanberra-dev (>= 0.28),
  libwebkitgtk-3.0-dev (<< 2.1.0),
@@ -30,7 +29,6 @@ Depends: ${shlibs:Depends}, ${misc:Depends},
  libgee-0.8-2 (>= 0.8.5),
  libglib2.0-0 (>= 2.32.0),
  libgtk-3-0 (>= 3.6.0),
- libunique-3.0-0 (>= 3.0.0),
  libnotify4 (>= 0.7.5),
  libcanberra0 (>= 0.28),
  libwebkitgtk-3.0-0 (<< 2.1.0),
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 204836f..9f8278a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -370,7 +370,6 @@ client/util/util-gravatar.vala
 client/util/util-gtk.vala
 client/util/util-international.vala
 client/util/util-webkit.vala
-client/util/util-yorba-application.vala
 )
 
 set(CONSOLE_SRC
@@ -479,7 +478,6 @@ pkg_check_modules(DEPS REQUIRED
     gio-2.0>=2.28.0
     gtk+-3.0>=3.6.0
     gee-0.8>=0.8.5
-    unique-3.0>=3.0.0
     libnotify>=0.7.5
     libcanberra>=0.28
     sqlite3>=3.7.4
@@ -490,7 +488,7 @@ pkg_check_modules(DEPS REQUIRED
 )
 
 set(ENGINE_PACKAGES
-    glib-2.0 gee-0.8 gio-2.0 gmime-2.6 unique-3.0 posix sqlite3 libxml-2.0
+    glib-2.0 gee-0.8 gio-2.0 gmime-2.6 posix sqlite3 libxml-2.0
 )
 
 set(CLIENT_PACKAGES
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index 54f2e51..21c21e6 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -9,10 +9,12 @@ extern const string _VERSION;
 extern const string _INSTALL_PREFIX;
 extern const string _GSETTINGS_DIR;
 extern const string _SOURCE_ROOT_DIR;
+extern const string GETTEXT_PACKAGE;
 
-public class GearyApplication : YorbaApplication {
+public class GearyApplication : Gtk.Application {
     public const string NAME = "Geary";
     public const string PRGNAME = "geary";
+    public const string APP_ID = "org.yorba.geary";
     public const string DESCRIPTION = DESKTOP_GENERIC_NAME;
     public const string COPYRIGHT = _("Copyright 2011-2013 Yorba Foundation");
     public const string WEBSITE = "http://www.yorba.org";;
@@ -44,30 +46,49 @@ public class GearyApplication : YorbaApplication {
     };
     
     public const string LICENSE = """
-Geary is free software; you can redistribute it and/or modify it under the 
-terms of the GNU Lesser General Public License as published by the Free 
-Software Foundation; either version 2.1 of the License, or (at your option) 
+Geary is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free
+Software Foundation; either version 2.1 of the License, or (at your option)
 any later version.
 
-Geary is distributed in the hope that it will be useful, but WITHOUT 
+Geary 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 Lesser General Public License for 
+FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 more details.
 
-You should have received a copy of the GNU Lesser General Public License 
-along with Geary; if not, write to the Free Software Foundation, Inc., 
+You should have received a copy of the GNU Lesser General Public License
+along with Geary; if not, write to the Free Software Foundation, Inc.,
 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 """;
     
-    public static GearyApplication instance { 
+    private static const string ACTION_ENTRY_COMPOSE = "compose";
+    
+    public static const ActionEntry[] action_entries = {
+        {ACTION_ENTRY_COMPOSE, activate_compose, "s"},
+    };
+    
+    public static GearyApplication instance {
         get { return _instance; }
-        private set { 
+        private set {
             // Ensure singleton behavior.
             assert (_instance == null);
             _instance = value;
         }
     }
     
+    /**
+     * Signal that is activated when 'exit' is called, but before the application actually exits.
+     *
+     * To cancel an exit, a callback should return GearyApplication.cancel_exit(). To procede with
+     * an exit, a callback should return true.
+     */
+    public virtual signal bool exiting(bool panicked) {
+        controller.close();
+        Date.terminate();
+        
+        return true;
+    }
+    
     public GearyController controller { get; private set; default = new GearyController(); }
     
     public Gtk.ActionGroup actions {
@@ -82,50 +103,85 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
     
     private static GearyApplication _instance = null;
     
+    private string bin;
     private File exec_dir;
     
+    private bool exiting_fired = false;
+    private int exitcode = 0;
+    
     public GearyApplication() {
-        base (NAME, PRGNAME, "org.yorba.geary");
+        Object(application_id: APP_ID);
         
         _instance = this;
     }
     
-    public override int startup() {
-        exec_dir = 
(File.new_for_path(Posix.realpath(Environment.find_program_in_path(args[0])))).get_parent();
+    // Application.run() calls this as an entry point.
+    public override bool local_command_line(ref unowned string[] args, out int exit_status) {
+        bin = args[0];
+        
+        try {
+            register();
+        } catch (Error e) {
+            // TODO
+            Posix.exit(1);
+        }
+        
+        Args.parse(args);
+        
+        activate();
+        foreach (unowned string arg in args) {
+            if (arg != null && arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME))
+                activate_action(ACTION_ENTRY_COMPOSE, new Variant.string(arg));
+        }
+        
+        exit_status = 0;
+        return true;
+    }
+    
+    public override void startup() {
+        base.startup();
+        
+        Environment.set_application_name(NAME);
+        Environment.set_prgname(PRGNAME);
+        International.init(GETTEXT_PACKAGE, bin);
+        
+        exec_dir = (File.new_for_path(Posix.realpath(Environment.find_program_in_path(bin)))).get_parent();
         
         Geary.Logging.init();
         Configuration.init(is_installed(), GSETTINGS_DIR);
         Date.init();
         WebKit.set_cache_model(WebKit.CacheModel.DOCUMENT_BROWSER);
         
-        int ec = base.startup();
-        if (ec != 0)
-            return ec;
+        add_action_entries(action_entries, this);
+    }
+    
+    public override void activate() {
+        base.activate();
         
-        return Args.parse(args);
+        if (!present())
+            create_async.begin();
     }
     
-    public override bool exiting(bool panicked) {
-        controller.close();
-        Date.terminate();
+    public void activate_compose(SimpleAction action, Variant? param) {
+        if (param == null)
+            return;
         
-        return true;
+        compose(param.get_string());
     }
     
-    public override void activate(string[] args) {
-        do_activate_async.begin(args);
+    public bool present() {
+        if (controller == null || controller.main_window == null)
+            return false;
+        
+        controller.main_window.present();
+        return true;
     }
-
-    // Without owned on the args parameter, vala won't bother to keep the array
-    // around until the open_async() call completes, leading to crashes.  This
-    // way, this method gets its own long-lived copy.
-    private async void do_activate_async(owned string[] args) {
-        // If Geary is already running, show the main window and return.
-        if (controller != null && controller.main_window != null) {
-            controller.main_window.present();
-            handle_args(args);
-            return;
-        }
+    
+    private async void create_async() {
+        // Manually keep the main loop around for the duration of this call.
+        // Without this, the main loop will exit as soon as we hit the yield
+        // below, before we create the main window.
+        hold();
         
         // do *after* parsing args, as they dicate where logging is sent to, if anywhere, and only
         // after activate (which means this is only logged for the one user-visible instance, not
@@ -133,10 +189,18 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
         message("%s %s prefix=%s exec_dir=%s is_installed=%s", NAME, VERSION, INSTALL_PREFIX,
             exec_dir.get_path(), is_installed().to_string());
         
-        config = new Configuration();
+        config = new Configuration(APP_ID);
         yield controller.open_async();
         
-        handle_args(args);
+        release();
+    }
+    
+    public bool compose(string mailto) {
+        if (controller == null)
+            return false;
+        
+        controller.compose_mailto(mailto);
+        return true;
     }
     
     // NOTE: This assert()'s if the Gtk.Action is not present in the default action group
@@ -241,12 +305,45 @@ along with Geary; if not, write to the Free Software Foundation, Inc.,
         load_ui_file_for_manager(ui_manager, ui_filename);
     }
     
-    private void handle_args(string[] args) {
-        foreach(string arg in args) {
-            if (arg.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
-                controller.compose_mailto(arg);
-            }
+    // This call will fire "exiting" only if it's not already been fired.
+    public void exit(int exitcode = 0) {
+        if (exiting_fired)
+            return;
+        
+        this.exitcode = exitcode;
+        
+        exiting_fired = true;
+        if (!exiting(false)) {
+            exiting_fired = false;
+            this.exitcode = 0;
+            
+            return;
         }
+        
+        if (Gtk.main_level() > 0)
+            Gtk.main_quit();
+        else
+            Posix.exit(exitcode);
+    }
+    
+    /**
+     * A callback for GearyApplication.exiting should return cancel_exit() to prevent the
+     * application from exiting.
+     */
+    public bool cancel_exit() {
+        Signal.stop_emission_by_name(this, "exiting");
+        return false;
+    }
+    
+    // This call will fire "exiting" only if it's not already been fired and halt the application
+    // in its tracks.
+    public void panic() {
+        if (!exiting_fired) {
+            exiting_fired = true;
+            exiting(true);
+        }
+        
+        Posix.exit(1);
     }
 }
 
diff --git a/src/client/application/geary-config.vala b/src/client/application/geary-config.vala
index 5351fa8..b7dc253 100644
--- a/src/client/application/geary-config.vala
+++ b/src/client/application/geary-config.vala
@@ -115,9 +115,9 @@ public class Configuration {
     }
     
     // Creates a configuration object.
-    public Configuration() {
+    public Configuration(string schema_id) {
         // Start GSettings.
-        settings = new Settings("org.yorba.geary");
+        settings = new Settings(schema_id);
         gnome_interface = new Settings("org.gnome.desktop.interface");
         foreach(string schema in GLib.Settings.list_schemas()) {
             if (schema == "com.canonical.indicator.datetime") {
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index b15b488..af171d6 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -161,7 +161,7 @@ public class GearyController : Geary.BaseObject {
         upgrade_dialog.notify[UpgradeDialog.PROP_VISIBLE_NAME].connect(display_main_window_if_ready);
         
         // Create the main window (must be done after creating actions.)
-        main_window = new MainWindow();
+        main_window = new MainWindow(GearyApplication.instance);
         main_window.notify["has-toplevel-focus"].connect(on_has_toplevel_focus);
         
         enable_message_buttons(false);
@@ -1184,8 +1184,8 @@ public class GearyController : Geary.BaseObject {
     }
     
     // We need to include the second parameter, or valac doesn't recognize the function as matching
-    // YorbaApplication.exiting's signature.
-    private bool on_application_exiting(YorbaApplication sender, bool panicked) {
+    // GearyApplication.exiting's signature.
+    private bool on_application_exiting(GearyApplication sender, bool panicked) {
         if (close_composition_windows())
             return true;
         
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 4f29e9f..3880c22 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -4,7 +4,7 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class MainWindow : Gtk.Window {
+public class MainWindow : Gtk.ApplicationWindow {
     private const int MESSAGE_LIST_WIDTH = 250;
     private const int FOLDER_LIST_WIDTH = 100;
     private const int STATUS_BAR_HEIGHT = 18;
@@ -28,7 +28,9 @@ public class MainWindow : Gtk.Window {
     private Geary.AggregateProgressMonitor progress_monitor = new Geary.AggregateProgressMonitor();
     private Geary.ProgressMonitor? conversation_monitor_progress = null;
     
-    public MainWindow() {
+    public MainWindow(GearyApplication application) {
+        Object(application: application);
+        
         title = GearyApplication.NAME;
         
         conversation_list_view = new ConversationListView(conversation_list_store);
diff --git a/src/client/notification/libnotify.vala b/src/client/notification/libnotify.vala
index 4da8a5a..421b8e9 100644
--- a/src/client/notification/libnotify.vala
+++ b/src/client/notification/libnotify.vala
@@ -57,7 +57,7 @@ public class Libnotify : Geary.BaseObject {
     
     private void on_default_action(Notify.Notification notification, string action) {
         invoked(folder, email);
-        GearyApplication.instance.activate(new string[0]);
+        GearyApplication.instance.activate();
     }
     
     private void notify_new_mail(Geary.Folder folder, int added) {


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