diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 00cec4a595a..90d0462d0fb 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -804,6 +804,10 @@ pref("browser.sessionstore.max_resumed_crashes", 1); pref("browser.sessionstore.restore_on_demand", false); // Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not pref("browser.sessionstore.restore_hidden_tabs", false); +// If restore_on_demand is set, pinned tabs are restored on startup by default. +// When set to true, this pref overrides that behavior, and pinned tabs will only +// be restored when they are focused. +pref("browser.sessionstore.restore_pinned_tabs_on_demand", false); // allow META refresh by default pref("accessibility.blockautorefresh", false); diff --git a/browser/components/sessionstore/src/nsSessionStore.js b/browser/components/sessionstore/src/nsSessionStore.js index 41ae9022167..b22bfa91d90 100644 --- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -251,6 +251,9 @@ SessionStoreService.prototype = { // whether to restore hidden tabs or not, pref controlled. _restoreHiddenTabs: null, + + // whether to restore app tabs on demand or not, pref controlled. + _restorePinnedTabsOnDemand: null, // The state from the previous session (after restoring pinned tabs). This // state is persisted and passed through to the next session during an app @@ -313,6 +316,10 @@ SessionStoreService.prototype = { this._restoreHiddenTabs = this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs"); this._prefBranch.addObserver("sessionstore.restore_hidden_tabs", this, true); + + this._restorePinnedTabsOnDemand = + this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand"); + this._prefBranch.addObserver("sessionstore.restore_pinned_tabs_on_demand", this, true); // Make sure gRestoreTabsProgressListener has a reference to sessionstore // so that it can make calls back in @@ -688,6 +695,10 @@ SessionStoreService.prototype = { this._restoreHiddenTabs = this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs"); break; + case "sessionstore.restore_pinned_tabs_on_demand": + this._restorePinnedTabsOnDemand = + this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand"); + break; } break; case "timer-callback": // timer call back for delayed saving @@ -3187,7 +3198,8 @@ SessionStoreService.prototype = { return; // If it's not possible to restore anything, then just bail out. - if ((!this._tabsToRestore.priority.length && this._restoreOnDemand) || + if ((this._restoreOnDemand && + (this._restorePinnedTabsOnDemand || !this._tabsToRestore.priority.length)) || this._tabsRestoringCount >= MAX_CONCURRENT_TAB_RESTORES) return; diff --git a/browser/components/sessionstore/test/browser_586068-cascaded_restore.js b/browser/components/sessionstore/test/browser_586068-cascaded_restore.js index bff38b83f81..04a0bdfdd14 100644 --- a/browser/components/sessionstore/test/browser_586068-cascaded_restore.js +++ b/browser/components/sessionstore/test/browser_586068-cascaded_restore.js @@ -56,11 +56,13 @@ let tests = [test_cascade, test_select, test_multiWindowState, test_setWindowStateNoOverwrite, test_setWindowStateOverwrite, test_setBrowserStateInterrupted, test_reload, /* test_reloadReload, */ test_reloadCascadeSetup, - /* test_reloadCascade, */ test_apptabs_only]; + /* test_reloadCascade, */ test_apptabs_only, + test_restore_apptabs_ondemand]; function runNextTest() { // Reset the pref try { Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand"); + Services.prefs.clearUserPref("browser.sessionstore.restore_pinned_tabs_on_demand"); } catch (e) {} // set an empty state & run the next test, or finish @@ -777,6 +779,69 @@ function test_apptabs_only() { } +// This test ensures that app tabs are not restored when restore_pinned_tabs_on_demand is set +function test_restore_apptabs_ondemand() { + Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true); + Services.prefs.setBoolPref("browser.sessionstore.restore_pinned_tabs_on_demand", true); + + // We have our own progress listener for this test, which we'll attach before our state is set + let progressListener = { + onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { + if (aBrowser.__SS_restoreState == TAB_STATE_RESTORING && + aStateFlags & Ci.nsIWebProgressListener.STATE_STOP && + aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK && + aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) + test_restore_apptabs_ondemand_progressCallback(aBrowser); + } + } + + let state = { windows: [{ tabs: [ + { entries: [{ url: "http://example.org/#1" }], extData: { "uniq": r() }, pinned: true }, + { entries: [{ url: "http://example.org/#2" }], extData: { "uniq": r() }, pinned: true }, + { entries: [{ url: "http://example.org/#3" }], extData: { "uniq": r() }, pinned: true }, + { entries: [{ url: "http://example.org/#4" }], extData: { "uniq": r() } }, + { entries: [{ url: "http://example.org/#5" }], extData: { "uniq": r() } }, + { entries: [{ url: "http://example.org/#6" }], extData: { "uniq": r() } }, + { entries: [{ url: "http://example.org/#7" }], extData: { "uniq": r() } }, + ], selected: 5 }] }; + + let loadCount = 0; + let nextTestTimer; + function test_restore_apptabs_ondemand_progressCallback(aBrowser) { + loadCount++; + + // get the tab + let tab; + for (let i = 0; i < window.gBrowser.tabs.length; i++) { + if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser) + tab = window.gBrowser.tabs[i]; + } + + // Check that the load only comes from the selected tab. + ok(gBrowser.selectedTab == tab, + "test_restore_apptabs_ondemand: load came from selected tab"); + + // We should get only 1 load: the selected tab + if (loadCount == 1) { + nextTestTimer = setTimeout(nextTest, 1000); + return; + } + else if (loadCount > 1) { + clearTimeout(nextTestTimer); + } + + function nextTest() { + window.gBrowser.removeTabsProgressListener(progressListener); + runNextTest(); + } + nextTest(); + } + + window.gBrowser.addTabsProgressListener(progressListener); + ss.setBrowserState(JSON.stringify(state)); +} + + function countTabs() { let needsRestore = 0, isRestoring = 0,