Bug 1002843 - Wait until important parts have been initialized before restoring tabs into windows r=smacleod

This commit is contained in:
Tim Taubert 2014-05-03 08:11:43 +02:00
Родитель d01bf252c5
Коммит 28b75bf5ec
11 изменённых файлов: 95 добавлений и 124 удалений

Просмотреть файл

@ -858,9 +858,11 @@ var gBrowserInit = {
} }
} }
// Certain kinds of automigration rely on this notification to complete their // Certain kinds of automigration rely on this notification to complete
// tasks BEFORE the browser window is shown. // their tasks BEFORE the browser window is shown. SessionStore uses it to
Services.obs.notifyObservers(null, "browser-window-before-show", ""); // 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. // Set a sane starting width/height for all resolutions on new profiles.
if (!document.documentElement.hasAttribute("width")) { if (!document.documentElement.hasAttribute("width")) {

Просмотреть файл

@ -30,7 +30,7 @@ const MAX_CONCURRENT_TAB_RESTORES = 3;
// global notifications observed // global notifications observed
const OBSERVING = [ const OBSERVING = [
"domwindowopened", "domwindowclosed", "browser-window-before-show", "domwindowclosed",
"quit-application-requested", "quit-application-granted", "quit-application-requested", "quit-application-granted",
"browser-lastwindow-close-granted", "browser-lastwindow-close-granted",
"quit-application", "browser:purge-session-history", "quit-application", "browser:purge-session-history",
@ -540,8 +540,8 @@ let SessionStoreInternal = {
*/ */
observe: function ssi_observe(aSubject, aTopic, aData) { observe: function ssi_observe(aSubject, aTopic, aData) {
switch (aTopic) { switch (aTopic) {
case "domwindowopened": // catch new windows case "browser-window-before-show": // catch new windows
this.onOpen(aSubject); this.onBeforeBrowserWindowShown(aSubject);
break; break;
case "domwindowclosed": // catch closed windows case "domwindowclosed": // catch closed windows
this.onClose(aSubject); this.onClose(aSubject);
@ -919,71 +919,59 @@ let SessionStoreInternal = {
}, },
/** /**
* On window open * Called right before a new browser window is shown.
* @param aWindow * @param aWindow
* Window reference * Window reference
*/ */
onOpen: function ssi_onOpen(aWindow) { onBeforeBrowserWindowShown: function (aWindow) {
let onload = () => { // Just call onLoad() directly if we're initialized already.
aWindow.removeEventListener("load", onload); 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. // Wait for the given window's delayed startup to be finished.
if (windowType != "navigator:browser") { 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; return;
} }
if (this._sessionInitialized) { if (this._sessionInitialized) {
this.onLoad(aWindow); 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();
} }
}, console.error);
// 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);
}, },
/** /**

Просмотреть файл

@ -31,9 +31,7 @@ function test() {
// open a window and add the above closed tab list // open a window and add the above closed tab list
let newWin = openDialog(location, "", "chrome,all,dialog=no"); let newWin = openDialog(location, "", "chrome,all,dialog=no");
newWin.addEventListener("load", function(aEvent) { promiseWindowLoaded(newWin).then(() => {
newWin.removeEventListener("load", arguments.callee, false);
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
test_state.windows[0]._closedTabs.length); test_state.windows[0]._closedTabs.length);
ss.setWindowState(newWin, JSON.stringify(test_state), true); ss.setWindowState(newWin, JSON.stringify(test_state), true);
@ -71,5 +69,5 @@ function test() {
newWin.close(); newWin.close();
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"); gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
finish(); finish();
}, false); });
} }

Просмотреть файл

@ -52,9 +52,7 @@ function test() {
// open a window and add the above closed tab list // open a window and add the above closed tab list
let newWin = openDialog(location, "", "chrome,all,dialog=no"); let newWin = openDialog(location, "", "chrome,all,dialog=no");
newWin.addEventListener("load", function(aEvent) { promiseWindowLoaded(newWin).then(() => {
newWin.removeEventListener("load", arguments.callee, false);
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", gPrefService.setIntPref("browser.sessionstore.max_tabs_undo",
test_state.windows[0]._closedTabs.length); test_state.windows[0]._closedTabs.length);
ss.setWindowState(newWin, JSON.stringify(test_state), true); ss.setWindowState(newWin, JSON.stringify(test_state), true);
@ -83,5 +81,5 @@ function test() {
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"); gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
finish(); finish();
}); });
}, false); });
} }

Просмотреть файл

@ -15,9 +15,7 @@ function test() {
// open a window and set a value on it // open a window and set a value on it
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no"); let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
newWin.addEventListener("load", function(aEvent) { promiseWindowLoaded(newWin).then(() => {
newWin.removeEventListener("load", arguments.callee, false);
ss.setWindowValue(newWin, uniqueKey1, uniqueValue1); ss.setWindowValue(newWin, uniqueKey1, uniqueValue1);
let newState = { windows: [{ tabs:[{ entries: [] }], extData: {} }] }; let newState = { windows: [{ tabs:[{ entries: [] }], extData: {} }] };
@ -44,5 +42,5 @@ function test() {
// clean up // clean up
newWin.close(); newWin.close();
finish(); finish();
}, false); });
} }

Просмотреть файл

@ -7,9 +7,7 @@ function test() {
waitForExplicitFinish(); waitForExplicitFinish();
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no"); let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
newWin.addEventListener("load", function(aEvent) { promiseWindowLoaded(newWin).then(() => {
newWin.removeEventListener("load", arguments.callee, false);
let newState = { windows: [{ let newState = { windows: [{
tabs: [{ entries: [] }], tabs: [{ entries: [] }],
_closedTabs: [{ _closedTabs: [{
@ -59,5 +57,5 @@ function test() {
}, 0); }, 0);
}, 0); }, 0);
}, 0); }, 0);
}, false); });
} }

Просмотреть файл

@ -80,8 +80,7 @@ function test() {
// open a window and add the above closed window list // open a window and add the above closed window list
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no"); let newWin = openDialog(location, "_blank", "chrome,all,dialog=no");
newWin.addEventListener("load", function(aEvent) { promiseWindowLoaded(newWin).then(() => {
this.removeEventListener("load", arguments.callee, false);
gPrefService.setIntPref("browser.sessionstore.max_windows_undo", gPrefService.setIntPref("browser.sessionstore.max_windows_undo",
test_state._closedWindows.length); test_state._closedWindows.length);
ss.setWindowState(newWin, JSON.stringify(test_state), true); ss.setWindowState(newWin, JSON.stringify(test_state), true);
@ -117,5 +116,5 @@ function test() {
newWin.close(); newWin.close();
gPrefService.clearUserPref("browser.sessionstore.max_windows_undo"); gPrefService.clearUserPref("browser.sessionstore.max_windows_undo");
finish(); finish();
}, false); });
} }

Просмотреть файл

@ -8,47 +8,38 @@ function test() {
waitForExplicitFinish(); waitForExplicitFinish();
let newWin = openDialog(location, "_blank", "chrome,all,dialog=no,toolbar=yes"); let newWin = openDialog(location, "_blank", "chrome,all,dialog=no,toolbar=yes");
newWin.addEventListener("load", function() { promiseWindowLoaded(newWin).then(() => {
newWin.removeEventListener("load", arguments.callee, false); let state1 = ss.getWindowState(newWin);
newWin.close();
executeSoon(function() { newWin = openDialog(location, "_blank",
let state1 = ss.getWindowState(newWin); "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar=no,location,personal,directories,dialog=no");
promiseWindowLoaded(newWin).then(() => {
let state2 = ss.getWindowState(newWin);
newWin.close(); newWin.close();
newWin = openDialog(location, "_blank", function testState(state, expected, callback) {
"chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar=no,location,personal,directories,dialog=no"); let win = openDialog(location, "_blank", "chrome,all,dialog=no");
newWin.addEventListener("load", function() { promiseWindowLoaded(win).then(() => {
newWin.removeEventListener("load", arguments.callee, false);
executeSoon(function() { is(win.gURLBar.readOnly, false,
let state2 = ss.getWindowState(newWin); "URL bar should not be read-only before setting the state");
newWin.close(); 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) { win.close();
let win = openDialog(location, "_blank", "chrome,all,dialog=no"); executeSoon(callback);
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);
});
}); });
}, false); }
testState(state1, {readOnly: false, enablehistory: "true"}, function() {
testState(state2, {readOnly: true, enablehistory: "false"}, finish);
});
}); });
}, false); });
} }

Просмотреть файл

@ -17,11 +17,10 @@ function test() {
browserWindowsCount(1); browserWindowsCount(1);
var win = openDialog(location, "", "chrome,all,dialog=no"); var win = openDialog(location, "", "chrome,all,dialog=no");
win.addEventListener("load", function () { promiseWindowLoaded(win).then(() => {
win.removeEventListener("load", arguments.callee, false);
browserWindowsCount(2); browserWindowsCount(2);
win.close(); win.close();
browserWindowsCount(1); browserWindowsCount(1);
finish(); finish();
}, false); });
} }

Просмотреть файл

@ -10,9 +10,7 @@ function test() {
// open a new window and setup the window state. // open a new window and setup the window state.
newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no"); newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
newWin.addEventListener("load", function onLoad(event) { whenWindowLoaded(newWin, function () {
this.removeEventListener("load", onLoad, false);
let newState = { let newState = {
windows: [{ windows: [{
tabs: [{ tabs: [{
@ -69,5 +67,5 @@ function test() {
} }
newWin.addEventListener("tabviewshown", onTabViewShow, false); newWin.addEventListener("tabviewshown", onTabViewShow, false);
waitForFocus(function() { newWin.TabView.toggle(); }); waitForFocus(function() { newWin.TabView.toggle(); });
}, false); });
} }

Просмотреть файл

@ -142,8 +142,10 @@ function afterAllTabsLoaded(callback, win) {
browser.__SS_restoreState && browser.__SS_restoreState &&
browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE); browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE);
if (isRestorable && browser.contentDocument.readyState != "complete" || let isLoading = browser.webProgress.isLoadingDocument ||
browser.webProgress.isLoadingDocument) { browser.contentDocument.readyState != "complete";
if (isRestorable && isLoading) {
stillToLoad++; stillToLoad++;
browser.addEventListener("load", onLoad, true); browser.addEventListener("load", onLoad, true);
} }