chrome.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. "use strict";
  5. const { Ci } = require("chrome");
  6. const Services = require("Services");
  7. const { DebuggerServer } = require("../main");
  8. const { getChildDocShells, TabActor } = require("./webbrowser");
  9. const makeDebugger = require("./utils/make-debugger");
  10. /**
  11. * Creates a TabActor for debugging all the chrome content in the
  12. * current process. Most of the implementation is inherited from TabActor.
  13. * ChromeActor is a child of RootActor, it can be instanciated via
  14. * RootActor.getProcess request.
  15. * ChromeActor exposes all tab actors via its form() request, like TabActor.
  16. *
  17. * History lecture:
  18. * All tab actors used to also be registered as global actors,
  19. * so that the root actor was also exposing tab actors for the main process.
  20. * Tab actors ended up having RootActor as parent actor,
  21. * but more and more features of the tab actors were relying on TabActor.
  22. * So we are now exposing a process actor that offers the same API as TabActor
  23. * by inheriting its functionality.
  24. * Global actors are now only the actors that are meant to be global,
  25. * and are no longer related to any specific scope/document.
  26. *
  27. * @param aConnection DebuggerServerConnection
  28. * The connection to the client.
  29. */
  30. function ChromeActor(aConnection) {
  31. TabActor.call(this, aConnection);
  32. // This creates a Debugger instance for chrome debugging all globals.
  33. this.makeDebugger = makeDebugger.bind(null, {
  34. findDebuggees: dbg => dbg.findAllGlobals(),
  35. shouldAddNewGlobalAsDebuggee: () => true
  36. });
  37. // Ensure catching the creation of any new content docshell
  38. this.listenForNewDocShells = true;
  39. // Defines the default docshell selected for the tab actor
  40. let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
  41. // Default to any available top level window if there is no expected window
  42. // (for example when we open firefox with -webide argument)
  43. if (!window) {
  44. window = Services.wm.getMostRecentWindow(null);
  45. }
  46. // On xpcshell, there is no window/docshell
  47. let docShell = window ? window.QueryInterface(Ci.nsIInterfaceRequestor)
  48. .getInterface(Ci.nsIDocShell)
  49. : null;
  50. Object.defineProperty(this, "docShell", {
  51. value: docShell,
  52. configurable: true
  53. });
  54. }
  55. exports.ChromeActor = ChromeActor;
  56. ChromeActor.prototype = Object.create(TabActor.prototype);
  57. ChromeActor.prototype.constructor = ChromeActor;
  58. ChromeActor.prototype.isRootActor = true;
  59. /**
  60. * Getter for the list of all docshells in this tabActor
  61. * @return {Array}
  62. */
  63. Object.defineProperty(ChromeActor.prototype, "docShells", {
  64. get: function () {
  65. // Iterate over all top-level windows and all their docshells.
  66. let docShells = [];
  67. let e = Services.ww.getWindowEnumerator();
  68. while (e.hasMoreElements()) {
  69. let window = e.getNext();
  70. let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
  71. .getInterface(Ci.nsIWebNavigation)
  72. .QueryInterface(Ci.nsIDocShell);
  73. docShells = docShells.concat(getChildDocShells(docShell));
  74. }
  75. return docShells;
  76. }
  77. });
  78. ChromeActor.prototype.observe = function (aSubject, aTopic, aData) {
  79. TabActor.prototype.observe.call(this, aSubject, aTopic, aData);
  80. if (!this.attached) {
  81. return;
  82. }
  83. if (aTopic == "chrome-webnavigation-create") {
  84. aSubject.QueryInterface(Ci.nsIDocShell);
  85. this._onDocShellCreated(aSubject);
  86. } else if (aTopic == "chrome-webnavigation-destroy") {
  87. this._onDocShellDestroy(aSubject);
  88. }
  89. };
  90. ChromeActor.prototype._attach = function () {
  91. if (this.attached) {
  92. return false;
  93. }
  94. TabActor.prototype._attach.call(this);
  95. // Listen for any new/destroyed chrome docshell
  96. Services.obs.addObserver(this, "chrome-webnavigation-create", false);
  97. Services.obs.addObserver(this, "chrome-webnavigation-destroy", false);
  98. // Iterate over all top-level windows.
  99. let docShells = [];
  100. let e = Services.ww.getWindowEnumerator();
  101. while (e.hasMoreElements()) {
  102. let window = e.getNext();
  103. let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
  104. .getInterface(Ci.nsIWebNavigation)
  105. .QueryInterface(Ci.nsIDocShell);
  106. if (docShell == this.docShell) {
  107. continue;
  108. }
  109. this._progressListener.watch(docShell);
  110. }
  111. };
  112. ChromeActor.prototype._detach = function () {
  113. if (!this.attached) {
  114. return false;
  115. }
  116. Services.obs.removeObserver(this, "chrome-webnavigation-create");
  117. Services.obs.removeObserver(this, "chrome-webnavigation-destroy");
  118. // Iterate over all top-level windows.
  119. let docShells = [];
  120. let e = Services.ww.getWindowEnumerator();
  121. while (e.hasMoreElements()) {
  122. let window = e.getNext();
  123. let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
  124. .getInterface(Ci.nsIWebNavigation)
  125. .QueryInterface(Ci.nsIDocShell);
  126. if (docShell == this.docShell) {
  127. continue;
  128. }
  129. this._progressListener.unwatch(docShell);
  130. }
  131. TabActor.prototype._detach.call(this);
  132. };
  133. /* ThreadActor hooks. */
  134. /**
  135. * Prepare to enter a nested event loop by disabling debuggee events.
  136. */
  137. ChromeActor.prototype.preNest = function () {
  138. // Disable events in all open windows.
  139. let e = Services.wm.getEnumerator(null);
  140. while (e.hasMoreElements()) {
  141. let win = e.getNext();
  142. let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
  143. .getInterface(Ci.nsIDOMWindowUtils);
  144. windowUtils.suppressEventHandling(true);
  145. windowUtils.suspendTimeouts();
  146. }
  147. };
  148. /**
  149. * Prepare to exit a nested event loop by enabling debuggee events.
  150. */
  151. ChromeActor.prototype.postNest = function (aNestData) {
  152. // Enable events in all open windows.
  153. let e = Services.wm.getEnumerator(null);
  154. while (e.hasMoreElements()) {
  155. let win = e.getNext();
  156. let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
  157. .getInterface(Ci.nsIDOMWindowUtils);
  158. windowUtils.resumeTimeouts();
  159. windowUtils.suppressEventHandling(false);
  160. }
  161. };