diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index a1ef3499d1e6..1e32b39c64e1 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -858,9 +858,11 @@ var gBrowserInit = { } } - // Certain kinds of automigration rely on this notification to complete their - // tasks BEFORE the browser window is shown. - Services.obs.notifyObservers(null, "browser-window-before-show", ""); + // Certain kinds of automigration rely on this notification to complete + // their tasks BEFORE the browser window is shown. SessionStore uses it to + // restore tabs into windows AFTER important parts like gMultiProcessBrowser + // have been initialized. + Services.obs.notifyObservers(window, "browser-window-before-show", ""); // Set a sane starting width/height for all resolutions on new profiles. if (!document.documentElement.hasAttribute("width")) { diff --git a/browser/components/sessionstore/src/SessionStore.jsm b/browser/components/sessionstore/src/SessionStore.jsm index cff3994d7a93..16c7ad142716 100644 --- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -30,7 +30,7 @@ const MAX_CONCURRENT_TAB_RESTORES = 3; // global notifications observed const OBSERVING = [ - "domwindowopened", "domwindowclosed", + "browser-window-before-show", "domwindowclosed", "quit-application-requested", "quit-application-granted", "browser-lastwindow-close-granted", "quit-application", "browser:purge-session-history", @@ -540,8 +540,8 @@ let SessionStoreInternal = { */ observe: function ssi_observe(aSubject, aTopic, aData) { switch (aTopic) { - case "domwindowopened": // catch new windows - this.onOpen(aSubject); + case "browser-window-before-show": // catch new windows + this.onBeforeBrowserWindowShown(aSubject); break; case "domwindowclosed": // catch closed windows this.onClose(aSubject); @@ -919,71 +919,59 @@ let SessionStoreInternal = { }, /** - * On window open + * Called right before a new browser window is shown. * @param aWindow * Window reference */ - onOpen: function ssi_onOpen(aWindow) { - let onload = () => { - aWindow.removeEventListener("load", onload); + onBeforeBrowserWindowShown: function (aWindow) { + // Just call onLoad() directly if we're initialized already. + if (this._sessionInitialized) { + this.onLoad(aWindow); + return; + } - let windowType = aWindow.document.documentElement.getAttribute("windowtype"); + // The very first window that is opened creates a promise that is then + // re-used by all subsequent windows. The promise will be used to tell + // when we're ready for initialization. + if (!this._promiseReadyForInitialization) { + let deferred = Promise.defer(); - // Ignore non-browser windows. - if (windowType != "navigator:browser") { + // Wait for the given window's delayed startup to be finished. + Services.obs.addObserver(function obs(subject, topic) { + if (aWindow == subject) { + Services.obs.removeObserver(obs, topic); + deferred.resolve(); + } + }, "browser-delayed-startup-finished", false); + + // We are ready for initialization as soon as the session file has been + // read from disk and the initial window's delayed startup has finished. + this._promiseReadyForInitialization = + Promise.all([deferred.promise, gSessionStartup.onceInitialized]); + } + + // We can't call this.onLoad since initialization + // hasn't completed, so we'll wait until it is done. + // Even if additional windows are opened and wait + // for initialization as well, the first opened + // window should execute first, and this.onLoad + // will be called with the initialState. + this._promiseReadyForInitialization.then(() => { + if (aWindow.closed) { return; } if (this._sessionInitialized) { this.onLoad(aWindow); - return; + } else { + let initialState = this.initSession(); + this._sessionInitialized = true; + this.onLoad(aWindow, initialState); + + // Let everyone know we're done. + this._deferredInitialized.resolve(); } - - // The very first window that is opened creates a promise that is then - // re-used by all subsequent windows. The promise will be used to tell - // when we're ready for initialization. - if (!this._promiseReadyForInitialization) { - let deferred = Promise.defer(); - - // Wait for the given window's delayed startup to be finished. - Services.obs.addObserver(function obs(subject, topic) { - if (aWindow == subject) { - Services.obs.removeObserver(obs, topic); - deferred.resolve(); - } - }, "browser-delayed-startup-finished", false); - - // We are ready for initialization as soon as the session file has been - // read from disk and the initial window's delayed startup has finished. - this._promiseReadyForInitialization = - Promise.all([deferred.promise, gSessionStartup.onceInitialized]); - } - - // We can't call this.onLoad since initialization - // hasn't completed, so we'll wait until it is done. - // Even if additional windows are opened and wait - // for initialization as well, the first opened - // window should execute first, and this.onLoad - // will be called with the initialState. - this._promiseReadyForInitialization.then(() => { - if (aWindow.closed) { - return; - } - - if (this._sessionInitialized) { - this.onLoad(aWindow); - } else { - let initialState = this.initSession(); - this._sessionInitialized = true; - this.onLoad(aWindow, initialState); - - // Let everyone know we're done. - this._deferredInitialized.resolve(); - } - }, console.error); - }; - - aWindow.addEventListener("load", onload); + }, console.error); }, /** diff --git a/browser/components/sessionstore/test/browser_461634.js b/browser/components/sessionstore/test/browser_461634.js index 931f12ccb952..2417f82010e6 100644 --- a/browser/components/sessionstore/test/browser_461634.js +++ b/browser/components/sessionstore/test/browser_461634.js @@ -31,9 +31,7 @@ function test() { // open a window and add the above closed tab list let newWin = openDialog(location, "", "chrome,all,dialog=no"); - newWin.addEventListener("load", function(aEvent) { - newWin.removeEventListener("load", arguments.callee, false); - + promiseWindowLoaded(newWin).then(() => { gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", test_state.windows[0]._closedTabs.length); ss.setWindowState(newWin, JSON.stringify(test_state), true); @@ -71,5 +69,5 @@ function test() { newWin.close(); gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"); finish(); - }, false); + }); } diff --git a/browser/components/sessionstore/test/browser_464199.js b/browser/components/sessionstore/test/browser_464199.js index f3593ae9e652..1f46f70635a9 100644 --- a/browser/components/sessionstore/test/browser_464199.js +++ b/browser/components/sessionstore/test/browser_464199.js @@ -52,9 +52,7 @@ function test() { // open a window and add the above closed tab list let newWin = openDialog(location, "", "chrome,all,dialog=no"); - newWin.addEventListener("load", function(aEvent) { - newWin.removeEventListener("load", arguments.callee, false); - + promiseWindowLoaded(newWin).then(() => { gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", test_state.windows[0]._closedTabs.length); ss.setWindowState(newWin, JSON.stringify(test_state), true); @@ -83,5 +81,5 @@ function test() { gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"); finish(); }); - }, false); + }); } diff --git a/browser/components/sessionstore/test/browser_465223.js b/browser/components/sessionstore/test/browser_465223.js index 4becc7d15b80..a7bdcd6acbf4 100644 --- a/browser/components/sessionstore/test/browser_465223.js +++ b/browser/components/sessionstore/test/browser_465223.js @@ -15,9 +15,7 @@ function test() { // open a window and set a value on it let newWin = openDialog(location, "_blank", "chrome,all,dialog=no"); - newWin.addEventListener("load", function(aEvent) { - newWin.removeEventListener("load", arguments.callee, false); - + promiseWindowLoaded(newWin).then(() => { ss.setWindowValue(newWin, uniqueKey1, uniqueValue1); let newState = { windows: [{ tabs:[{ entries: [] }], extData: {} }] }; @@ -44,5 +42,5 @@ function test() { // clean up newWin.close(); finish(); - }, false); + }); } diff --git a/browser/components/sessionstore/test/browser_477657.js b/browser/components/sessionstore/test/browser_477657.js index 7c6562166441..71bac2381da2 100644 --- a/browser/components/sessionstore/test/browser_477657.js +++ b/browser/components/sessionstore/test/browser_477657.js @@ -7,9 +7,7 @@ function test() { waitForExplicitFinish(); let newWin = openDialog(location, "_blank", "chrome,all,dialog=no"); - newWin.addEventListener("load", function(aEvent) { - newWin.removeEventListener("load", arguments.callee, false); - + promiseWindowLoaded(newWin).then(() => { let newState = { windows: [{ tabs: [{ entries: [] }], _closedTabs: [{ @@ -59,5 +57,5 @@ function test() { }, 0); }, 0); }, 0); - }, false); + }); } diff --git a/browser/components/sessionstore/test/browser_491577.js b/browser/components/sessionstore/test/browser_491577.js index 7626db1a403a..3ef45a97d5ae 100644 --- a/browser/components/sessionstore/test/browser_491577.js +++ b/browser/components/sessionstore/test/browser_491577.js @@ -80,8 +80,7 @@ function test() { // open a window and add the above closed window list let newWin = openDialog(location, "_blank", "chrome,all,dialog=no"); - newWin.addEventListener("load", function(aEvent) { - this.removeEventListener("load", arguments.callee, false); + promiseWindowLoaded(newWin).then(() => { gPrefService.setIntPref("browser.sessionstore.max_windows_undo", test_state._closedWindows.length); ss.setWindowState(newWin, JSON.stringify(test_state), true); @@ -117,5 +116,5 @@ function test() { newWin.close(); gPrefService.clearUserPref("browser.sessionstore.max_windows_undo"); finish(); - }, false); + }); } diff --git a/browser/components/sessionstore/test/browser_495495.js b/browser/components/sessionstore/test/browser_495495.js index 982bcdcaf061..5c0378569e92 100644 --- a/browser/components/sessionstore/test/browser_495495.js +++ b/browser/components/sessionstore/test/browser_495495.js @@ -8,47 +8,38 @@ function test() { waitForExplicitFinish(); let newWin = openDialog(location, "_blank", "chrome,all,dialog=no,toolbar=yes"); - newWin.addEventListener("load", function() { - newWin.removeEventListener("load", arguments.callee, false); + promiseWindowLoaded(newWin).then(() => { + let state1 = ss.getWindowState(newWin); + newWin.close(); - executeSoon(function() { - let state1 = ss.getWindowState(newWin); + newWin = openDialog(location, "_blank", + "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar=no,location,personal,directories,dialog=no"); + promiseWindowLoaded(newWin).then(() => { + let state2 = ss.getWindowState(newWin); newWin.close(); - newWin = openDialog(location, "_blank", - "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar=no,location,personal,directories,dialog=no"); - newWin.addEventListener("load", function() { - newWin.removeEventListener("load", arguments.callee, false); + function testState(state, expected, callback) { + let win = openDialog(location, "_blank", "chrome,all,dialog=no"); + promiseWindowLoaded(win).then(() => { - executeSoon(function() { - let state2 = ss.getWindowState(newWin); - newWin.close(); + is(win.gURLBar.readOnly, false, + "URL bar should not be read-only before setting the state"); + is(win.gURLBar.getAttribute("enablehistory"), "true", + "URL bar autocomplete should be enabled before setting the state"); + ss.setWindowState(win, state, true); + is(win.gURLBar.readOnly, expected.readOnly, + "URL bar read-only state should be restored correctly"); + is(win.gURLBar.getAttribute("enablehistory"), expected.enablehistory, + "URL bar autocomplete state should be restored correctly"); - function testState(state, expected, callback) { - let win = openDialog(location, "_blank", "chrome,all,dialog=no"); - win.addEventListener("load", function() { - win.removeEventListener("load", arguments.callee, false); - - is(win.gURLBar.readOnly, false, - "URL bar should not be read-only before setting the state"); - is(win.gURLBar.getAttribute("enablehistory"), "true", - "URL bar autocomplete should be enabled before setting the state"); - ss.setWindowState(win, state, true); - is(win.gURLBar.readOnly, expected.readOnly, - "URL bar read-only state should be restored correctly"); - is(win.gURLBar.getAttribute("enablehistory"), expected.enablehistory, - "URL bar autocomplete state should be restored correctly"); - - win.close(); - executeSoon(callback); - }, false); - } - - testState(state1, {readOnly: false, enablehistory: "true"}, function() { - testState(state2, {readOnly: true, enablehistory: "false"}, finish); - }); + win.close(); + executeSoon(callback); }); - }, false); + } + + testState(state1, {readOnly: false, enablehistory: "true"}, function() { + testState(state2, {readOnly: true, enablehistory: "false"}, finish); + }); }); - }, false); + }); } diff --git a/browser/components/sessionstore/test/browser_528776.js b/browser/components/sessionstore/test/browser_528776.js index b25812195bd4..ca88ec66fa6d 100644 --- a/browser/components/sessionstore/test/browser_528776.js +++ b/browser/components/sessionstore/test/browser_528776.js @@ -17,11 +17,10 @@ function test() { browserWindowsCount(1); var win = openDialog(location, "", "chrome,all,dialog=no"); - win.addEventListener("load", function () { - win.removeEventListener("load", arguments.callee, false); + promiseWindowLoaded(win).then(() => { browserWindowsCount(2); win.close(); browserWindowsCount(1); finish(); - }, false); + }); } diff --git a/browser/components/tabview/test/browser_tabview_bug598600.js b/browser/components/tabview/test/browser_tabview_bug598600.js index 930918e7f885..a0d3e9580d2e 100644 --- a/browser/components/tabview/test/browser_tabview_bug598600.js +++ b/browser/components/tabview/test/browser_tabview_bug598600.js @@ -10,9 +10,7 @@ function test() { // open a new window and setup the window state. newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no"); - newWin.addEventListener("load", function onLoad(event) { - this.removeEventListener("load", onLoad, false); - + whenWindowLoaded(newWin, function () { let newState = { windows: [{ tabs: [{ @@ -69,5 +67,5 @@ function test() { } newWin.addEventListener("tabviewshown", onTabViewShow, false); waitForFocus(function() { newWin.TabView.toggle(); }); - }, false); + }); } diff --git a/browser/components/tabview/test/head.js b/browser/components/tabview/test/head.js index d9ded0b960c7..1ec86710963c 100644 --- a/browser/components/tabview/test/head.js +++ b/browser/components/tabview/test/head.js @@ -142,8 +142,10 @@ function afterAllTabsLoaded(callback, win) { browser.__SS_restoreState && browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE); - if (isRestorable && browser.contentDocument.readyState != "complete" || - browser.webProgress.isLoadingDocument) { + let isLoading = browser.webProgress.isLoadingDocument || + browser.contentDocument.readyState != "complete"; + + if (isRestorable && isLoading) { stillToLoad++; browser.addEventListener("load", onLoad, true); }