Browser.sys.mjs (3436B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const lazy = {}; 6 7 ChromeUtils.defineESModuleGetters(lazy, { 8 pprint: "chrome://remote/content/shared/Format.sys.mjs", 9 waitForObserverTopic: "chrome://remote/content/marionette/sync.sys.mjs", 10 }); 11 12 /** 13 * Quits the application with the provided flags. 14 * 15 * Optional {@link nsIAppStartup} flags may be provided as 16 * an array of masks, and these will be combined by ORing 17 * them with a bitmask. The available masks are defined in 18 * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIAppStartup. 19 * 20 * Crucially, only one of the *Quit flags can be specified. The |eRestart| 21 * flag may be bit-wise combined with one of the *Quit flags to cause 22 * the application to restart after it quits. 23 * 24 * @param {Array.<string>=} flags 25 * Constant name of masks to pass to |Services.startup.quit|. 26 * If empty or undefined, |nsIAppStartup.eAttemptQuit| is used. 27 * @param {boolean=} safeMode 28 * Optional flag to indicate that the application has to 29 * be restarted in safe mode. 30 * @param {boolean=} isWindowless 31 * Optional flag to indicate that the browser was started in windowless mode. 32 * 33 * @returns {Record<string, boolean>} 34 * Dictionary containing information that explains the shutdown reason. 35 * The value for `cause` contains the shutdown kind like "shutdown" or 36 * "restart", while `forced` will indicate if it was a normal or forced 37 * shutdown of the application. "in_app" is always set to indicate that 38 * it is a shutdown triggered from within the application. 39 */ 40 export async function quit(flags = [], safeMode = false, isWindowless = false) { 41 if (flags.includes("eSilently")) { 42 if (!isWindowless) { 43 throw new Error( 44 `Silent restarts only allowed with "moz:windowless" capability set` 45 ); 46 } 47 if (!flags.includes("eRestart")) { 48 throw new TypeError(`"silently" only works with restart flag`); 49 } 50 } 51 52 const quits = ["eConsiderQuit", "eAttemptQuit", "eForceQuit"]; 53 54 let quitSeen; 55 let mode = 0; 56 if (flags.length) { 57 for (let k of flags) { 58 if (!(k in Ci.nsIAppStartup)) { 59 throw new TypeError(lazy.pprint`Expected ${k} in ${Ci.nsIAppStartup}`); 60 } 61 62 if (quits.includes(k)) { 63 if (quitSeen) { 64 throw new TypeError(`${k} cannot be combined with ${quitSeen}`); 65 } 66 quitSeen = k; 67 } 68 69 mode |= Ci.nsIAppStartup[k]; 70 } 71 } 72 73 if (!quitSeen) { 74 mode |= Ci.nsIAppStartup.eAttemptQuit; 75 } 76 77 // Notify all windows that an application quit has been requested. 78 const cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance( 79 Ci.nsISupportsPRBool 80 ); 81 Services.obs.notifyObservers(cancelQuit, "quit-application-requested"); 82 83 // If the shutdown of the application is prevented force quit it instead. 84 if (cancelQuit.data) { 85 mode |= Ci.nsIAppStartup.eForceQuit; 86 } 87 88 // Delay response until the application is about to quit. 89 const quitApplication = lazy.waitForObserverTopic("quit-application"); 90 91 if (safeMode) { 92 Services.startup.restartInSafeMode(mode); 93 } else { 94 Services.startup.quit(mode); 95 } 96 97 return { 98 cause: (await quitApplication).data, 99 forced: cancelQuit.data, 100 in_app: true, 101 }; 102 }