summaryrefslogtreecommitdiff
path: root/src/Application.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/Application.vala')
-rw-r--r--src/Application.vala228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/Application.vala b/src/Application.vala
new file mode 100644
index 0000000..95163cf
--- /dev/null
+++ b/src/Application.vala
@@ -0,0 +1,228 @@
+/* Copyright 2010-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.
+ */
+
+public class Application {
+ private static Application instance = null;
+ private Gtk.Application system_app = null;
+ private int system_app_run_retval = 0;
+ private bool direct;
+
+ public virtual signal void starting() {
+ }
+
+ public virtual signal void exiting(bool panicked) {
+ }
+
+ public virtual signal void init_done() {
+ }
+
+ private bool fixup_raw_thumbs = false;
+
+ public void set_raw_thumbs_fix_required(bool should_fixup) {
+ fixup_raw_thumbs = should_fixup;
+ }
+
+ public bool get_raw_thumbs_fix_required() {
+ return fixup_raw_thumbs;
+ }
+
+ private bool running = false;
+ private bool exiting_fired = false;
+
+ private Application(bool is_direct) {
+ if (is_direct) {
+ // we allow multiple instances of ourself in direct mode, so DON'T
+ // attempt to be unique. We don't request any command-line handling
+ // here because this is processed elsewhere, and we don't need to handle
+ // command lines from remote instances, since we don't care about them.
+ system_app = new Gtk.Application("org.yorba.shotwell-direct", GLib.ApplicationFlags.HANDLES_OPEN |
+ GLib.ApplicationFlags.NON_UNIQUE);
+ } else {
+ // we've been invoked in library mode; set up for uniqueness and handling
+ // of incoming command lines from remote instances (needed for getting
+ // storage device and camera mounts).
+ system_app = new Gtk.Application("org.yorba.shotwell", GLib.ApplicationFlags.HANDLES_OPEN |
+ GLib.ApplicationFlags.HANDLES_COMMAND_LINE);
+ }
+
+ // GLib will assert if we don't do this...
+ try {
+ system_app.register();
+ } catch (Error e) {
+ panic();
+ }
+
+ direct = is_direct;
+
+ if (!direct) {
+ system_app.command_line.connect(on_command_line);
+ }
+
+ system_app.activate.connect(on_activated);
+ system_app.startup.connect(on_activated);
+ }
+
+ /**
+ * @brief This is a helper for library mode that should only be
+ * called if we've gotten a camera mount and are _not_ the primary
+ * instance.
+ */
+ public static void send_to_primary_instance(string[]? argv) {
+ get_instance().system_app.run(argv);
+ }
+
+ /**
+ * @brief A helper for library mode that tells the primary
+ * instance to bring its window to the foreground. This
+ * should only be called if we are _not_ the primary instance.
+ */
+ public static void present_primary_instance() {
+ get_instance().system_app.activate();
+ }
+
+ public static bool get_is_remote() {
+ return get_instance().system_app.get_is_remote();
+ }
+
+ public static bool get_is_direct() {
+ return get_instance().direct;
+ }
+
+ /**
+ * @brief Signal handler for GApplication's 'command-line' signal.
+ *
+ * The most likely scenario for this to be fired is if the user
+ * either tried to run us twice in library mode, or we've just gotten
+ * a camera/removeable-storage mount; in either case, the remote instance
+ * will trigger this and exit, and we'll need to bring the window back up...
+ */
+ public static void on_activated() {
+ get_instance();
+
+ LibraryWindow lw = AppWindow.get_instance() as LibraryWindow;
+ if ((lw != null) && (!get_is_direct())) {
+ LibraryWindow.get_app().present();
+ }
+ }
+
+ /**
+ * @brief Signal handler for GApplication's 'command-line' signal.
+ *
+ * Gets fired whenever a remote instance tries to run, usually
+ * with an incoming camera connection.
+ *
+ * @note This does _not_ get called in direct-edit mode.
+ */
+ public static int on_command_line(ApplicationCommandLine acl) {
+ string[]? argv = acl.get_arguments();
+
+ if (argv != null) {
+ foreach (string s in argv) {
+ LibraryWindow lw = AppWindow.get_instance() as LibraryWindow;
+ if (lw != null) {
+ lw.mounted_camera_shell_notification(s, false);
+ }
+ }
+ }
+ on_activated();
+ return 0;
+ }
+
+ /**
+ * @brief Initializes the Shotwell application object and prepares
+ * it for use.
+ *
+ * @param is_direct Whether the application was invoked in direct
+ * or in library mode; defaults to FALSE, that is, library mode.
+ *
+ * @note This MUST be called prior to calling get_instance(), as the
+ * application needs to know what mode it was brought up in; failure to
+ * call this first will lead to an assertion.
+ */
+ public static void init(bool is_direct = false) {
+ if (instance == null)
+ instance = new Application(is_direct);
+ }
+
+ public static void terminate() {
+ get_instance().exit();
+ }
+
+ public static Application get_instance() {
+ assert (instance != null);
+
+ return instance;
+ }
+
+ public void start(string[]? argv = null) {
+ if (running)
+ return;
+
+ running = true;
+
+ starting();
+
+ assert(AppWindow.get_instance() != null);
+ system_app.add_window(AppWindow.get_instance());
+ system_app_run_retval = system_app.run(argv);
+
+ if (!direct) {
+ system_app.command_line.disconnect(on_command_line);
+ }
+
+ system_app.activate.disconnect(on_activated);
+ system_app.startup.disconnect(on_activated);
+
+ running = false;
+ }
+
+ public void exit() {
+ // only fire this once, but thanks to terminate(), it will be fired at least once (even
+ // if start() is not called and "starting" is not fired)
+ if (exiting_fired || !running)
+ return;
+
+ exiting_fired = true;
+
+ exiting(false);
+
+ system_app.release();
+ }
+
+ // This will fire the exiting signal with panicked set to true, but only if exit() hasn't
+ // already been called. This call will immediately halt the application.
+ public void panic() {
+ if (!exiting_fired) {
+ exiting_fired = true;
+ exiting(true);
+ }
+ Posix.exit(1);
+ }
+
+ /**
+ * @brief Allows the caller to ask for some part of the desktop session's functionality to
+ * be prevented from running; wrapper for Gtk.Application.inhibit().
+ *
+ * @note The return value is a 'cookie' that needs to be passed to 'uninhibit' to turn
+ * off a requested inhibition and should be saved by the caller.
+ */
+ public uint inhibit(Gtk.ApplicationInhibitFlags what, string? reason="none given") {
+ return system_app.inhibit(AppWindow.get_instance(), what, reason);
+ }
+
+ /**
+ * @brief Turns off a previously-requested inhibition. Wrapper for
+ * Gtk.Application.uninhibit().
+ */
+ public void uninhibit(uint cookie) {
+ system_app.uninhibit(cookie);
+ }
+
+ public int get_run_return_value() {
+ return system_app_run_retval;
+ }
+}
+