summaryrefslogtreecommitdiffstats
path: root/browser/modules/NetworkPrioritizer.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'browser/modules/NetworkPrioritizer.jsm')
-rw-r--r--browser/modules/NetworkPrioritizer.jsm194
1 files changed, 194 insertions, 0 deletions
diff --git a/browser/modules/NetworkPrioritizer.jsm b/browser/modules/NetworkPrioritizer.jsm
new file mode 100644
index 000000000..770a30e09
--- /dev/null
+++ b/browser/modules/NetworkPrioritizer.jsm
@@ -0,0 +1,194 @@
+/* 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 adjusts network priority for tabs in a way that gives 'important'
+ * tabs a higher priority. There are 3 levels of priority. Each is listed below
+ * with the priority adjustment used.
+ *
+ * Highest (-10): Selected tab in the focused window.
+ * Medium (0): Background tabs in the focused window.
+ * Selected tab in background windows.
+ * Lowest (+10): Background tabs in background windows.
+ */
+
+this.EXPORTED_SYMBOLS = ["trackBrowserWindow"];
+
+const Ci = Components.interfaces;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+
+// Lazy getters
+XPCOMUtils.defineLazyServiceGetter(this, "_focusManager",
+ "@mozilla.org/focus-manager;1",
+ "nsIFocusManager");
+
+
+// Constants
+const TAB_EVENTS = ["TabBrowserInserted", "TabSelect", "TabRemotenessChange"];
+const WINDOW_EVENTS = ["activate", "unload"];
+// lower value means higher priority
+const PRIORITY_DELTA = Ci.nsISupportsPriority.PRIORITY_NORMAL - Ci.nsISupportsPriority.PRIORITY_LOW;
+
+
+// Variables
+var _lastFocusedWindow = null;
+var _windows = [];
+// this is used for restoring the priority after TabRemotenessChange
+var _priorityBackup = new WeakMap();
+
+
+// Exported symbol
+this.trackBrowserWindow = function trackBrowserWindow(aWindow) {
+ WindowHelper.addWindow(aWindow);
+}
+
+
+// Global methods
+function _handleEvent(aEvent) {
+ switch (aEvent.type) {
+ case "TabBrowserInserted":
+ BrowserHelper.onOpen(aEvent.target.linkedBrowser);
+ break;
+ case "TabSelect":
+ BrowserHelper.onSelect(aEvent.target.linkedBrowser);
+ break;
+ case "activate":
+ WindowHelper.onActivate(aEvent.target);
+ break;
+ case "TabRemotenessChange":
+ BrowserHelper.onRemotenessChange(aEvent.target.linkedBrowser);
+ break;
+ case "unload":
+ WindowHelper.removeWindow(aEvent.currentTarget);
+ break;
+ }
+}
+
+
+// Methods that impact a browser. Put into single object for organization.
+var BrowserHelper = {
+ onOpen: function NP_BH_onOpen(aBrowser) {
+ _priorityBackup.set(aBrowser.permanentKey, Ci.nsISupportsPriority.PRIORITY_NORMAL);
+
+ // If the tab is in the focused window, leave priority as it is
+ if (aBrowser.ownerGlobal != _lastFocusedWindow)
+ this.decreasePriority(aBrowser);
+ },
+
+ onSelect: function NP_BH_onSelect(aBrowser) {
+ let windowEntry = WindowHelper.getEntry(aBrowser.ownerGlobal);
+ if (windowEntry.lastSelectedBrowser)
+ this.decreasePriority(windowEntry.lastSelectedBrowser);
+ this.increasePriority(aBrowser);
+
+ windowEntry.lastSelectedBrowser = aBrowser;
+ },
+
+ onRemotenessChange: function (aBrowser) {
+ aBrowser.setPriority(_priorityBackup.get(aBrowser.permanentKey));
+ },
+
+ increasePriority: function NP_BH_increasePriority(aBrowser) {
+ aBrowser.adjustPriority(PRIORITY_DELTA);
+ _priorityBackup.set(aBrowser.permanentKey,
+ _priorityBackup.get(aBrowser.permanentKey) + PRIORITY_DELTA);
+ },
+
+ decreasePriority: function NP_BH_decreasePriority(aBrowser) {
+ aBrowser.adjustPriority(PRIORITY_DELTA * -1);
+ _priorityBackup.set(aBrowser.permanentKey,
+ _priorityBackup.get(aBrowser.permanentKey) - PRIORITY_DELTA);
+ }
+};
+
+
+// Methods that impact a window. Put into single object for organization.
+var WindowHelper = {
+ addWindow: function NP_WH_addWindow(aWindow) {
+ // Build internal data object
+ _windows.push({ window: aWindow, lastSelectedBrowser: null });
+
+ // Add event listeners
+ TAB_EVENTS.forEach(function(event) {
+ aWindow.gBrowser.tabContainer.addEventListener(event, _handleEvent, false);
+ });
+ WINDOW_EVENTS.forEach(function(event) {
+ aWindow.addEventListener(event, _handleEvent, false);
+ });
+
+ // This gets called AFTER activate event, so if this is the focused window
+ // we want to activate it. Otherwise, deprioritize it.
+ if (aWindow == _focusManager.activeWindow)
+ this.handleFocusedWindow(aWindow);
+ else
+ this.decreasePriority(aWindow);
+
+ // Select the selected tab
+ BrowserHelper.onSelect(aWindow.gBrowser.selectedBrowser);
+ },
+
+ removeWindow: function NP_WH_removeWindow(aWindow) {
+ if (aWindow == _lastFocusedWindow)
+ _lastFocusedWindow = null;
+
+ // Delete this window from our tracking
+ _windows.splice(this.getEntryIndex(aWindow), 1);
+
+ // Remove the event listeners
+ TAB_EVENTS.forEach(function(event) {
+ aWindow.gBrowser.tabContainer.removeEventListener(event, _handleEvent, false);
+ });
+ WINDOW_EVENTS.forEach(function(event) {
+ aWindow.removeEventListener(event, _handleEvent, false);
+ });
+ },
+
+ onActivate: function NP_WH_onActivate(aWindow, aHasFocus) {
+ // If this window was the last focused window, we don't need to do anything
+ if (aWindow == _lastFocusedWindow)
+ return;
+
+ // handleFocusedWindow will deprioritize the current window
+ this.handleFocusedWindow(aWindow);
+
+ // Lastly we should increase priority for this window
+ this.increasePriority(aWindow);
+ },
+
+ handleFocusedWindow: function NP_WH_handleFocusedWindow(aWindow) {
+ // If we have a last focused window, we need to deprioritize it first
+ if (_lastFocusedWindow)
+ this.decreasePriority(_lastFocusedWindow);
+
+ // aWindow is now focused
+ _lastFocusedWindow = aWindow;
+ },
+
+ // Auxiliary methods
+ increasePriority: function NP_WH_increasePriority(aWindow) {
+ aWindow.gBrowser.browsers.forEach(function(aBrowser) {
+ BrowserHelper.increasePriority(aBrowser);
+ });
+ },
+
+ decreasePriority: function NP_WH_decreasePriority(aWindow) {
+ aWindow.gBrowser.browsers.forEach(function(aBrowser) {
+ BrowserHelper.decreasePriority(aBrowser);
+ });
+ },
+
+ getEntry: function NP_WH_getEntry(aWindow) {
+ return _windows[this.getEntryIndex(aWindow)];
+ },
+
+ getEntryIndex: function NP_WH_getEntryAtIndex(aWindow) {
+ // Assumes that every object has a unique window & it's in the array
+ for (let i = 0; i < _windows.length; i++)
+ if (_windows[i].window == aWindow)
+ return i;
+ }
+};
+