vapi-window.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*******************************************************************************
  2. ηMatrix - a browser extension to black/white list requests.
  3. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
  4. Copyright (C) 2019-2022 Alessio Vanni
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see {http://www.gnu.org/licenses/}.
  15. Home: https://gitlab.com/vannilla/ematrix
  16. uMatrix Home: https://github.com/gorhill/uMatrix
  17. */
  18. 'use strict';
  19. /******************************************************************************/
  20. (function () {
  21. vAPI.window = (function () {
  22. let windowToIdMap = new Map();
  23. let windowIdGenerator = 1;
  24. let api = {
  25. onOpenWindow: null,
  26. onCloseWindow: null
  27. };
  28. // https://github.com/gorhill/uMatrix/issues/586 This is
  29. // necessary hack because on SeaMonkey 2.40, for unknown
  30. // reasons private windows do not have the attribute
  31. // `windowtype` set to `navigator:browser`. As a fallback, the
  32. // code here will also test whether the id attribute is
  33. // `main-window`.
  34. api.toBrowserWindow = function (win) {
  35. let docElement = win && win.document
  36. && win.document.documentElement;
  37. if (!docElement) {
  38. return null;
  39. }
  40. if (vAPI.thunderbird) {
  41. return docElement.getAttribute('windowtype') === 'mail:3pane'
  42. ? win
  43. : null;
  44. }
  45. return docElement.getAttribute('windowtype') === 'navigator:browser'
  46. || docElement.getAttribute('id') === 'main-window'
  47. ? win
  48. : null;
  49. };
  50. api.getWindows = function () {
  51. return windowToIdMap.keys();
  52. };
  53. api.idFromWindow = function (win) {
  54. return windowToIdMap.get(win) || 0;
  55. };
  56. api.getCurrentWindow = function () {
  57. return this.toBrowserWindow(Services.wm.getMostRecentWindow(null));
  58. };
  59. let addWindow = function (win) {
  60. if (!win || windowToIdMap.has(win)) {
  61. return;
  62. }
  63. windowToIdMap.set(win, windowIdGenerator++);
  64. if (typeof api.onOpenWindow === 'function') {
  65. api.onOpenWindow(win);
  66. }
  67. };
  68. let removeWindow = function (win) {
  69. if (!win || windowToIdMap.delete(win) !== true) {
  70. return;
  71. }
  72. if (typeof api.onCloseWindow === 'function') {
  73. api.onCloseWindow(win);
  74. }
  75. };
  76. // https://github.com/gorhill/uMatrix/issues/357
  77. // Use nsIWindowMediator for being notified of opened/closed windows.
  78. let listeners = {
  79. onOpenWindow: function (aWindow) {
  80. let win;
  81. try {
  82. win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
  83. .getInterface(Ci.nsIDOMWindow);
  84. } catch (e) {
  85. // Ignore
  86. }
  87. addWindow(win);
  88. },
  89. onCloseWindow: function (aWindow) {
  90. let win;
  91. try {
  92. win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
  93. .getInterface(Ci.nsIDOMWindow);
  94. } catch (e) {
  95. // Ignore
  96. }
  97. removeWindow(win);
  98. },
  99. observe: function (aSubject, topic) {
  100. let win;
  101. try {
  102. win = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
  103. .getInterface(Ci.nsIDOMWindow);
  104. } catch (e) {
  105. // Ignore
  106. }
  107. if (!win) {
  108. return;
  109. }
  110. switch (topic) {
  111. case 'domwindowopened':
  112. addWindow(win);
  113. break;
  114. case 'domwindowclosed':
  115. removeWindow(win);
  116. break;
  117. default:
  118. console.error('unknown observer topic');
  119. break;
  120. }
  121. }
  122. };
  123. (function() {
  124. let winumerator;
  125. winumerator = Services.wm.getEnumerator(null);
  126. while (winumerator.hasMoreElements()) {
  127. let win = winumerator.getNext();
  128. if (!win.closed) {
  129. windowToIdMap.set(win, windowIdGenerator++);
  130. }
  131. }
  132. winumerator = Services.ww.getWindowEnumerator();
  133. while (winumerator.hasMoreElements()) {
  134. let win = winumerator.getNext()
  135. .QueryInterface(Ci.nsIInterfaceRequestor)
  136. .getInterface(Ci.nsIDOMWindow);
  137. if (!win.closed) {
  138. windowToIdMap.set(win, windowIdGenerator++);
  139. }
  140. }
  141. Services.wm.addListener(listeners);
  142. Services.ww.registerNotification(listeners);
  143. })();
  144. vAPI.addCleanUpTask(function() {
  145. Services.wm.removeListener(listeners);
  146. Services.ww.unregisterNotification(listeners);
  147. windowToIdMap.clear();
  148. });
  149. return api;
  150. })();
  151. })();