2017-07-27 21:41:00 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This module tracks each browser window and informs network module
|
|
|
|
* the current selected tab's content outer window ID.
|
|
|
|
*/
|
|
|
|
|
2018-04-11 10:05:56 +00:00
|
|
|
var EXPORTED_SYMBOLS = ["BrowserWindowTracker"];
|
2017-07-27 21:41:00 +00:00
|
|
|
|
2018-01-29 23:20:18 +00:00
|
|
|
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
2017-07-27 21:41:00 +00:00
|
|
|
|
|
|
|
// Lazy getters
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "_focusManager",
|
|
|
|
"@mozilla.org/focus-manager;1",
|
|
|
|
"nsIFocusManager");
|
2018-04-11 10:05:56 +00:00
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
|
|
AppConstants: "resource://gre/modules/AppConstants.jsm",
|
|
|
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm"
|
|
|
|
});
|
2017-07-27 21:41:00 +00:00
|
|
|
|
|
|
|
// Constants
|
|
|
|
const TAB_EVENTS = ["TabBrowserInserted", "TabSelect"];
|
|
|
|
const WINDOW_EVENTS = ["activate", "unload"];
|
|
|
|
const DEBUG = false;
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
var _lastFocusedWindow = null;
|
|
|
|
var _lastTopLevelWindowID = 0;
|
|
|
|
|
|
|
|
// Global methods
|
|
|
|
function debug(s) {
|
|
|
|
if (DEBUG) {
|
|
|
|
dump("-*- UpdateTopLevelContentWindowIDHelper: " + s + "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
function _updateCurrentContentOuterWindowID(browser) {
|
|
|
|
if (!browser.outerWindowID ||
|
|
|
|
browser.outerWindowID === _lastTopLevelWindowID) {
|
2017-07-27 21:41:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
debug("Current window uri=" + browser.currentURI.spec +
|
|
|
|
" id=" + browser.outerWindowID);
|
2017-07-27 21:41:00 +00:00
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
_lastTopLevelWindowID = browser.outerWindowID;
|
2018-02-28 17:51:33 +00:00
|
|
|
let windowIDWrapper = Cc["@mozilla.org/supports-PRUint64;1"]
|
2017-07-27 21:41:00 +00:00
|
|
|
.createInstance(Ci.nsISupportsPRUint64);
|
|
|
|
windowIDWrapper.data = _lastTopLevelWindowID;
|
|
|
|
Services.obs.notifyObservers(windowIDWrapper,
|
|
|
|
"net:current-toplevel-outer-content-windowid");
|
|
|
|
}
|
|
|
|
|
|
|
|
function _handleEvent(aEvent) {
|
|
|
|
switch (aEvent.type) {
|
|
|
|
case "TabBrowserInserted":
|
|
|
|
if (aEvent.target.ownerGlobal.gBrowser.selectedBrowser === aEvent.target.linkedBrowser) {
|
|
|
|
_updateCurrentContentOuterWindowID(aEvent.target.linkedBrowser);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "TabSelect":
|
|
|
|
_updateCurrentContentOuterWindowID(aEvent.target.linkedBrowser);
|
|
|
|
break;
|
|
|
|
case "activate":
|
|
|
|
WindowHelper.onActivate(aEvent.target);
|
|
|
|
break;
|
|
|
|
case "unload":
|
|
|
|
WindowHelper.removeWindow(aEvent.currentTarget);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
function _handleMessage(message) {
|
|
|
|
let browser = message.target;
|
|
|
|
if (message.name === "Browser:Init" &&
|
2017-08-08 21:46:00 +00:00
|
|
|
browser === browser.ownerGlobal.gBrowser.selectedBrowser) {
|
|
|
|
_updateCurrentContentOuterWindowID(browser);
|
2017-07-27 21:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Methods that impact a window. Put into single object for organization.
|
|
|
|
var WindowHelper = {
|
2018-04-11 10:05:59 +00:00
|
|
|
addWindow(window) {
|
2017-07-27 21:41:00 +00:00
|
|
|
// Add event listeners
|
|
|
|
TAB_EVENTS.forEach(function(event) {
|
2018-04-11 10:05:59 +00:00
|
|
|
window.gBrowser.tabContainer.addEventListener(event, _handleEvent);
|
2017-07-27 21:41:00 +00:00
|
|
|
});
|
|
|
|
WINDOW_EVENTS.forEach(function(event) {
|
2018-04-11 10:05:59 +00:00
|
|
|
window.addEventListener(event, _handleEvent);
|
2017-07-27 21:41:00 +00:00
|
|
|
});
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
let messageManager = window.getGroupMessageManager("browsers");
|
2017-07-27 21:41:00 +00:00
|
|
|
messageManager.addMessageListener("Browser:Init", _handleMessage);
|
|
|
|
|
|
|
|
// This gets called AFTER activate event, so if this is the focused window
|
|
|
|
// we want to activate it.
|
2018-04-11 10:05:59 +00:00
|
|
|
if (window == _focusManager.activeWindow)
|
|
|
|
this.handleFocusedWindow(window);
|
2017-07-27 21:41:00 +00:00
|
|
|
|
|
|
|
// Update the selected tab's content outer window ID.
|
2018-04-11 10:05:59 +00:00
|
|
|
_updateCurrentContentOuterWindowID(window.gBrowser.selectedBrowser);
|
2017-07-27 21:41:00 +00:00
|
|
|
},
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
removeWindow(window) {
|
|
|
|
if (window == _lastFocusedWindow)
|
2017-07-27 21:41:00 +00:00
|
|
|
_lastFocusedWindow = null;
|
|
|
|
|
|
|
|
// Remove the event listeners
|
|
|
|
TAB_EVENTS.forEach(function(event) {
|
2018-04-11 10:05:59 +00:00
|
|
|
window.gBrowser.tabContainer.removeEventListener(event, _handleEvent);
|
2017-07-27 21:41:00 +00:00
|
|
|
});
|
|
|
|
WINDOW_EVENTS.forEach(function(event) {
|
2018-04-11 10:05:59 +00:00
|
|
|
window.removeEventListener(event, _handleEvent);
|
2017-07-27 21:41:00 +00:00
|
|
|
});
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
let messageManager = window.getGroupMessageManager("browsers");
|
2017-07-27 21:41:00 +00:00
|
|
|
messageManager.removeMessageListener("Browser:Init", _handleMessage);
|
|
|
|
},
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
onActivate(window, hasFocus) {
|
2017-07-27 21:41:00 +00:00
|
|
|
// If this window was the last focused window, we don't need to do anything
|
2018-04-11 10:05:59 +00:00
|
|
|
if (window == _lastFocusedWindow)
|
2017-07-27 21:41:00 +00:00
|
|
|
return;
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
this.handleFocusedWindow(window);
|
2017-07-27 21:41:00 +00:00
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
_updateCurrentContentOuterWindowID(window.gBrowser.selectedBrowser);
|
2017-07-27 21:41:00 +00:00
|
|
|
},
|
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
handleFocusedWindow(window) {
|
|
|
|
// window is now focused
|
|
|
|
_lastFocusedWindow = window;
|
2017-07-27 21:41:00 +00:00
|
|
|
},
|
2018-04-11 10:05:56 +00:00
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
getTopWindow(options) {
|
|
|
|
let checkPrivacy = typeof options == "object" &&
|
|
|
|
"private" in options;
|
2018-04-11 10:05:56 +00:00
|
|
|
|
2018-04-11 10:05:59 +00:00
|
|
|
let allowPopups = typeof options == "object" && !!options.allowPopups;
|
2018-04-11 10:05:56 +00:00
|
|
|
|
|
|
|
function isSuitableBrowserWindow(win) {
|
|
|
|
return (!win.closed &&
|
|
|
|
(allowPopups || win.toolbar.visible) &&
|
|
|
|
(!checkPrivacy ||
|
|
|
|
PrivateBrowsingUtils.permanentPrivateBrowsing ||
|
2018-04-11 10:05:59 +00:00
|
|
|
PrivateBrowsingUtils.isWindowPrivate(win) == options.private));
|
2018-04-11 10:05:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let broken_wm_z_order =
|
|
|
|
AppConstants.platform != "macosx" && AppConstants.platform != "win";
|
|
|
|
|
|
|
|
if (broken_wm_z_order) {
|
|
|
|
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
|
|
|
|
|
|
|
// if we're lucky, this isn't a popup, and we can just return this
|
|
|
|
if (win && !isSuitableBrowserWindow(win)) {
|
|
|
|
win = null;
|
|
|
|
let windowList = Services.wm.getEnumerator("navigator:browser");
|
|
|
|
// this is oldest to newest, so this gets a bit ugly
|
|
|
|
while (windowList.hasMoreElements()) {
|
|
|
|
let nextWin = windowList.getNext();
|
|
|
|
if (isSuitableBrowserWindow(nextWin))
|
|
|
|
win = nextWin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return win;
|
|
|
|
}
|
|
|
|
let windowList = Services.wm.getZOrderDOMWindowEnumerator("navigator:browser", true);
|
|
|
|
while (windowList.hasMoreElements()) {
|
|
|
|
let win = windowList.getNext();
|
|
|
|
if (isSuitableBrowserWindow(win))
|
|
|
|
return win;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
this.BrowserWindowTracker = {
|
|
|
|
/**
|
|
|
|
* Get the most recent browser window.
|
|
|
|
*
|
2018-04-11 10:05:59 +00:00
|
|
|
* @param options an object accepting the arguments for the search.
|
2018-04-11 10:05:56 +00:00
|
|
|
* * private: true to restrict the search to private windows
|
|
|
|
* only, false to restrict the search to non-private only.
|
|
|
|
* Omit the property to search in both groups.
|
|
|
|
* * allowPopups: true if popup windows are permissable.
|
|
|
|
*/
|
2018-04-11 10:05:59 +00:00
|
|
|
getTopWindow(options) {
|
|
|
|
return WindowHelper.getTopWindow(options);
|
2018-04-11 10:05:56 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
track(window) {
|
|
|
|
return WindowHelper.addWindow(window);
|
|
|
|
}
|
2017-07-27 21:41:00 +00:00
|
|
|
};
|