Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * This module adjusts network priority for tabs in a way that gives 'important'
7 * tabs a higher priority. There are 3 levels of priority. Each is listed below
8 * with the priority adjustment used.
9 *
10 * Highest (-10): Selected tab in the focused window.
11 * Medium (0): Background tabs in the focused window.
12 * Selected tab in background windows.
13 * Lowest (+10): Background tabs in background windows.
14 */
16 this.EXPORTED_SYMBOLS = ["trackBrowserWindow"];
18 const Ci = Components.interfaces;
20 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
23 // Lazy getters
24 XPCOMUtils.defineLazyServiceGetter(this, "_focusManager",
25 "@mozilla.org/focus-manager;1",
26 "nsIFocusManager");
29 // Constants
30 const TAB_EVENTS = ["TabOpen", "TabSelect"];
31 const WINDOW_EVENTS = ["activate", "unload"];
32 // PRIORITY DELTA is -10 because lower priority value is actually a higher priority
33 const PRIORITY_DELTA = -10;
36 // Variables
37 let _lastFocusedWindow = null;
38 let _windows = [];
41 // Exported symbol
42 this.trackBrowserWindow = function trackBrowserWindow(aWindow) {
43 WindowHelper.addWindow(aWindow);
44 }
47 // Global methods
48 function _handleEvent(aEvent) {
49 switch (aEvent.type) {
50 case "TabOpen":
51 BrowserHelper.onOpen(aEvent.target.linkedBrowser);
52 break;
53 case "TabSelect":
54 BrowserHelper.onSelect(aEvent.target.linkedBrowser);
55 break;
56 case "activate":
57 WindowHelper.onActivate(aEvent.target);
58 break;
59 case "unload":
60 WindowHelper.removeWindow(aEvent.currentTarget);
61 break;
62 }
63 }
66 // Methods that impact a browser. Put into single object for organization.
67 let BrowserHelper = {
68 onOpen: function NP_BH_onOpen(aBrowser) {
69 // If the tab is in the focused window, leave priority as it is
70 if (aBrowser.ownerDocument.defaultView != _lastFocusedWindow)
71 this.decreasePriority(aBrowser);
72 },
74 onSelect: function NP_BH_onSelect(aBrowser) {
75 let windowEntry = WindowHelper.getEntry(aBrowser.ownerDocument.defaultView);
76 if (windowEntry.lastSelectedBrowser)
77 this.decreasePriority(windowEntry.lastSelectedBrowser);
78 this.increasePriority(aBrowser);
80 windowEntry.lastSelectedBrowser = aBrowser;
81 },
83 increasePriority: function NP_BH_increasePriority(aBrowser) {
84 aBrowser.adjustPriority(PRIORITY_DELTA);
85 },
87 decreasePriority: function NP_BH_decreasePriority(aBrowser) {
88 aBrowser.adjustPriority(PRIORITY_DELTA * -1);
89 }
90 };
93 // Methods that impact a window. Put into single object for organization.
94 let WindowHelper = {
95 addWindow: function NP_WH_addWindow(aWindow) {
96 // Build internal data object
97 _windows.push({ window: aWindow, lastSelectedBrowser: null });
99 // Add event listeners
100 TAB_EVENTS.forEach(function(event) {
101 aWindow.gBrowser.tabContainer.addEventListener(event, _handleEvent, false);
102 });
103 WINDOW_EVENTS.forEach(function(event) {
104 aWindow.addEventListener(event, _handleEvent, false);
105 });
107 // This gets called AFTER activate event, so if this is the focused window
108 // we want to activate it. Otherwise, deprioritize it.
109 if (aWindow == _focusManager.activeWindow)
110 this.handleFocusedWindow(aWindow);
111 else
112 this.decreasePriority(aWindow);
114 // Select the selected tab
115 BrowserHelper.onSelect(aWindow.gBrowser.selectedBrowser);
116 },
118 removeWindow: function NP_WH_removeWindow(aWindow) {
119 if (aWindow == _lastFocusedWindow)
120 _lastFocusedWindow = null;
122 // Delete this window from our tracking
123 _windows.splice(this.getEntryIndex(aWindow), 1);
125 // Remove the event listeners
126 TAB_EVENTS.forEach(function(event) {
127 aWindow.gBrowser.tabContainer.removeEventListener(event, _handleEvent, false);
128 });
129 WINDOW_EVENTS.forEach(function(event) {
130 aWindow.removeEventListener(event, _handleEvent, false);
131 });
132 },
134 onActivate: function NP_WH_onActivate(aWindow, aHasFocus) {
135 // If this window was the last focused window, we don't need to do anything
136 if (aWindow == _lastFocusedWindow)
137 return;
139 // handleFocusedWindow will deprioritize the current window
140 this.handleFocusedWindow(aWindow);
142 // Lastly we should increase priority for this window
143 this.increasePriority(aWindow);
144 },
146 handleFocusedWindow: function NP_WH_handleFocusedWindow(aWindow) {
147 // If we have a last focused window, we need to deprioritize it first
148 if (_lastFocusedWindow)
149 this.decreasePriority(_lastFocusedWindow);
151 // aWindow is now focused
152 _lastFocusedWindow = aWindow;
153 },
155 // Auxiliary methods
156 increasePriority: function NP_WH_increasePriority(aWindow) {
157 aWindow.gBrowser.browsers.forEach(function(aBrowser) {
158 BrowserHelper.increasePriority(aBrowser);
159 });
160 },
162 decreasePriority: function NP_WH_decreasePriority(aWindow) {
163 aWindow.gBrowser.browsers.forEach(function(aBrowser) {
164 BrowserHelper.decreasePriority(aBrowser);
165 });
166 },
168 getEntry: function NP_WH_getEntry(aWindow) {
169 return _windows[this.getEntryIndex(aWindow)];
170 },
172 getEntryIndex: function NP_WH_getEntryAtIndex(aWindow) {
173 // Assumes that every object has a unique window & it's in the array
174 for (let i = 0; i < _windows.length; i++)
175 if (_windows[i].window == aWindow)
176 return i;
177 }
178 };