Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
pprint: "chrome://remote/content/shared/Format.sys.mjs",
waitForObserverTopic: "chrome://remote/content/marionette/sync.sys.mjs",
});
/**
* Quits the application with the provided flags.
*
* Optional {@link nsIAppStartup} flags may be provided as
* an array of masks, and these will be combined by ORing
* them with a bitmask. The available masks are defined in
*
* Crucially, only one of the *Quit flags can be specified. The |eRestart|
* flag may be bit-wise combined with one of the *Quit flags to cause
* the application to restart after it quits.
*
* @param {Array.<string>=} flags
* Constant name of masks to pass to |Services.startup.quit|.
* If empty or undefined, |nsIAppStartup.eAttemptQuit| is used.
* @param {boolean=} safeMode
* Optional flag to indicate that the application has to
* be restarted in safe mode.
* @param {boolean=} isWindowless
* Optional flag to indicate that the browser was started in windowless mode.
*
* @returns {Record<string, boolean>}
* Dictionary containing information that explains the shutdown reason.
* The value for `cause` contains the shutdown kind like "shutdown" or
* "restart", while `forced` will indicate if it was a normal or forced
* shutdown of the application. "in_app" is always set to indicate that
* it is a shutdown triggered from within the application.
*/
export async function quit(flags = [], safeMode = false, isWindowless = false) {
if (flags.includes("eSilently")) {
if (!isWindowless) {
throw new Error(
`Silent restarts only allowed with "moz:windowless" capability set`
);
}
if (!flags.includes("eRestart")) {
throw new TypeError(`"silently" only works with restart flag`);
}
}
const quits = ["eConsiderQuit", "eAttemptQuit", "eForceQuit"];
let quitSeen;
let mode = 0;
if (flags.length) {
for (let k of flags) {
if (!(k in Ci.nsIAppStartup)) {
throw new TypeError(lazy.pprint`Expected ${k} in ${Ci.nsIAppStartup}`);
}
if (quits.includes(k)) {
if (quitSeen) {
throw new TypeError(`${k} cannot be combined with ${quitSeen}`);
}
quitSeen = k;
}
mode |= Ci.nsIAppStartup[k];
}
}
if (!quitSeen) {
mode |= Ci.nsIAppStartup.eAttemptQuit;
}
// Notify all windows that an application quit has been requested.
const cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
Ci.nsISupportsPRBool
);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
// If the shutdown of the application is prevented force quit it instead.
if (cancelQuit.data) {
mode |= Ci.nsIAppStartup.eForceQuit;
}
// Delay response until the application is about to quit.
const quitApplication = lazy.waitForObserverTopic("quit-application");
if (safeMode) {
Services.startup.restartInSafeMode(mode);
} else {
Services.startup.quit(mode);
}
return {
cause: (await quitApplication).data,
forced: cancelQuit.data,
in_app: true,
};
}