toolbox-process-window.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. "use strict";
  6. var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
  7. var { loader, require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
  8. // Require this module to setup core modules
  9. loader.require("devtools/client/framework/devtools-browser");
  10. var { gDevTools } = require("devtools/client/framework/devtools");
  11. var { TargetFactory } = require("devtools/client/framework/target");
  12. var { Toolbox } = require("devtools/client/framework/toolbox");
  13. var Services = require("Services");
  14. var { DebuggerClient } = require("devtools/shared/client/main");
  15. var { PrefsHelper } = require("devtools/client/shared/prefs");
  16. var { Task } = require("devtools/shared/task");
  17. /**
  18. * Shortcuts for accessing various debugger preferences.
  19. */
  20. var Prefs = new PrefsHelper("devtools.debugger", {
  21. chromeDebuggingHost: ["Char", "chrome-debugging-host"],
  22. chromeDebuggingPort: ["Int", "chrome-debugging-port"],
  23. chromeDebuggingWebSocket: ["Bool", "chrome-debugging-websocket"],
  24. });
  25. var gToolbox, gClient;
  26. var connect = Task.async(function*() {
  27. window.removeEventListener("load", connect);
  28. // Initiate the connection
  29. let transport = yield DebuggerClient.socketConnect({
  30. host: Prefs.chromeDebuggingHost,
  31. port: Prefs.chromeDebuggingPort,
  32. webSocket: Prefs.chromeDebuggingWebSocket,
  33. });
  34. gClient = new DebuggerClient(transport);
  35. yield gClient.connect();
  36. let addonID = getParameterByName("addonID");
  37. if (addonID) {
  38. let { addons } = yield gClient.listAddons();
  39. let addonActor = addons.filter(addon => addon.id === addonID).pop();
  40. openToolbox({
  41. form: addonActor,
  42. chrome: true,
  43. isTabActor: addonActor.isWebExtension ? true : false
  44. });
  45. } else {
  46. let response = yield gClient.getProcess();
  47. openToolbox({
  48. form: response.form,
  49. chrome: true
  50. });
  51. }
  52. });
  53. // Certain options should be toggled since we can assume chrome debugging here
  54. function setPrefDefaults() {
  55. Services.prefs.setBoolPref("devtools.inspector.showUserAgentStyles", true);
  56. Services.prefs.setBoolPref("devtools.performance.ui.show-platform-data", true);
  57. Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
  58. Services.prefs.setBoolPref("browser.dom.window.dump.enabled", true);
  59. Services.prefs.setBoolPref("devtools.command-button-noautohide.enabled", true);
  60. Services.prefs.setBoolPref("devtools.scratchpad.enabled", true);
  61. // Bug 1225160 - Using source maps with browser debugging can lead to a crash
  62. Services.prefs.setBoolPref("devtools.debugger.source-maps-enabled", false);
  63. Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
  64. Services.prefs.setBoolPref("devtools.debugger.client-source-maps-enabled", true);
  65. }
  66. window.addEventListener("load", function() {
  67. let cmdClose = document.getElementById("toolbox-cmd-close");
  68. cmdClose.addEventListener("command", onCloseCommand);
  69. setPrefDefaults();
  70. connect().catch(e => {
  71. let errorMessageContainer = document.getElementById("error-message-container");
  72. let errorMessage = document.getElementById("error-message");
  73. errorMessage.value = e.message || e;
  74. errorMessageContainer.hidden = false;
  75. console.error(e);
  76. });
  77. });
  78. function onCloseCommand(event) {
  79. window.close();
  80. }
  81. function openToolbox({ form, chrome, isTabActor }) {
  82. let options = {
  83. form: form,
  84. client: gClient,
  85. chrome: chrome,
  86. isTabActor: isTabActor
  87. };
  88. TargetFactory.forRemoteTab(options).then(target => {
  89. let frame = document.getElementById("toolbox-iframe");
  90. // Remember the last panel that was used inside of this profile.
  91. // But if we are testing, then it should always open the debugger panel.
  92. let selectedTool =
  93. Services.prefs.getCharPref("devtools.browsertoolbox.panel",
  94. Services.prefs.getCharPref("devtools.toolbox.selectedTool",
  95. "jsdebugger"));
  96. let options = { customIframe: frame };
  97. gDevTools.showToolbox(target,
  98. selectedTool,
  99. Toolbox.HostType.CUSTOM,
  100. options)
  101. .then(onNewToolbox);
  102. });
  103. }
  104. function onNewToolbox(toolbox) {
  105. gToolbox = toolbox;
  106. bindToolboxHandlers();
  107. raise();
  108. let env = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment);
  109. let testScript = env.get("MOZ_TOOLBOX_TEST_SCRIPT");
  110. if (testScript) {
  111. // Only allow executing random chrome scripts when a special
  112. // test-only pref is set
  113. let prefName = "devtools.browser-toolbox.allow-unsafe-script";
  114. if (Services.prefs.getPrefType(prefName) == Services.prefs.PREF_BOOL &&
  115. Services.prefs.getBoolPref(prefName) === true) {
  116. evaluateTestScript(testScript, toolbox);
  117. }
  118. }
  119. }
  120. function evaluateTestScript(script, toolbox) {
  121. let sandbox = Cu.Sandbox(window);
  122. sandbox.window = window;
  123. sandbox.toolbox = toolbox;
  124. Cu.evalInSandbox(script, sandbox);
  125. }
  126. function bindToolboxHandlers() {
  127. gToolbox.once("destroyed", quitApp);
  128. window.addEventListener("unload", onUnload);
  129. }
  130. function setupThreadListeners(panel) {
  131. updateBadgeText(panel._controller.activeThread.state == "paused");
  132. let onPaused = updateBadgeText.bind(null, true);
  133. let onResumed = updateBadgeText.bind(null, false);
  134. panel.target.on("thread-paused", onPaused);
  135. panel.target.on("thread-resumed", onResumed);
  136. panel.once("destroyed", () => {
  137. panel.off("thread-paused", onPaused);
  138. panel.off("thread-resumed", onResumed);
  139. });
  140. }
  141. function updateBadgeText(paused) {
  142. let dockSupport = Cc["@mozilla.org/widget/macdocksupport;1"].getService(Ci.nsIMacDockSupport);
  143. dockSupport.badgeText = paused ? "▐▐ " : " ▶";
  144. }
  145. function onUnload() {
  146. window.removeEventListener("unload", onUnload);
  147. window.removeEventListener("message", onMessage);
  148. let cmdClose = document.getElementById("toolbox-cmd-close");
  149. cmdClose.removeEventListener("command", onCloseCommand);
  150. gToolbox.destroy();
  151. }
  152. function onMessage(event) {
  153. try {
  154. let json = JSON.parse(event.data);
  155. switch (json.name) {
  156. case "toolbox-raise":
  157. raise();
  158. break;
  159. case "toolbox-title":
  160. setTitle(json.data.value);
  161. break;
  162. }
  163. } catch(e) { console.error(e); }
  164. }
  165. window.addEventListener("message", onMessage);
  166. function raise() {
  167. window.focus();
  168. }
  169. function setTitle(title) {
  170. document.title = title;
  171. }
  172. function quitApp() {
  173. let quit = Cc["@mozilla.org/supports-PRBool;1"]
  174. .createInstance(Ci.nsISupportsPRBool);
  175. Services.obs.notifyObservers(quit, "quit-application-requested", null);
  176. let shouldProceed = !quit.data;
  177. if (shouldProceed) {
  178. Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
  179. }
  180. }
  181. function getParameterByName (name) {
  182. name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  183. let regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
  184. let results = regex.exec(window.location.search);
  185. return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  186. }