NetworkPrioritizer.jsm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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/. */
  4. /*
  5. * This module adjusts network priority for tabs in a way that gives 'important'
  6. * tabs a higher priority. There are 3 levels of priority. Each is listed below
  7. * with the priority adjustment used.
  8. *
  9. * Highest (-10): Selected tab in the focused window.
  10. * Medium (0): Background tabs in the focused window.
  11. * Selected tab in background windows.
  12. * Lowest (+10): Background tabs in background windows.
  13. */
  14. this.EXPORTED_SYMBOLS = ["trackBrowserWindow"];
  15. const Ci = Components.interfaces;
  16. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  17. // Lazy getters
  18. XPCOMUtils.defineLazyServiceGetter(this, "_focusManager",
  19. "@mozilla.org/focus-manager;1",
  20. "nsIFocusManager");
  21. // Constants
  22. const TAB_EVENTS = ["TabOpen", "TabSelect"];
  23. const WINDOW_EVENTS = ["activate", "unload"];
  24. // PRIORITY DELTA is -10 because lower priority value is actually a higher priority
  25. const PRIORITY_DELTA = -10;
  26. // Variables
  27. var _lastFocusedWindow = null;
  28. var _windows = [];
  29. // Exported symbol
  30. this.trackBrowserWindow = function trackBrowserWindow(aWindow) {
  31. WindowHelper.addWindow(aWindow);
  32. }
  33. // Global methods
  34. function _handleEvent(aEvent) {
  35. switch (aEvent.type) {
  36. case "TabOpen":
  37. BrowserHelper.onOpen(aEvent.target.linkedBrowser);
  38. break;
  39. case "TabSelect":
  40. BrowserHelper.onSelect(aEvent.target.linkedBrowser);
  41. break;
  42. case "activate":
  43. WindowHelper.onActivate(aEvent.target);
  44. break;
  45. case "unload":
  46. WindowHelper.removeWindow(aEvent.currentTarget);
  47. break;
  48. }
  49. }
  50. // Methods that impact a browser. Put into single object for organization.
  51. var BrowserHelper = {
  52. onOpen: function(aBrowser) {
  53. // If the tab is in the focused window, leave priority as it is
  54. if (aBrowser.ownerDocument.defaultView != _lastFocusedWindow)
  55. this.decreasePriority(aBrowser);
  56. },
  57. onSelect: function(aBrowser) {
  58. let windowEntry = WindowHelper.getEntry(aBrowser.ownerDocument.defaultView);
  59. if (windowEntry.lastSelectedBrowser)
  60. this.decreasePriority(windowEntry.lastSelectedBrowser);
  61. this.increasePriority(aBrowser);
  62. windowEntry.lastSelectedBrowser = aBrowser;
  63. },
  64. increasePriority: function(aBrowser) {
  65. aBrowser.adjustPriority(PRIORITY_DELTA);
  66. },
  67. decreasePriority: function(aBrowser) {
  68. aBrowser.adjustPriority(PRIORITY_DELTA * -1);
  69. }
  70. };
  71. // Methods that impact a window. Put into single object for organization.
  72. var WindowHelper = {
  73. addWindow: function(aWindow) {
  74. // Build internal data object
  75. _windows.push({ window: aWindow, lastSelectedBrowser: null });
  76. // Add event listeners
  77. TAB_EVENTS.forEach(function(event) {
  78. aWindow.gBrowser.tabContainer.addEventListener(event, _handleEvent, false);
  79. });
  80. WINDOW_EVENTS.forEach(function(event) {
  81. aWindow.addEventListener(event, _handleEvent, false);
  82. });
  83. // This gets called AFTER activate event, so if this is the focused window
  84. // we want to activate it. Otherwise, deprioritize it.
  85. if (aWindow == _focusManager.activeWindow)
  86. this.handleFocusedWindow(aWindow);
  87. else
  88. this.decreasePriority(aWindow);
  89. // Select the selected tab
  90. BrowserHelper.onSelect(aWindow.gBrowser.selectedBrowser);
  91. },
  92. removeWindow: function(aWindow) {
  93. if (aWindow == _lastFocusedWindow)
  94. _lastFocusedWindow = null;
  95. // Delete this window from our tracking
  96. _windows.splice(this.getEntryIndex(aWindow), 1);
  97. // Remove the event listeners
  98. TAB_EVENTS.forEach(function(event) {
  99. aWindow.gBrowser.tabContainer.removeEventListener(event, _handleEvent, false);
  100. });
  101. WINDOW_EVENTS.forEach(function(event) {
  102. aWindow.removeEventListener(event, _handleEvent, false);
  103. });
  104. },
  105. onActivate: function(aWindow, aHasFocus) {
  106. // If this window was the last focused window, we don't need to do anything
  107. if (aWindow == _lastFocusedWindow)
  108. return;
  109. // handleFocusedWindow will deprioritize the current window
  110. this.handleFocusedWindow(aWindow);
  111. // Lastly we should increase priority for this window
  112. this.increasePriority(aWindow);
  113. },
  114. handleFocusedWindow: function(aWindow) {
  115. // If we have a last focused window, we need to deprioritize it first
  116. if (_lastFocusedWindow)
  117. this.decreasePriority(_lastFocusedWindow);
  118. // aWindow is now focused
  119. _lastFocusedWindow = aWindow;
  120. },
  121. // Auxiliary methods
  122. increasePriority: function(aWindow) {
  123. aWindow.gBrowser.browsers.forEach(function(aBrowser) {
  124. BrowserHelper.increasePriority(aBrowser);
  125. });
  126. },
  127. decreasePriority: function(aWindow) {
  128. aWindow.gBrowser.browsers.forEach(function(aBrowser) {
  129. BrowserHelper.decreasePriority(aBrowser);
  130. });
  131. },
  132. getEntry: function(aWindow) {
  133. return _windows[this.getEntryIndex(aWindow)];
  134. },
  135. getEntryIndex: function(aWindow) {
  136. // Assumes that every object has a unique window & it's in the array
  137. for (let i = 0; i < _windows.length; i++)
  138. if (_windows[i].window == aWindow)
  139. return i;
  140. }
  141. };