Bumping manifests a=b2g-bump
[gecko.git] / browser / modules / NetworkPrioritizer.jsm
blobea4a8779045905e6d6ca04c480a299b0db09dbb9
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);
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   }
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   }
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   }