Application.vala 7.43 KB
Newer Older
1
/* Copyright 2016 Software Freedom Conservancy Inc.
2 3
 *
 * This software is licensed under the GNU Lesser General Public License
4
 * (version 2.1 or later).  See the COPYING file in this distribution.
5 6 7 8
 */

public class Application {
    private static Application instance = null;
9 10 11 12
    private Gtk.Application system_app = null;
    private int system_app_run_retval = 0;
    private bool direct;

13 14
    public virtual signal void starting() {
    }
15

16 17
    public virtual signal void exiting(bool panicked) {
    }
18 19 20
    
    public virtual signal void init_done() {
    }
21

22 23 24 25 26 27 28 29 30 31
    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;
    }

32 33 34 35
    public Gtk.Application get_system_app () {
        return system_app;
    }

36 37
    private bool running = false;
    private bool exiting_fired = false;
38 39 40 41 42 43 44

    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.
Jens Georg's avatar
Jens Georg committed
45
            system_app = new Gtk.Application("org.gnome.Shotwell-direct", GLib.ApplicationFlags.HANDLES_OPEN |
46 47 48 49 50
                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).
Jens Georg's avatar
Jens Georg committed
51
            system_app = new Gtk.Application("org.gnome.Shotwell", GLib.ApplicationFlags.HANDLES_OPEN |
52
                GLib.ApplicationFlags.HANDLES_COMMAND_LINE);
53
        }
54

55 56 57 58 59
        // GLib will assert if we don't do this...
        try {
            system_app.register();
        } catch (Error e) {
            panic();
60 61 62 63
        }
        
        direct = is_direct;

64 65 66 67
        if (!direct) {
            system_app.command_line.connect(on_command_line);
        }

68 69 70 71 72 73 74 75 76 77 78 79
        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);
    }
80
    
81 82 83 84 85 86 87 88 89 90 91
    /**
     * @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();
92 93
    }
    
94 95 96 97
    public static bool get_is_direct() {
        return get_instance().direct;
    }

98 99 100 101
    public static void set_accels_for_action (string action, string[] accel) {
        get_instance().system_app.set_accels_for_action (action, accel);
    }

102 103 104 105
    public static void set_menubar (GLib.MenuModel? model) {
        get_instance().system_app.set_menubar (model);
    }

106 107 108 109 110
    /**
     * @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
111
     * a camera/removable-storage mount; in either case, the remote instance
112 113 114
     * will trigger this and exit, and we'll need to bring the window back up...
     */
    public static void on_activated() {
115
        get_instance();
116 117 118

        LibraryWindow lw = AppWindow.get_instance() as LibraryWindow;
        if ((lw != null) && (!get_is_direct())) {
119
            LibraryWindow.get_app().present();
120
        }
121
    }
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161

    /**
     * @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);
    }

162 163 164
    public static void terminate() {
        get_instance().exit();
    }
165

166
    public static Application get_instance() {
167 168
        assert (instance != null);

169 170
        return instance;
    }
171 172

    public void start(string[]? argv = null) {
173 174
        if (running)
            return;
175

176
        running = true;
177

178
        starting();
179 180 181 182 183

        assert(AppWindow.get_instance() != null);
        system_app.add_window(AppWindow.get_instance());
        system_app_run_retval = system_app.run(argv);

184 185 186 187
        if (!direct) {
            system_app.command_line.disconnect(on_command_line);
        }

188 189 190
        system_app.activate.disconnect(on_activated);
        system_app.startup.disconnect(on_activated);

191 192
        running = false;
    }
193

194 195 196
    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)
197
        if (exiting_fired || !running)
198
            return;
199

200
        exiting_fired = true;
201

202
        exiting(false);
203 204

        system_app.release();
205
    }
206

207 208 209 210 211 212 213 214 215
    // 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);
    }
216

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    /**
     * @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);
    }

236 237 238
    public int get_run_return_value() {
        return system_app_run_retval;
    }
239 240
}