Bug 853779 - Ensure we don't lose sessions when starting with a private window only; r=yoric a=lsblakk
authorTim Taubert <ttaubert@mozilla.com>
Sun, 06 Oct 2013 15:41:45 -0700
changeset 155867 7453a764f9a9
parent 155866 bfe92ec66b67
child 155868 92d60b740d28
push id4453
push userttaubert@mozilla.com
push dateTue, 22 Oct 2013 03:08:24 +0000
treeherdermozilla-aurora@7453a764f9a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric, lsblakk
bugs853779
milestone26.0a2
Bug 853779 - Ensure we don't lose sessions when starting with a private window only; r=yoric a=lsblakk
browser/components/sessionstore/src/SessionSaver.jsm
browser/components/sessionstore/src/SessionStore.jsm
--- a/browser/components/sessionstore/src/SessionSaver.jsm
+++ b/browser/components/sessionstore/src/SessionSaver.jsm
@@ -203,32 +203,30 @@ let SessionSaverInternal = {
       if (state.windows[i].isPrivate) {
         state.windows.splice(i, 1);
         if (state.selectedWindow >= i) {
           state.selectedWindow--;
         }
       }
     }
 
-#ifndef XP_MACOSX
-    // Don't save invalid states.
-    // Looks like we currently have private windows, only.
-    if (state.windows.length == 0) {
-      stopWatchCancel("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
-      return;
-    }
-#endif
-
     // Remove private windows from the list of closed windows.
     for (let i = state._closedWindows.length - 1; i >= 0; i--) {
       if (state._closedWindows[i].isPrivate) {
         state._closedWindows.splice(i, 1);
       }
     }
 
+    // Make sure that we keep the previous session if we started with a single
+    // private window and no non-private windows have been opened, yet.
+    if (state.deferredInitialState) {
+      state.windows = state.deferredInitialState.windows || [];
+      delete state.deferredInitialState;
+    }
+
 #ifndef XP_MACOSX
     // We want to restore closed windows that are marked with _shouldRestore.
     // We're doing this here because we want to control this only when saving
     // the file.
     while (state._closedWindows.length) {
       let i = state._closedWindows.length - 1;
 
       if (!state._closedWindows[i]._shouldRestore) {
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -725,17 +725,17 @@ let SessionStoreInternal = {
       SessionSaver.updateLastSaveTime();
 
       // restore a crashed session resp. resume the last session if requested
       if (aInitialState) {
         if (isPrivateWindow) {
           // We're starting with a single private window. Save the state we
           // actually wanted to restore so that we can do it later in case
           // the user opens another, non-private window.
-          this._deferredInitialState = aInitialState;
+          this._deferredInitialState = gSessionStartup.state;
 
           // Nothing to restore now, notify observers things are complete.
           Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
         } else {
           TelemetryTimestamps.add("sessionRestoreRestoring");
           this._restoreCount = aInitialState.windows ? aInitialState.windows.length : 0;
 
           let overwrite = this._isCmdLineEmpty(aWindow, aInitialState);
@@ -1378,16 +1378,19 @@ let SessionStoreInternal = {
   /* ........ nsISessionStore API .............. */
 
   getBrowserState: function ssi_getBrowserState() {
     let state = this.getCurrentState();
 
     // Don't include the last session state in getBrowserState().
     delete state.lastSessionState;
 
+    // Don't include any deferred initial state.
+    delete state.deferredInitialState;
+
     return this._toJSONString(state);
   },
 
   setBrowserState: function ssi_setBrowserState(aState) {
     this._handleClosedWindows();
 
     try {
       var state = JSON.parse(aState);
@@ -2485,16 +2488,23 @@ let SessionStoreInternal = {
       scratchpads: scratchpads
     };
 
     // Persist the last session if we deferred restoring it
     if (this._lastSessionState) {
       state.lastSessionState = this._lastSessionState;
     }
 
+    // If we were called by the SessionSaver and started with only a private
+    // window we want to pass the deferred initial state to not lose the
+    // previous session.
+    if (this._deferredInitialState) {
+      state.deferredInitialState = this._deferredInitialState;
+    }
+
     return state;
   },
 
   /**
    * serialize session data for a window
    * @param aWindow
    *        Window reference
    * @returns string
@@ -3941,16 +3951,24 @@ let SessionStoreInternal = {
    * this._lastSessionState and will be kept in case the user explicitly wants
    * to restore the previous session (publicly exposed as restoreLastSession).
    *
    * @param state
    *        The state, presumably from nsISessionStartup.state
    * @returns [defaultState, state]
    */
   _prepDataForDeferredRestore: function ssi_prepDataForDeferredRestore(state) {
+    // Make sure that we don't modify the global state as provided by
+    // nsSessionStartup.state. Converting the object to a JSON string and
+    // parsing it again is the easiest way to do that, although not the most
+    // efficient one. Deferred sessions that don't have automatic session
+    // restore enabled tend to be a lot smaller though so that this shouldn't
+    // be a big perf hit.
+    state = JSON.parse(JSON.stringify(state));
+
     let defaultState = { windows: [], selectedWindow: 1 };
 
     state.selectedWindow = state.selectedWindow || 1;
 
     // Look at each window, remove pinned tabs, adjust selectedindex,
     // remove window if necessary.
     for (let wIndex = 0; wIndex < state.windows.length;) {
       let window = state.windows[wIndex];