1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/modules/NetworkPrioritizer.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,179 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * This module adjusts network priority for tabs in a way that gives 'important' 1.10 + * tabs a higher priority. There are 3 levels of priority. Each is listed below 1.11 + * with the priority adjustment used. 1.12 + * 1.13 + * Highest (-10): Selected tab in the focused window. 1.14 + * Medium (0): Background tabs in the focused window. 1.15 + * Selected tab in background windows. 1.16 + * Lowest (+10): Background tabs in background windows. 1.17 + */ 1.18 + 1.19 +this.EXPORTED_SYMBOLS = ["trackBrowserWindow"]; 1.20 + 1.21 +const Ci = Components.interfaces; 1.22 + 1.23 +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); 1.24 + 1.25 + 1.26 +// Lazy getters 1.27 +XPCOMUtils.defineLazyServiceGetter(this, "_focusManager", 1.28 + "@mozilla.org/focus-manager;1", 1.29 + "nsIFocusManager"); 1.30 + 1.31 + 1.32 +// Constants 1.33 +const TAB_EVENTS = ["TabOpen", "TabSelect"]; 1.34 +const WINDOW_EVENTS = ["activate", "unload"]; 1.35 +// PRIORITY DELTA is -10 because lower priority value is actually a higher priority 1.36 +const PRIORITY_DELTA = -10; 1.37 + 1.38 + 1.39 +// Variables 1.40 +let _lastFocusedWindow = null; 1.41 +let _windows = []; 1.42 + 1.43 + 1.44 +// Exported symbol 1.45 +this.trackBrowserWindow = function trackBrowserWindow(aWindow) { 1.46 + WindowHelper.addWindow(aWindow); 1.47 +} 1.48 + 1.49 + 1.50 +// Global methods 1.51 +function _handleEvent(aEvent) { 1.52 + switch (aEvent.type) { 1.53 + case "TabOpen": 1.54 + BrowserHelper.onOpen(aEvent.target.linkedBrowser); 1.55 + break; 1.56 + case "TabSelect": 1.57 + BrowserHelper.onSelect(aEvent.target.linkedBrowser); 1.58 + break; 1.59 + case "activate": 1.60 + WindowHelper.onActivate(aEvent.target); 1.61 + break; 1.62 + case "unload": 1.63 + WindowHelper.removeWindow(aEvent.currentTarget); 1.64 + break; 1.65 + } 1.66 +} 1.67 + 1.68 + 1.69 +// Methods that impact a browser. Put into single object for organization. 1.70 +let BrowserHelper = { 1.71 + onOpen: function NP_BH_onOpen(aBrowser) { 1.72 + // If the tab is in the focused window, leave priority as it is 1.73 + if (aBrowser.ownerDocument.defaultView != _lastFocusedWindow) 1.74 + this.decreasePriority(aBrowser); 1.75 + }, 1.76 + 1.77 + onSelect: function NP_BH_onSelect(aBrowser) { 1.78 + let windowEntry = WindowHelper.getEntry(aBrowser.ownerDocument.defaultView); 1.79 + if (windowEntry.lastSelectedBrowser) 1.80 + this.decreasePriority(windowEntry.lastSelectedBrowser); 1.81 + this.increasePriority(aBrowser); 1.82 + 1.83 + windowEntry.lastSelectedBrowser = aBrowser; 1.84 + }, 1.85 + 1.86 + increasePriority: function NP_BH_increasePriority(aBrowser) { 1.87 + aBrowser.adjustPriority(PRIORITY_DELTA); 1.88 + }, 1.89 + 1.90 + decreasePriority: function NP_BH_decreasePriority(aBrowser) { 1.91 + aBrowser.adjustPriority(PRIORITY_DELTA * -1); 1.92 + } 1.93 +}; 1.94 + 1.95 + 1.96 +// Methods that impact a window. Put into single object for organization. 1.97 +let WindowHelper = { 1.98 + addWindow: function NP_WH_addWindow(aWindow) { 1.99 + // Build internal data object 1.100 + _windows.push({ window: aWindow, lastSelectedBrowser: null }); 1.101 + 1.102 + // Add event listeners 1.103 + TAB_EVENTS.forEach(function(event) { 1.104 + aWindow.gBrowser.tabContainer.addEventListener(event, _handleEvent, false); 1.105 + }); 1.106 + WINDOW_EVENTS.forEach(function(event) { 1.107 + aWindow.addEventListener(event, _handleEvent, false); 1.108 + }); 1.109 + 1.110 + // This gets called AFTER activate event, so if this is the focused window 1.111 + // we want to activate it. Otherwise, deprioritize it. 1.112 + if (aWindow == _focusManager.activeWindow) 1.113 + this.handleFocusedWindow(aWindow); 1.114 + else 1.115 + this.decreasePriority(aWindow); 1.116 + 1.117 + // Select the selected tab 1.118 + BrowserHelper.onSelect(aWindow.gBrowser.selectedBrowser); 1.119 + }, 1.120 + 1.121 + removeWindow: function NP_WH_removeWindow(aWindow) { 1.122 + if (aWindow == _lastFocusedWindow) 1.123 + _lastFocusedWindow = null; 1.124 + 1.125 + // Delete this window from our tracking 1.126 + _windows.splice(this.getEntryIndex(aWindow), 1); 1.127 + 1.128 + // Remove the event listeners 1.129 + TAB_EVENTS.forEach(function(event) { 1.130 + aWindow.gBrowser.tabContainer.removeEventListener(event, _handleEvent, false); 1.131 + }); 1.132 + WINDOW_EVENTS.forEach(function(event) { 1.133 + aWindow.removeEventListener(event, _handleEvent, false); 1.134 + }); 1.135 + }, 1.136 + 1.137 + onActivate: function NP_WH_onActivate(aWindow, aHasFocus) { 1.138 + // If this window was the last focused window, we don't need to do anything 1.139 + if (aWindow == _lastFocusedWindow) 1.140 + return; 1.141 + 1.142 + // handleFocusedWindow will deprioritize the current window 1.143 + this.handleFocusedWindow(aWindow); 1.144 + 1.145 + // Lastly we should increase priority for this window 1.146 + this.increasePriority(aWindow); 1.147 + }, 1.148 + 1.149 + handleFocusedWindow: function NP_WH_handleFocusedWindow(aWindow) { 1.150 + // If we have a last focused window, we need to deprioritize it first 1.151 + if (_lastFocusedWindow) 1.152 + this.decreasePriority(_lastFocusedWindow); 1.153 + 1.154 + // aWindow is now focused 1.155 + _lastFocusedWindow = aWindow; 1.156 + }, 1.157 + 1.158 + // Auxiliary methods 1.159 + increasePriority: function NP_WH_increasePriority(aWindow) { 1.160 + aWindow.gBrowser.browsers.forEach(function(aBrowser) { 1.161 + BrowserHelper.increasePriority(aBrowser); 1.162 + }); 1.163 + }, 1.164 + 1.165 + decreasePriority: function NP_WH_decreasePriority(aWindow) { 1.166 + aWindow.gBrowser.browsers.forEach(function(aBrowser) { 1.167 + BrowserHelper.decreasePriority(aBrowser); 1.168 + }); 1.169 + }, 1.170 + 1.171 + getEntry: function NP_WH_getEntry(aWindow) { 1.172 + return _windows[this.getEntryIndex(aWindow)]; 1.173 + }, 1.174 + 1.175 + getEntryIndex: function NP_WH_getEntryAtIndex(aWindow) { 1.176 + // Assumes that every object has a unique window & it's in the array 1.177 + for (let i = 0; i < _windows.length; i++) 1.178 + if (_windows[i].window == aWindow) 1.179 + return i; 1.180 + } 1.181 +}; 1.182 +