B2G/gecko/browser/components/sessionstore/src/SessionStore.jsm
/**
   * restore features to a single window
   * @param aWindow
   *        Window reference
   * @param aState
   *        JS object or its eval'able source
   * @param aOverwriteTabs
   *        bool overwrite existing tabs w/ new ones
   * @param aFollowUp
   *        bool this isn't the restoration of the first window
   */
restore features to a single window
@param aWindow
Window reference
@param aState
JS object or its eval'able source
@param aOverwriteTabs
bool overwrite existing tabs w/ new ones
@param aFollowUp
bool this isn't the restoration of the first window
restore features to a single window @param aWindow Window reference @param aState JS object or its eval ' able source @param aOverwriteTabs bool overwrite existing tabs w / new ones @param aFollowUp bool this isn ' t the restoration of the first window
function ssi_restoreWindow(aWindow, aState, aOverwriteTabs, aFollowUp) {
    if (!aFollowUp) {
      this.windowToFocus = aWindow;
    }
    if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
      this.onLoad(aWindow);
    try {
      var root = typeof aState == "string" ? JSON.parse(aState) : aState;
      if (!root.windows[0]) {
        this._sendRestoreCompletedNotifications();
        return; 
      }
    }
    catch (ex) { 
      debug(ex);
      this._sendRestoreCompletedNotifications();
      return;
    }
    this._setWindowStateBusy(aWindow);
    if (root._closedWindows)
      this._closedWindows = root._closedWindows;
    var winData;
    if (!root.selectedWindow || root.selectedWindow > root.windows.length) {
      root.selectedWindow = 0;
    } else {
      root.windows.unshift(root.windows.splice(root.selectedWindow - 1, 1)[0]);
    }
    for (var w = 1; w < root.windows.length; w++) {
      winData = root.windows[w];
      if (winData && winData.tabs && winData.tabs[0]) {
        var window = this._openWindowWithState({ windows: [winData] });
      }
    }
    winData = root.windows[0];
    if (!winData.tabs) {
      winData.tabs = [];
    }
    else if (root._firstTabs && !aOverwriteTabs && winData.tabs.length == 1 &&
             (!winData.tabs[0].entries || winData.tabs[0].entries.length == 0)) {
      winData.tabs = [];
    }
    var tabbrowser = aWindow.gBrowser;
    var openTabCount = aOverwriteTabs ? tabbrowser.browsers.length : -1;
    var newTabCount = winData.tabs.length;
    var tabs = [];
    var tabstrip = tabbrowser.tabContainer.mTabstrip;
    var smoothScroll = tabstrip.smoothScroll;
    tabstrip.smoothScroll = false;
    if (aOverwriteTabs) {
      for (let t = tabbrowser._numPinnedTabs - 1; t > -1; t--)
        tabbrowser.unpinTab(tabbrowser.tabs[t]);
    }
    if (aOverwriteTabs && tabbrowser.selectedTab._tPos >= newTabCount)
      tabbrowser.moveTabTo(tabbrowser.selectedTab, newTabCount - 1);
    let numVisibleTabs = 0;
    for (var t = 0; t < newTabCount; t++) {
      tabs.push(t < openTabCount ?
                tabbrowser.tabs[t] :
                tabbrowser.addTab("about:blank", {skipAnimation: true}));
      if (!aOverwriteTabs && root._firstTabs) {
        tabbrowser.moveTabTo(tabs[t], t);
      }
      if (winData.tabs[t].pinned)
        tabbrowser.pinTab(tabs[t]);
      if (winData.tabs[t].hidden) {
        tabbrowser.hideTab(tabs[t]);
      }
      else {
        tabbrowser.showTab(tabs[t]);
        numVisibleTabs++;
      }
    }
    if (!numVisibleTabs && winData.tabs.length) {
      winData.tabs[0].hidden = false;
      tabbrowser.showTab(tabs[0]);
    }
    if (aOverwriteTabs) {
      for (let i = 0; i < tabbrowser.tabs.length; i++) {
        if (tabbrowser.browsers[i].__SS_restoreState)
          this._resetTabRestoringState(tabbrowser.tabs[i]);
      }
    }
    if (!aWindow.__SS_tabsToRestore)
      aWindow.__SS_tabsToRestore = 0;
    if (aOverwriteTabs)
      aWindow.__SS_tabsToRestore = newTabCount;
    else
      aWindow.__SS_tabsToRestore += newTabCount;
    delete aWindow.__SS_lastSessionWindowID;
    if (winData.__lastSessionWindowID)
      aWindow.__SS_lastSessionWindowID = winData.__lastSessionWindowID;
    if (aOverwriteTabs && newTabCount < openTabCount) {
      Array.slice(tabbrowser.tabs, newTabCount, openTabCount)
           .forEach(tabbrowser.removeTab, tabbrowser);
    }
    if (aOverwriteTabs) {
      this.restoreWindowFeatures(aWindow, winData);
      delete this._windows[aWindow.__SSi].extData;
    }
    if (winData.cookies) {
      this.restoreCookies(winData.cookies);
    }
    if (winData.extData) {
      if (!this._windows[aWindow.__SSi].extData) {
        this._windows[aWindow.__SSi].extData = {};
      }
      for (var key in winData.extData) {
        this._windows[aWindow.__SSi].extData[key] = winData.extData[key];
      }
    }
    if (aOverwriteTabs || root._firstTabs) {
      this._windows[aWindow.__SSi]._closedTabs = winData._closedTabs || [];
    }
    this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs,
      (aOverwriteTabs ? (parseInt(winData.selected) || 1) : 0), 0, 0);
    if (aState.scratchpads) {
      ScratchpadManager.restoreSession(aState.scratchpads);
    }
    tabstrip.smoothScroll = smoothScroll;
    this._sendRestoreCompletedNotifications();
  }
function ssi_restoreWindow ( aWindow , aState , aOverwriteTabs , aFollowUp ) { if ( ! aFollowUp ) { this . windowToFocus = aWindow ; } if ( aWindow && ( ! aWindow . __SSi || ! this . _windows [ aWindow . __SSi ] ) ) this . onLoad ( aWindow ) ; try { var root = typeof aState == "string" ? JSON . parse ( aState ) : aState ; if ( ! root . windows [ 0 ] ) { this . _sendRestoreCompletedNotifications ( ) ; return ; } } catch ( ex ) { debug ( ex ) ; this . _sendRestoreCompletedNotifications ( ) ; return ; } this . _setWindowStateBusy ( aWindow ) ; if ( root . _closedWindows ) this . _closedWindows = root . _closedWindows ; var winData ; if ( ! root . selectedWindow || root . selectedWindow > root . windows . length ) { root . selectedWindow = 0 ; } else { root . windows . unshift ( root . windows . splice ( root . selectedWindow - 1 , 1 ) [ 0 ] ) ; } for ( var w = 1 ; w < root . windows . length ; w ++ ) { winData = root . windows [ w ] ; if ( winData && winData . tabs && winData . tabs [ 0 ] ) { var window = this . _openWindowWithState ( { windows : [ winData ] } ) ; } } winData = root . windows [ 0 ] ; if ( ! winData . tabs ) { winData . tabs = [ ] ; } else if ( root . _firstTabs && ! aOverwriteTabs && winData . tabs . length == 1 && ( ! winData . tabs [ 0 ] . entries || winData . tabs [ 0 ] . entries . length == 0 ) ) { winData . tabs = [ ] ; } var tabbrowser = aWindow . gBrowser ; var openTabCount = aOverwriteTabs ? tabbrowser . browsers . length : - 1 ; var newTabCount = winData . tabs . length ; var tabs = [ ] ; var tabstrip = tabbrowser . tabContainer . mTabstrip ; var smoothScroll = tabstrip . smoothScroll ; tabstrip . smoothScroll = false ; if ( aOverwriteTabs ) { for ( let t = tabbrowser . _numPinnedTabs - 1 ; t > - 1 ; t -- ) tabbrowser . unpinTab ( tabbrowser . tabs [ t ] ) ; } if ( aOverwriteTabs && tabbrowser . selectedTab . _tPos >= newTabCount ) tabbrowser . moveTabTo ( tabbrowser . selectedTab , newTabCount - 1 ) ; let numVisibleTabs = 0 ; for ( var t = 0 ; t < newTabCount ; t ++ ) { tabs . push ( t < openTabCount ? tabbrowser . tabs [ t ] : tabbrowser . addTab ( "about:blank" , { skipAnimation : true } ) ) ; if ( ! aOverwriteTabs && root . _firstTabs ) { tabbrowser . moveTabTo ( tabs [ t ] , t ) ; } if ( winData . tabs [ t ] . pinned ) tabbrowser . pinTab ( tabs [ t ] ) ; if ( winData . tabs [ t ] . hidden ) { tabbrowser . hideTab ( tabs [ t ] ) ; } else { tabbrowser . showTab ( tabs [ t ] ) ; numVisibleTabs ++ ; } } if ( ! numVisibleTabs && winData . tabs . length ) { winData . tabs [ 0 ] . hidden = false ; tabbrowser . showTab ( tabs [ 0 ] ) ; } if ( aOverwriteTabs ) { for ( let i = 0 ; i < tabbrowser . tabs . length ; i ++ ) { if ( tabbrowser . browsers [ i ] . __SS_restoreState ) this . _resetTabRestoringState ( tabbrowser . tabs [ i ] ) ; } } if ( ! aWindow . __SS_tabsToRestore ) aWindow . __SS_tabsToRestore = 0 ; if ( aOverwriteTabs ) aWindow . __SS_tabsToRestore = newTabCount ; else aWindow . __SS_tabsToRestore += newTabCount ; delete aWindow . __SS_lastSessionWindowID ; if ( winData . __lastSessionWindowID ) aWindow . __SS_lastSessionWindowID = winData . __lastSessionWindowID ; if ( aOverwriteTabs && newTabCount < openTabCount ) { Array . slice ( tabbrowser . tabs , newTabCount , openTabCount ) . forEach ( tabbrowser . removeTab , tabbrowser ) ; } if ( aOverwriteTabs ) { this . restoreWindowFeatures ( aWindow , winData ) ; delete this . _windows [ aWindow . __SSi ] . extData ; } if ( winData . cookies ) { this . restoreCookies ( winData . cookies ) ; } if ( winData . extData ) { if ( ! this . _windows [ aWindow . __SSi ] . extData ) { this . _windows [ aWindow . __SSi ] . extData = { } ; } for ( var key in winData . extData ) { this . _windows [ aWindow . __SSi ] . extData [ key ] = winData . extData [ key ] ; } } if ( aOverwriteTabs || root . _firstTabs ) { this . _windows [ aWindow . __SSi ] . _closedTabs = winData . _closedTabs || [ ] ; } this . restoreHistoryPrecursor ( aWindow , tabs , winData . tabs , ( aOverwriteTabs ? ( parseInt ( winData . selected ) || 1 ) : 0 ) , 0 , 0 ) ; if ( aState . scratchpads ) { ScratchpadManager . restoreSession ( aState . scratchpads ) ; } tabstrip . smoothScroll = smoothScroll ; this . _sendRestoreCompletedNotifications ( ) ; }
restore features to a single window
 @param aWindow
        Window reference
 @param aState
        JS object or its eval'able source
 @param aOverwriteTabs
        bool overwrite existing tabs w/ new ones
 @param aFollowUp
        bool this isn't the restoration of the first window
restore features to a single window @param aWindow Window reference @param aState JS object or its eval ' able source @param aOverwriteTabs bool overwrite existing tabs w / new ones @param aFollowUp bool this isn ' t the restoration of the first window
// initialize window if necessary // nothing to restore // invalid state object - don't restore anything // We're not returning from this before we end up calling restoreHistoryPrecursor // for this window, so make sure we send the SSWindowStateBusy event. // put the selected window at the beginning of the array to ensure that // it gets restored first // open new windows for all further window entries of a multi-window session // (unless they don't contain any tab data) // don't restore a single blank tab when we've had an external // URL passed in for loading at startup (cf. bug 357419) // disable smooth scrolling while adding, moving, removing and selecting tabs // unpin all tabs to ensure they are not reordered in the next loop // make sure that the selected tab won't be closed in order to // prevent unnecessary flickering // when resuming at startup: add additionally requested pages to the end // if all tabs to be restored are hidden, make the first one visible // If overwriting tabs, we want to reset each tab's "restoring" state. Since // we're overwriting those tabs, they should no longer be restoring. The // tabs will be rebuilt and marked if they need to be restored after loading // state (in restoreHistoryPrecursor). // We want to set up a counter on the window that indicates how many tabs // in this window are unrestored. This will be used in restoreNextTab to // determine if gRestoreTabsProgressListener should be removed from the window. // If we aren't overwriting existing tabs, then we want to add to the existing // count in case there are still tabs restoring. // We want to correlate the window with data from the last session, so // assign another id if we have one. Otherwise clear so we don't do // anything with it. // when overwriting tabs, remove all superflous ones // set smoothScroll back to the original value