mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1067648 - Introduce restoreTab() and use it from restoreTabs() r=billm
This commit is contained in:
parent
7950fcbec7
commit
0e9469ca26
@ -346,6 +346,9 @@ let SessionStoreInternal = {
|
||||
// and restore the session.
|
||||
_promiseReadyForInitialization: null,
|
||||
|
||||
// Keep busy state counters per window.
|
||||
_windowBusyStates: new WeakMap(),
|
||||
|
||||
/**
|
||||
* A promise fulfilled once initialization is complete.
|
||||
*/
|
||||
@ -1556,8 +1559,7 @@ let SessionStoreInternal = {
|
||||
this._resetTabRestoringState(aTab);
|
||||
}
|
||||
|
||||
this._setWindowStateBusy(window);
|
||||
this.restoreTabs(window, [aTab], [tabState], 0);
|
||||
this.restoreTab(aTab, tabState);
|
||||
},
|
||||
|
||||
duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
|
||||
@ -1579,14 +1581,11 @@ let SessionStoreInternal = {
|
||||
tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
|
||||
tabState.pinned = false;
|
||||
|
||||
this._setWindowStateBusy(aWindow);
|
||||
let newTab = aTab == aWindow.gBrowser.selectedTab ?
|
||||
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
|
||||
aWindow.gBrowser.addTab();
|
||||
|
||||
this.restoreTabs(aWindow, [newTab], [tabState], 0,
|
||||
true /* Load this tab right away. */);
|
||||
|
||||
this.restoreTab(newTab, tabState, true /* Load this tab right away. */);
|
||||
return newTab;
|
||||
},
|
||||
|
||||
@ -1632,13 +1631,12 @@ let SessionStoreInternal = {
|
||||
let closedTab = closedTabs.splice(aIndex, 1).shift();
|
||||
let closedTabState = closedTab.state;
|
||||
|
||||
this._setWindowStateBusy(aWindow);
|
||||
// create a new tab
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
let tab = tabbrowser.addTab();
|
||||
let tab = tabbrowser.selectedTab = tabbrowser.addTab();
|
||||
|
||||
// restore tab content
|
||||
this.restoreTabs(aWindow, [tab], [closedTabState], 1);
|
||||
this.restoreTab(tab, closedTabState);
|
||||
|
||||
// restore the tab's position
|
||||
tabbrowser.moveTabTo(tab, closedTab.pos);
|
||||
@ -2383,8 +2381,11 @@ let SessionStoreInternal = {
|
||||
newClosedTabsData.slice(0, this._max_tabs_undo);
|
||||
}
|
||||
|
||||
this.restoreTabs(aWindow, tabs, winData.tabs,
|
||||
(overwriteTabs ? (parseInt(winData.selected || "1")) : 0));
|
||||
// Restore tabs, if any.
|
||||
if (winData.tabs.length) {
|
||||
this.restoreTabs(aWindow, tabs, winData.tabs,
|
||||
(overwriteTabs ? (parseInt(winData.selected || "1")) : 0));
|
||||
}
|
||||
|
||||
if (aState.scratchpads) {
|
||||
ScratchpadManager.restoreSession(aState.scratchpads);
|
||||
@ -2395,6 +2396,7 @@ let SessionStoreInternal = {
|
||||
|
||||
TelemetryStopwatch.finish("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
|
||||
|
||||
this._setWindowStateReady(aWindow);
|
||||
this._sendRestoreCompletedNotifications();
|
||||
},
|
||||
|
||||
@ -2410,14 +2412,8 @@ let SessionStoreInternal = {
|
||||
* Index of the tab to select. This is a 1-based index where "1"
|
||||
* indicates the first tab should be selected, and "0" indicates that
|
||||
* the currently selected tab will not be changed.
|
||||
* @param aRestoreImmediately
|
||||
* Flag to indicate whether the given set of tabs aTabs should be
|
||||
* restored/loaded immediately even if restore_on_demand = true
|
||||
*/
|
||||
restoreTabs: function (aWindow, aTabs, aTabData, aSelectTab,
|
||||
aRestoreImmediately = false)
|
||||
{
|
||||
|
||||
restoreTabs(aWindow, aTabs, aTabData, aSelectTab) {
|
||||
var tabbrowser = aWindow.gBrowser;
|
||||
|
||||
if (!this._isWindowLoaded(aWindow)) {
|
||||
@ -2427,130 +2423,150 @@ let SessionStoreInternal = {
|
||||
delete this._windows[aWindow.__SSi]._restoring;
|
||||
}
|
||||
|
||||
// It's important to set the window state to dirty so that
|
||||
// we collect their data for the first time when saving state.
|
||||
DirtyWindows.add(aWindow);
|
||||
let numTabsToRestore = aTabs.length;
|
||||
let numTabsInWindow = tabbrowser.tabs.length;
|
||||
let tabsDataArray = this._windows[aWindow.__SSi].tabs;
|
||||
|
||||
// Set the state to restore as the window's current state. Normally, this
|
||||
// will just be overridden the next time we collect state but we need this
|
||||
// as a fallback should Firefox be shutdown early without notifying us
|
||||
// beforehand.
|
||||
this._windows[aWindow.__SSi].tabs = aTabData.slice();
|
||||
this._windows[aWindow.__SSi].selected = aSelectTab;
|
||||
|
||||
if (aTabs.length == 0) {
|
||||
// This is normally done later, but as we're returning early
|
||||
// here we need to take care of it.
|
||||
this._setWindowStateReady(aWindow);
|
||||
return;
|
||||
// Update the window state in case we shut down without being notified.
|
||||
// Individual tab states will be taken care of by restoreTab() below.
|
||||
if (numTabsInWindow == numTabsToRestore) {
|
||||
// Remove all previous tab data.
|
||||
tabsDataArray.length = 0;
|
||||
} else {
|
||||
// Remove all previous tab data except tabs that should not be overriden.
|
||||
tabsDataArray.splice(numTabsInWindow - numTabsToRestore);
|
||||
}
|
||||
|
||||
// Let the tab data array have the right number of slots.
|
||||
tabsDataArray.length = numTabsInWindow;
|
||||
|
||||
// If provided, set the selected tab.
|
||||
if (aSelectTab > 0 && aSelectTab <= aTabs.length) {
|
||||
tabbrowser.selectedTab = aTabs[aSelectTab - 1];
|
||||
|
||||
// Update the window state in case we shut down without being notified.
|
||||
this._windows[aWindow.__SSi].selected = aSelectTab;
|
||||
}
|
||||
|
||||
// Prepare the tabs so that they can be properly restored. We'll pin/unpin
|
||||
// and show/hide tabs as necessary. We'll also set the labels, user typed
|
||||
// value, and attach a copy of the tab's data in case we close it before
|
||||
// it's been restored.
|
||||
// Restore all tabs.
|
||||
for (let t = 0; t < aTabs.length; t++) {
|
||||
let tab = aTabs[t];
|
||||
let browser = tabbrowser.getBrowserForTab(tab);
|
||||
let tabData = aTabData[t];
|
||||
this.restoreTab(aTabs[t], aTabData[t]);
|
||||
}
|
||||
},
|
||||
|
||||
if (tabData.pinned)
|
||||
tabbrowser.pinTab(tab);
|
||||
else
|
||||
tabbrowser.unpinTab(tab);
|
||||
// Restores the given tab state for a given tab.
|
||||
restoreTab(tab, tabData, restoreImmediately = false) {
|
||||
let browser = tab.linkedBrowser;
|
||||
let window = tab.ownerDocument.defaultView;
|
||||
let tabbrowser = window.gBrowser;
|
||||
|
||||
if (tabData.hidden)
|
||||
tabbrowser.hideTab(tab);
|
||||
else
|
||||
tabbrowser.showTab(tab);
|
||||
// Increase the busy state counter before modifying the tab.
|
||||
this._setWindowStateBusy(window);
|
||||
|
||||
if (tabData.lastAccessed) {
|
||||
tab.lastAccessed = tabData.lastAccessed;
|
||||
}
|
||||
// It's important to set the window state to dirty so that
|
||||
// we collect their data for the first time when saving state.
|
||||
DirtyWindows.add(window);
|
||||
|
||||
if ("attributes" in tabData) {
|
||||
// Ensure that we persist tab attributes restored from previous sessions.
|
||||
Object.keys(tabData.attributes).forEach(a => TabAttributes.persist(a));
|
||||
}
|
||||
// Update the tab state in case we shut down without being notified.
|
||||
this._windows[window.__SSi].tabs[tab._tPos] = tabData;
|
||||
|
||||
if (!tabData.entries) {
|
||||
tabData.entries = [];
|
||||
}
|
||||
if (tabData.extData) {
|
||||
tab.__SS_extdata = {};
|
||||
for (let key in tabData.extData)
|
||||
tab.__SS_extdata[key] = tabData.extData[key];
|
||||
} else {
|
||||
delete tab.__SS_extdata;
|
||||
}
|
||||
delete tabData.closedAt; // Tab is now open.
|
||||
|
||||
// Flush all data from the content script synchronously. This is done so
|
||||
// that all async messages that are still on their way to chrome will
|
||||
// be ignored and don't override any tab data set when restoring.
|
||||
TabState.flush(tab.linkedBrowser);
|
||||
|
||||
// Ensure the index is in bounds.
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
|
||||
activeIndex = Math.max(activeIndex, 0);
|
||||
|
||||
// Save the index in case we updated it above.
|
||||
tabData.index = activeIndex + 1;
|
||||
|
||||
// In electrolysis, we may need to change the browser's remote
|
||||
// attribute so that it runs in a content process.
|
||||
let activePageData = tabData.entries[activeIndex] || null;
|
||||
let uri = activePageData ? activePageData.url || null : null;
|
||||
tabbrowser.updateBrowserRemotenessByURL(browser, uri);
|
||||
|
||||
// Start a new epoch and include the epoch in the restoreHistory
|
||||
// message. If a message is received that relates to a previous epoch, we
|
||||
// discard it.
|
||||
let epoch = this._nextRestoreEpoch++;
|
||||
this._browserEpochs.set(browser.permanentKey, epoch);
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
browser.__SS_data = tabData;
|
||||
browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
|
||||
browser.setAttribute("pending", "true");
|
||||
tab.setAttribute("pending", "true");
|
||||
|
||||
// Update the persistent tab state cache with |tabData| information.
|
||||
TabStateCache.update(browser, {
|
||||
history: {entries: tabData.entries, index: tabData.index},
|
||||
scroll: tabData.scroll || null,
|
||||
storage: tabData.storage || null,
|
||||
formdata: tabData.formdata || null,
|
||||
disallow: tabData.disallow || null,
|
||||
pageStyle: tabData.pageStyle || null
|
||||
});
|
||||
|
||||
browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory",
|
||||
{tabData: tabData, epoch: epoch});
|
||||
|
||||
// Restore tab attributes.
|
||||
if ("attributes" in tabData) {
|
||||
TabAttributes.set(tab, tabData.attributes);
|
||||
}
|
||||
|
||||
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
|
||||
// it ensures each window will have its selected tab loaded.
|
||||
if (aRestoreImmediately || tabbrowser.selectedBrowser == browser) {
|
||||
this.restoreTabContent(tab);
|
||||
} else {
|
||||
TabRestoreQueue.add(tab);
|
||||
this.restoreNextTab();
|
||||
}
|
||||
// Prepare the tab so that it can be properly restored. We'll pin/unpin
|
||||
// and show/hide tabs as necessary. We'll also attach a copy of the tab's
|
||||
// data in case we close it before it's been restored.
|
||||
if (tabData.pinned) {
|
||||
tabbrowser.pinTab(tab);
|
||||
} else {
|
||||
tabbrowser.unpinTab(tab);
|
||||
}
|
||||
|
||||
this._setWindowStateReady(aWindow);
|
||||
if (tabData.hidden) {
|
||||
tabbrowser.hideTab(tab);
|
||||
} else {
|
||||
tabbrowser.showTab(tab);
|
||||
}
|
||||
|
||||
if (tabData.lastAccessed) {
|
||||
tab.lastAccessed = tabData.lastAccessed;
|
||||
}
|
||||
|
||||
if ("attributes" in tabData) {
|
||||
// Ensure that we persist tab attributes restored from previous sessions.
|
||||
Object.keys(tabData.attributes).forEach(a => TabAttributes.persist(a));
|
||||
}
|
||||
|
||||
if (!tabData.entries) {
|
||||
tabData.entries = [];
|
||||
}
|
||||
if (tabData.extData) {
|
||||
tab.__SS_extdata = Cu.cloneInto(tabData.extData, {});
|
||||
} else {
|
||||
delete tab.__SS_extdata;
|
||||
}
|
||||
|
||||
// Tab is now open.
|
||||
delete tabData.closedAt;
|
||||
|
||||
// Flush all data from the content script synchronously. This is done so
|
||||
// that all async messages that are still on their way to chrome will
|
||||
// be ignored and don't override any tab data set when restoring.
|
||||
TabState.flush(browser);
|
||||
|
||||
// Ensure the index is in bounds.
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
|
||||
activeIndex = Math.max(activeIndex, 0);
|
||||
|
||||
// Save the index in case we updated it above.
|
||||
tabData.index = activeIndex + 1;
|
||||
|
||||
// In electrolysis, we may need to change the browser's remote
|
||||
// attribute so that it runs in a content process.
|
||||
let activePageData = tabData.entries[activeIndex] || null;
|
||||
let uri = activePageData ? activePageData.url || null : null;
|
||||
tabbrowser.updateBrowserRemotenessByURL(browser, uri);
|
||||
|
||||
// Start a new epoch and include the epoch in the restoreHistory
|
||||
// message. If a message is received that relates to a previous epoch, we
|
||||
// discard it.
|
||||
let epoch = this._nextRestoreEpoch++;
|
||||
this._browserEpochs.set(browser.permanentKey, epoch);
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
browser.__SS_data = tabData;
|
||||
browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
|
||||
browser.setAttribute("pending", "true");
|
||||
tab.setAttribute("pending", "true");
|
||||
|
||||
// Update the persistent tab state cache with |tabData| information.
|
||||
TabStateCache.update(browser, {
|
||||
history: {entries: tabData.entries, index: tabData.index},
|
||||
scroll: tabData.scroll || null,
|
||||
storage: tabData.storage || null,
|
||||
formdata: tabData.formdata || null,
|
||||
disallow: tabData.disallow || null,
|
||||
pageStyle: tabData.pageStyle || null
|
||||
});
|
||||
|
||||
browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory",
|
||||
{tabData: tabData, epoch: epoch});
|
||||
|
||||
// Restore tab attributes.
|
||||
if ("attributes" in tabData) {
|
||||
TabAttributes.set(tab, tabData.attributes);
|
||||
}
|
||||
|
||||
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
|
||||
// it ensures each window will have its selected tab loaded.
|
||||
if (restoreImmediately || tabbrowser.selectedBrowser == browser) {
|
||||
this.restoreTabContent(tab);
|
||||
} else {
|
||||
TabRestoreQueue.add(tab);
|
||||
this.restoreNextTab();
|
||||
}
|
||||
|
||||
// Decrease the busy state counter after we're done.
|
||||
this._setWindowStateReady(window);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -3240,8 +3256,16 @@ let SessionStoreInternal = {
|
||||
* @param aWindow the window
|
||||
*/
|
||||
_setWindowStateReady: function ssi_setWindowStateReady(aWindow) {
|
||||
this._setWindowStateBusyValue(aWindow, false);
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
let newCount = (this._windowBusyStates.get(aWindow) || 0) - 1;
|
||||
if (newCount < 0) {
|
||||
throw new Error("Invalid window busy state (less than zero).");
|
||||
}
|
||||
this._windowBusyStates.set(aWindow, newCount);
|
||||
|
||||
if (newCount == 0) {
|
||||
this._setWindowStateBusyValue(aWindow, false);
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -3249,8 +3273,13 @@ let SessionStoreInternal = {
|
||||
* @param aWindow the window
|
||||
*/
|
||||
_setWindowStateBusy: function ssi_setWindowStateBusy(aWindow) {
|
||||
this._setWindowStateBusyValue(aWindow, true);
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
let newCount = (this._windowBusyStates.get(aWindow) || 0) + 1;
|
||||
this._windowBusyStates.set(aWindow, newCount);
|
||||
|
||||
if (newCount == 1) {
|
||||
this._setWindowStateBusyValue(aWindow, true);
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user