--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1349,16 +1349,18 @@ var BrowserApp = {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
// Quit aborted.
if (cancelQuit.data) {
return;
}
+ Services.obs.notifyObservers(null, "quit-application-proceeding", null);
+
// Tell session store to forget about this window
if (aClear.dontSaveSession) {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
ss.removeWindow(window);
}
BrowserApp.sanitize(aClear.sanitize, function() {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -34,16 +34,17 @@ function log(a) {
}
// -----------------------------------------------------------------------
// Session Store
// -----------------------------------------------------------------------
const STATE_STOPPED = 0;
const STATE_RUNNING = 1;
+const STATE_QUITTING = -1;
const PRIVACY_NONE = 0;
const PRIVACY_ENCRYPTED = 1;
const PRIVACY_FULL = 2;
const PREFS_RESTORE_FROM_CRASH = "browser.sessionstore.resume_from_crash";
const PREFS_MAX_CRASH_RESUMES = "browser.sessionstore.max_resumed_crashes";
@@ -106,16 +107,19 @@ SessionStore.prototype = {
let self = this;
let observerService = Services.obs;
switch (aTopic) {
case "app-startup":
observerService.addObserver(this, "final-ui-startup", true);
observerService.addObserver(this, "domwindowopened", true);
observerService.addObserver(this, "domwindowclosed", true);
observerService.addObserver(this, "browser:purge-session-history", true);
+ observerService.addObserver(this, "quit-application-requested", true);
+ observerService.addObserver(this, "quit-application-proceeding", true);
+ observerService.addObserver(this, "quit-application", true);
observerService.addObserver(this, "Session:Restore", true);
observerService.addObserver(this, "Session:NotifyLocationChange", true);
observerService.addObserver(this, "application-background", true);
observerService.addObserver(this, "ClosedTabs:StartNotifications", true);
observerService.addObserver(this, "ClosedTabs:StopNotifications", true);
observerService.addObserver(this, "last-pb-context-exited", true);
observerService.addObserver(this, "Session:RestoreRecentTabs", true);
observerService.addObserver(this, "Tabs:OpenMultiple", true);
@@ -130,41 +134,71 @@ SessionStore.prototype = {
self.onWindowOpen(window);
window.removeEventListener("load", arguments.callee, false);
}, false);
break;
}
case "domwindowclosed": // catch closed windows
this.onWindowClose(aSubject);
break;
+ case "quit-application-requested":
+ // Get a current snapshot of all windows
+ this._forEachBrowserWindow(function(aWindow) {
+ self._collectWindowData(aWindow);
+ });
+ break;
+ case "quit-application-proceeding":
+ // Freeze the data at what we've got (ignoring closing windows)
+ this._loadState = STATE_QUITTING;
+ break;
+ case "quit-application":
+ observerService.removeObserver(this, "domwindowopened");
+ observerService.removeObserver(this, "domwindowclosed");
+ observerService.removeObserver(this, "quit-application-requested");
+ observerService.removeObserver(this, "quit-application-proceeding");
+ observerService.removeObserver(this, "quit-application");
+ observerService.removeObserver(this, "Session:Restore");
+
+ // If a save has been queued, kill the timer and save now
+ if (this._saveTimer) {
+ this._saveTimer.cancel();
+ this._saveTimer = null;
+ this.saveState();
+ }
+
+ break;
case "browser:purge-session-history": // catch sanitization
this._clearDisk();
// Clear all data about closed tabs
for (let [ssid, win] in Iterator(this._windows))
win.closedTabs = [];
this._lastClosedTabIndex = -1;
if (this._loadState == STATE_RUNNING) {
// Save the purged state immediately
this.saveState();
+ } else if (this._loadState == STATE_QUITTING) {
+ this.saveStateDelayed();
}
Services.obs.notifyObservers(null, "sessionstore-state-purge-complete", "");
if (this._notifyClosedTabs) {
this._sendClosedTabsToJava(Services.wm.getMostRecentWindow("navigator:browser"));
}
break;
case "timer-callback":
- // Timer call back for delayed saving
- this._saveTimer = null;
- log("timer-callback, pendingWrite = " + this._pendingWrite);
- if (this._pendingWrite) {
- this.saveState();
+ if (STATE_RUNNING) {
+ // Timer call back for delayed saving
+ this._saveTimer = null;
+ log("timer-callback, pendingWrite = " + this._pendingWrite);
+ if (this._pendingWrite) {
+ this.saveState();
+ }
}
break;
case "Session:Restore": {
Services.obs.removeObserver(this, "Session:Restore");
if (aData) {
// Be ready to handle any restore failures by making sure we have a valid tab opened
let window = Services.wm.getMostRecentWindow("navigator:browser");
let restoreCleanup = {
@@ -355,17 +389,17 @@ SessionStore.prototype = {
onWindowOpen: function ss_onWindowOpen(aWindow) {
// Return if window has already been initialized
if (aWindow && aWindow.__SSID && this._windows[aWindow.__SSID]) {
return;
}
// Ignore non-browser windows and windows opened while shutting down
- if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
+ if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" || this._loadState == STATE_QUITTING) {
return;
}
// Assign it a unique identifier (timestamp) and create its data object
aWindow.__SSID = "window" + Date.now();
this._windows[aWindow.__SSID] = { tabs: [], selected: 0, closedTabs: [] };
// Perform additional initialization when the first window is loading
@@ -405,16 +439,18 @@ SessionStore.prototype = {
// Update all window data for a last time
this._collectWindowData(aWindow);
// Clear this window from the list
delete this._windows[aWindow.__SSID];
// Save the state without this window to disk
this.saveStateDelayed();
+ } else if (this._loadState == STATE_QUITTING) {
+ this.saveStateDelayed();
}
let tabs = aWindow.BrowserApp.tabs;
for (let i = 0; i < tabs.length; i++)
this.onTabRemove(aWindow, tabs[i].browser, true);
delete aWindow.__SSID;
},
@@ -1595,14 +1631,19 @@ SessionStore.prototype = {
removeWindow: function ss_removeWindow(aWindow) {
if (!aWindow || !aWindow.__SSID || !this._windows[aWindow.__SSID]) {
return;
}
delete this._windows[aWindow.__SSID];
delete aWindow.__SSID;
- this.saveState();
+ if (this._loadState == STATE_RUNNING) {
+ // Save the purged state immediately
+ this.saveState();
+ } else if (this._loadState == STATE_QUITTING) {
+ this.saveStateDelayed();
+ }
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SessionStore]);