зеркало из https://github.com/mozilla/gecko-dev.git
Bug 662812 - Panorama isn't aware of the current SSWindowState when being initialized; r=zpao
This commit is contained in:
Родитель
332ca401eb
Коммит
f3bb27e32e
|
@ -184,6 +184,23 @@ let Storage = {
|
|||
return existingData;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: readWindowBusyState
|
||||
// Returns the current busyState for the given window.
|
||||
readWindowBusyState: function Storage_readWindowBusyState(win) {
|
||||
let state;
|
||||
|
||||
try {
|
||||
let data = this._sessionStore.getWindowState(win);
|
||||
if (data)
|
||||
state = JSON.parse(data);
|
||||
} catch (e) {
|
||||
Utils.log("Error while parsing window state");
|
||||
}
|
||||
|
||||
return (state && state.windows[0].busy);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveGroupItemsData
|
||||
// Saves the global data for the <GroupItems> singleton for the given window.
|
||||
|
|
|
@ -123,9 +123,9 @@ let UI = {
|
|||
wasInTabView: false
|
||||
},
|
||||
|
||||
// Variable: _storageBusyCount
|
||||
// Used to keep track of how many calls to storageBusy vs storageReady.
|
||||
_storageBusyCount: 0,
|
||||
// Variable: _storageBusy
|
||||
// Tells whether the storage is currently busy or not.
|
||||
_storageBusy: false,
|
||||
|
||||
// Variable: isDOMWindowClosing
|
||||
// Tells wether the parent window is about to close
|
||||
|
@ -169,6 +169,10 @@ let UI = {
|
|||
|
||||
// ___ storage
|
||||
Storage.init();
|
||||
|
||||
if (Storage.readWindowBusyState(gWindow))
|
||||
this.storageBusy();
|
||||
|
||||
let data = Storage.readUIData(gWindow);
|
||||
this._storageSanity(data);
|
||||
this._pageBounds = data.pageBounds;
|
||||
|
@ -612,12 +616,13 @@ let UI = {
|
|||
// Pauses the storage activity that conflicts with sessionstore updates and
|
||||
// private browsing mode switches. Calls can be nested.
|
||||
storageBusy: function UI_storageBusy() {
|
||||
if (!this._storageBusyCount) {
|
||||
TabItems.pauseReconnecting();
|
||||
GroupItems.pauseAutoclose();
|
||||
}
|
||||
|
||||
this._storageBusyCount++;
|
||||
if (this._storageBusy)
|
||||
return;
|
||||
|
||||
this._storageBusy = true;
|
||||
|
||||
TabItems.pauseReconnecting();
|
||||
GroupItems.pauseAutoclose();
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -625,16 +630,18 @@ let UI = {
|
|||
// Resumes the activity paused by storageBusy, and updates for any new group
|
||||
// information in sessionstore. Calls can be nested.
|
||||
storageReady: function UI_storageReady() {
|
||||
this._storageBusyCount--;
|
||||
if (!this._storageBusyCount) {
|
||||
let hasGroupItemsData = GroupItems.load();
|
||||
if (!hasGroupItemsData)
|
||||
this.reset();
|
||||
|
||||
TabItems.resumeReconnecting();
|
||||
GroupItems._updateTabBar();
|
||||
GroupItems.resumeAutoclose();
|
||||
}
|
||||
if (!this._storageBusy)
|
||||
return;
|
||||
|
||||
this._storageBusy = false;
|
||||
|
||||
let hasGroupItemsData = GroupItems.load();
|
||||
if (!hasGroupItemsData)
|
||||
this.reset();
|
||||
|
||||
TabItems.resumeReconnecting();
|
||||
GroupItems._updateTabBar();
|
||||
GroupItems.resumeAutoclose();
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -730,7 +737,7 @@ let UI = {
|
|||
} else {
|
||||
// If we're currently in the process of entering private browsing,
|
||||
// we don't want to go to the Tab View UI.
|
||||
if (self._storageBusyCount)
|
||||
if (self._storageBusy)
|
||||
return;
|
||||
|
||||
// if not closing the last tab
|
||||
|
|
|
@ -37,26 +37,20 @@ function setupTwo(win) {
|
|||
contentWindow.TabItems.update(tabItem.tab);
|
||||
tabItem.addSubscriber("savedCachedImageData", function onSaved(item) {
|
||||
item.removeSubscriber("savedCachedImageData", onSaved);
|
||||
--numTabsToSave;
|
||||
|
||||
if (!--numTabsToSave)
|
||||
restoreWindow();
|
||||
});
|
||||
});
|
||||
|
||||
// after the window is closed, restore it.
|
||||
let xulWindowDestory = function() {
|
||||
Services.obs.removeObserver(
|
||||
xulWindowDestory, "xul-window-destroyed", false);
|
||||
|
||||
// "xul-window-destroyed" is just fired just before a XUL window is
|
||||
// destroyed so restore window and test it after a delay
|
||||
let restoreWindow = function() {
|
||||
executeSoon(function() {
|
||||
restoredWin = undoCloseWindow();
|
||||
restoredWin.addEventListener("load", function onLoad(event) {
|
||||
restoredWin.removeEventListener("load", onLoad, false);
|
||||
|
||||
registerCleanupFunction(function() restoredWin.close());
|
||||
|
||||
// ensure that closed tabs have been saved
|
||||
is(numTabsToSave, 0, "All tabs were saved when window was closed.");
|
||||
is(restoredWin.gBrowser.tabs.length, 3, "The total number of tabs is 3");
|
||||
|
||||
// setup tab variables and listen to the tabs load progress
|
||||
|
@ -103,7 +97,6 @@ function setupTwo(win) {
|
|||
}, false);
|
||||
});
|
||||
};
|
||||
Services.obs.addObserver(xulWindowDestory, "xul-window-destroyed", false);
|
||||
|
||||
win.close();
|
||||
}
|
||||
|
|
|
@ -49,11 +49,15 @@ function onTabViewLoadedAndShown() {
|
|||
groupTitles[a] = gi.getTitle();
|
||||
}
|
||||
|
||||
contentWindow.gPrefBranch.setBoolPref("animate_zoom", false);
|
||||
|
||||
// Create a second tab
|
||||
gBrowser.addTab("about:robots");
|
||||
is(gBrowser.tabs.length, 2, "we now have 2 tabs");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
contentWindow.gPrefBranch.clearUserPref("animate_zoom");
|
||||
});
|
||||
|
||||
afterAllTabsLoaded(function() {
|
||||
|
|
|
@ -361,7 +361,10 @@ function togglePrivateBrowsing(callback) {
|
|||
|
||||
Services.obs.addObserver(function observe() {
|
||||
Services.obs.removeObserver(observe, topic);
|
||||
afterAllTabsLoaded(callback);
|
||||
|
||||
// use executeSoon() to let Panorama load its group data from the session
|
||||
// before we call afterAllTabsLoaded()
|
||||
executeSoon(function () afterAllTabsLoaded(callback));
|
||||
}, topic, false);
|
||||
|
||||
let pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
|
|
|
@ -762,7 +762,7 @@ SessionStoreService.prototype = {
|
|||
aWindow.__SSi = "window" + Date.now();
|
||||
|
||||
// and create its data object
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [] };
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
|
||||
if (!this._isWindowLoaded(aWindow))
|
||||
this._windows[aWindow.__SSi]._restoring = true;
|
||||
if (!aWindow.toolbar.visible)
|
||||
|
@ -946,6 +946,9 @@ SessionStoreService.prototype = {
|
|||
// save the window if it has multiple tabs or a single saveable tab
|
||||
if (winData.tabs.length > 1 ||
|
||||
(winData.tabs.length == 1 && this._shouldSaveTabState(winData.tabs[0]))) {
|
||||
// we don't want to save the busy state
|
||||
delete winData.busy;
|
||||
|
||||
this._closedWindows.unshift(winData);
|
||||
this._capClosedWindows();
|
||||
}
|
||||
|
@ -1242,7 +1245,7 @@ SessionStoreService.prototype = {
|
|||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
var window = aTab.ownerDocument.defaultView;
|
||||
this._sendWindowStateEvent(window, "Busy");
|
||||
this._setWindowStateBusy(window);
|
||||
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
|
||||
},
|
||||
|
||||
|
@ -1258,7 +1261,7 @@ SessionStoreService.prototype = {
|
|||
tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
|
||||
tabState.pinned = false;
|
||||
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
this._setWindowStateBusy(aWindow);
|
||||
let newTab = aTab == aWindow.gBrowser.selectedTab ?
|
||||
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
|
||||
aWindow.gBrowser.addTab();
|
||||
|
@ -1301,7 +1304,7 @@ SessionStoreService.prototype = {
|
|||
let closedTab = closedTabs.splice(aIndex, 1).shift();
|
||||
let closedTabState = closedTab.state;
|
||||
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
this._setWindowStateBusy(aWindow);
|
||||
// create a new tab
|
||||
let browser = aWindow.gBrowser;
|
||||
let tab = browser.addTab();
|
||||
|
@ -2511,7 +2514,7 @@ SessionStoreService.prototype = {
|
|||
|
||||
// We're not returning from this before we end up calling restoreHistoryPrecursor
|
||||
// for this window, so make sure we send the SSWindowStateBusy event.
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
this._setWindowStateBusy(aWindow);
|
||||
|
||||
if (root._closedWindows)
|
||||
this._closedWindows = root._closedWindows;
|
||||
|
@ -2698,7 +2701,7 @@ SessionStoreService.prototype = {
|
|||
if (aTabs.length == 0) {
|
||||
// this is normally done in restoreHistory() but as we're returning early
|
||||
// here we need to take care of it.
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
this._setWindowStateReady(aWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2843,7 +2846,7 @@ SessionStoreService.prototype = {
|
|||
if (aTabs.length == 0) {
|
||||
// At this point we're essentially ready for consumers to read/write data
|
||||
// via the sessionstore API so we'll send the SSWindowStateReady event.
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
this._setWindowStateReady(aWindow);
|
||||
return; // no more tabs to restore
|
||||
}
|
||||
|
||||
|
@ -3981,6 +3984,42 @@ SessionStoreService.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given window's busy state
|
||||
* @param aWindow the window
|
||||
* @param aValue the window's busy state
|
||||
*/
|
||||
_setWindowStateBusyValue:
|
||||
function sss__changeWindowStateBusyValue(aWindow, aValue) {
|
||||
|
||||
this._windows[aWindow.__SSi].busy = aValue;
|
||||
|
||||
// Keep the to-be-restored state in sync because that is returned by
|
||||
// getWindowState() as long as the window isn't loaded, yet.
|
||||
if (!this._isWindowLoaded(aWindow)) {
|
||||
let stateToRestore = this._statesToRestore[aWindow.__SS_restoreID].windows[0];
|
||||
stateToRestore.busy = aValue;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given window's state to 'not busy'.
|
||||
* @param aWindow the window
|
||||
*/
|
||||
_setWindowStateReady: function sss__setWindowStateReady(aWindow) {
|
||||
this._setWindowStateBusyValue(aWindow, false);
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given window's state to 'busy'.
|
||||
* @param aWindow the window
|
||||
*/
|
||||
_setWindowStateBusy: function sss__setWindowStateBusy(aWindow) {
|
||||
this._setWindowStateBusyValue(aWindow, true);
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatch an SSWindowState_____ event for the given window.
|
||||
* @param aWindow the window
|
||||
|
|
|
@ -150,6 +150,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_635418.js \
|
||||
browser_636279.js \
|
||||
browser_659591.js \
|
||||
browser_662812.js \
|
||||
$(NULL)
|
||||
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
const TAB_STATE_NEEDS_RESTORE = 1;
|
||||
const TAB_STATE_RESTORING = 2;
|
||||
|
||||
let stateBackup = ss.getBrowserState();
|
||||
|
||||
let state = {windows:[{tabs:[
|
||||
{entries:[{url:"http://example.com#1"}]},
|
||||
{entries:[{url:"http://example.com#2"}]},
|
||||
|
@ -23,22 +21,14 @@ function test() {
|
|||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs");
|
||||
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
|
||||
|
||||
TabsProgressListener.uninit();
|
||||
|
||||
ss.setBrowserState(stateBackup);
|
||||
});
|
||||
|
||||
TabsProgressListener.init();
|
||||
|
||||
Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 3);
|
||||
|
||||
// First stage: restoreHiddenTabs = true
|
||||
// Second stage: restoreHiddenTabs = false
|
||||
test_loadTabs(true, function () {
|
||||
test_loadTabs(false, function () {
|
||||
waitForFocus(finish);
|
||||
});
|
||||
test_loadTabs(false, finish);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -46,10 +36,9 @@ function test_loadTabs(restoreHiddenTabs, callback) {
|
|||
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", restoreHiddenTabs);
|
||||
|
||||
let expectedTabs = restoreHiddenTabs ? 8 : 4;
|
||||
|
||||
let firstProgress = true;
|
||||
|
||||
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
|
||||
newWindowWithState(state, function (win, needsRestore, isRestoring) {
|
||||
if (firstProgress) {
|
||||
firstProgress = false;
|
||||
is(isRestoring, 3, "restoring 3 tabs concurrently");
|
||||
|
@ -57,60 +46,75 @@ function test_loadTabs(restoreHiddenTabs, callback) {
|
|||
ok(isRestoring < 4, "restoring max. 3 tabs concurrently");
|
||||
}
|
||||
|
||||
if (gBrowser.tabs.length - needsRestore == expectedTabs) {
|
||||
TabsProgressListener.unsetCallback();
|
||||
is(gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
|
||||
if (win.gBrowser.tabs.length - needsRestore == expectedTabs) {
|
||||
is(win.gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
|
||||
|
||||
TabsProgressListener.uninit();
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
ss.setBrowserState(JSON.stringify(state));
|
||||
}
|
||||
|
||||
function countTabs() {
|
||||
let needsRestore = 0, isRestoring = 0;
|
||||
let windowsEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
|
||||
while (windowsEnum.hasMoreElements()) {
|
||||
let window = windowsEnum.getNext();
|
||||
if (window.closed)
|
||||
continue;
|
||||
|
||||
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||
let browser = window.gBrowser.tabs[i].linkedBrowser;
|
||||
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||
isRestoring++;
|
||||
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||
needsRestore++;
|
||||
}
|
||||
}
|
||||
|
||||
return [needsRestore, isRestoring];
|
||||
}
|
||||
|
||||
let TabsProgressListener = {
|
||||
init: function () {
|
||||
gBrowser.addTabsProgressListener(this);
|
||||
init: function (win) {
|
||||
this.window = win;
|
||||
|
||||
this.window.gBrowser.addTabsProgressListener(this);
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
this.unsetCallback();
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
this.window.gBrowser.removeTabsProgressListener(this);
|
||||
|
||||
delete this.window;
|
||||
delete this.callback;
|
||||
},
|
||||
|
||||
setCallback: function (callback) {
|
||||
this.callback = callback;
|
||||
},
|
||||
|
||||
unsetCallback: function () {
|
||||
delete this.callback;
|
||||
},
|
||||
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (this.callback && aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
||||
this.callback.apply(null, countTabs());
|
||||
this.callback.apply(null, [this.window].concat(this.countTabs()));
|
||||
},
|
||||
|
||||
countTabs: function () {
|
||||
let needsRestore = 0, isRestoring = 0;
|
||||
|
||||
for (let i = 0; i < this.window.gBrowser.tabs.length; i++) {
|
||||
let browser = this.window.gBrowser.tabs[i].linkedBrowser;
|
||||
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||
isRestoring++;
|
||||
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||
needsRestore++;
|
||||
}
|
||||
|
||||
return [needsRestore, isRestoring];
|
||||
}
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenWindowLoaded(win, callback) {
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
executeSoon(callback);
|
||||
}, false);
|
||||
}
|
||||
|
||||
// ----------
|
||||
function newWindowWithState(state, callback) {
|
||||
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", opts);
|
||||
|
||||
registerCleanupFunction(function () win.close());
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
TabsProgressListener.init(win);
|
||||
TabsProgressListener.setCallback(callback);
|
||||
|
||||
ss.setWindowState(win, JSON.stringify(state), true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("SSWindowStateBusy", function onBusy() {
|
||||
window.removeEventListener("SSWindowStateBusy", onBusy, false);
|
||||
|
||||
let state = JSON.parse(ss.getWindowState(window));
|
||||
ok(state.windows[0].busy, "window is busy");
|
||||
|
||||
window.addEventListener("SSWindowStateReady", function onReady() {
|
||||
window.removeEventListener("SSWindowStateReady", onReady, false);
|
||||
|
||||
let state = JSON.parse(ss.getWindowState(window));
|
||||
ok(!state.windows[0].busy, "window is not busy");
|
||||
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
executeSoon(finish);
|
||||
}, false);
|
||||
}, false);
|
||||
|
||||
// create a new tab
|
||||
let tab = gBrowser.addTab("about:mozilla");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// close and restore it
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
gBrowser.removeTab(tab);
|
||||
ss.undoCloseTab(window, 0);
|
||||
}, true);
|
||||
}
|
Загрузка…
Ссылка в новой задаче