123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /* global content */
- /* exported startup, shutdown, install, uninstall */
- "use strict";
- const Cu = Components.utils;
- const Ci = Components.interfaces;
- const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
- function actionOccurred(id) {
- let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
- let Telemetry = require("devtools/client/shared/telemetry");
- let telemetry = new Telemetry();
- telemetry.actionOccurred(id);
- }
- // Helper to listen to a key on all windows
- function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
- let keyListener = function (event) {
- if (event.ctrlKey == !!ctrlKey &&
- event.altKey == !!altKey &&
- event.keyCode === keyCode) {
- callback(event);
- // Call preventDefault to avoid duplicated events when
- // doing the key stroke within a tab.
- event.preventDefault();
- }
- };
- let observer = function (window, topic, data) {
- // Listen on keyup to call keyListener only once per stroke
- if (topic === "domwindowopened") {
- window.addEventListener("keyup", keyListener);
- } else {
- window.removeEventListener("keyup", keyListener);
- }
- };
- return {
- start: function () {
- // Automatically process already opened windows
- let e = Services.ww.getWindowEnumerator();
- while (e.hasMoreElements()) {
- let window = e.getNext();
- observer(window, "domwindowopened", null);
- }
- // And listen for new ones to come
- Services.ww.registerNotification(observer);
- },
- stop: function () {
- Services.ww.unregisterNotification(observer);
- let e = Services.ww.getWindowEnumerator();
- while (e.hasMoreElements()) {
- let window = e.getNext();
- observer(window, "domwindowclosed", null);
- }
- }
- };
- }
- let getTopLevelWindow = function (window) {
- return window.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow);
- };
- function reload(event) {
- // We automatically reload the toolbox if we are on a browser tab
- // with a toolbox already opened
- let top = getTopLevelWindow(event.view);
- let isBrowser = top.location.href.includes("/browser.xul");
- let reloadToolbox = false;
- if (isBrowser && top.gBrowser) {
- // We do not use any devtools code before the call to Loader.jsm reload as
- // any attempt to use Loader.jsm to load a module will instanciate a new
- // Loader.
- let nbox = top.gBrowser.getNotificationBox();
- reloadToolbox =
- top.document.getAnonymousElementByAttribute(nbox, "class",
- "devtools-toolbox-bottom-iframe") ||
- top.document.getAnonymousElementByAttribute(nbox, "class",
- "devtools-toolbox-side-iframe") ||
- Services.wm.getMostRecentWindow("devtools:toolbox");
- }
- let browserConsole = Services.wm.getMostRecentWindow("devtools:webconsole");
- let reopenBrowserConsole = false;
- if (browserConsole) {
- browserConsole.close();
- reopenBrowserConsole = true;
- }
- dump("Reload DevTools. (reload-toolbox:" + reloadToolbox + ")\n");
- // Invalidate xul cache in order to see changes made to chrome:// files
- Services.obs.notifyObservers(null, "startupcache-invalidate", null);
- // This frame script is going to be executed in all processes:
- // parent and child
- Services.ppmm.loadProcessScript("data:,new " + function () {
- /* Flush message manager cached frame scripts as well as chrome locales */
- let obs = Components.classes["@mozilla.org/observer-service;1"]
- .getService(Components.interfaces.nsIObserverService);
- obs.notifyObservers(null, "message-manager-flush-caches", null);
- /* Also purge cached modules in child processes, we do it a few lines after
- in the parent process */
- if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
- Services.obs.notifyObservers(null, "devtools-unload", "reload");
- }
- }, false);
- // As we can't get a reference to existing Loader.jsm instances, we send them
- // an observer service notification to unload them.
- Services.obs.notifyObservers(null, "devtools-unload", "reload");
- // Then spawn a brand new Loader.jsm instance and start the main module
- Cu.unload("resource://devtools/shared/Loader.jsm");
- // Also unload all resources loaded as jsm, hopefully all of them are going
- // to be converted into regular modules
- Cu.unload("resource://devtools/client/shared/browser-loader.js");
- Cu.unload("resource://devtools/client/framework/ToolboxProcess.jsm");
- Cu.unload("resource://devtools/shared/apps/Devices.jsm");
- Cu.unload("resource://devtools/client/scratchpad/scratchpad-manager.jsm");
- Cu.unload("resource://devtools/shared/Parser.jsm");
- Cu.unload("resource://devtools/client/shared/DOMHelpers.jsm");
- Cu.unload("resource://devtools/client/shared/widgets/VariablesView.jsm");
- Cu.unload("resource://devtools/client/responsivedesign/responsivedesign.jsm");
- Cu.unload("resource://devtools/client/shared/widgets/AbstractTreeItem.jsm");
- Cu.unload("resource://devtools/shared/deprecated-sync-thenables.js");
- const {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
- devtools.require("devtools/client/framework/devtools-browser");
- // Go over all top level windows to reload all devtools related things
- let windowsEnum = Services.wm.getEnumerator(null);
- while (windowsEnum.hasMoreElements()) {
- let window = windowsEnum.getNext();
- let windowtype = window.document.documentElement.getAttribute("windowtype");
- if (windowtype == "navigator:browser" && window.gBrowser) {
- // Enumerate tabs on firefox windows
- for (let tab of window.gBrowser.tabs) {
- let browser = tab.linkedBrowser;
- let location = browser.documentURI.spec;
- let mm = browser.messageManager;
- // To reload JSON-View tabs and any devtools document
- if (location.startsWith("about:debugging") ||
- location.startsWith("chrome://devtools/")) {
- browser.reload();
- }
- // We have to use a frame script to query "baseURI"
- mm.loadFrameScript("data:text/javascript,new " + function () {
- let isJSONView =
- content.document.baseURI.startsWith("resource://devtools/");
- if (isJSONView) {
- content.location.reload();
- }
- }, false);
- }
- } else if (windowtype === "devtools:webide") {
- window.location.reload();
- }
- }
- if (reloadToolbox) {
- // Reopen the toolbox automatically if we are reloading from toolbox
- // shortcut and are on a browser window.
- // Wait for a second before opening the toolbox to avoid races
- // between the old and the new one.
- let {setTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
- setTimeout(() => {
- let { TargetFactory } = devtools.require("devtools/client/framework/target");
- let { gDevTools } = devtools.require("devtools/client/framework/devtools");
- let target = TargetFactory.forTab(top.gBrowser.selectedTab);
- gDevTools.showToolbox(target);
- }, 1000);
- }
- // Browser console document can't just be reloaded.
- // HUDService is going to close it on unload.
- // Instead we have to manually toggle it.
- if (reopenBrowserConsole) {
- let {HUDService} = devtools.require("devtools/client/webconsole/hudservice");
- HUDService.toggleBrowserConsole();
- }
- actionOccurred("reloadAddonReload");
- }
- let prefs = {
- // Enable dump as some errors are only printed on the stdout
- "browser.dom.window.dump.enabled": true,
- // Enable the browser toolbox and various chrome-only features
- "devtools.chrome.enabled": true,
- "devtools.debugger.remote-enabled": true,
- // Disable the prompt to ease usage of the browser toolbox
- "devtools.debugger.prompt-connection": false,
- };
- let originalPrefValues = {};
- let listener;
- function startup() {
- dump("DevTools addon started.\n");
- listener = new MultiWindowKeyListener({
- keyCode: Ci.nsIDOMKeyEvent.DOM_VK_R, ctrlKey: true, altKey: true,
- callback: reload
- });
- listener.start();
- // Toggle development prefs and save original values
- originalPrefValues = {};
- for (let name in prefs) {
- let value = prefs[name];
- let userValue = Services.prefs.getBoolPref(name);
- // Only toggle if the pref isn't already set to the right value
- if (userValue != value) {
- Services.prefs.setBoolPref(name, value);
- originalPrefValues[name] = userValue;
- }
- }
- }
- function shutdown() {
- listener.stop();
- listener = null;
- // Restore preferences that used to be before the addon was installed
- for (let name in originalPrefValues) {
- let userValue = Services.prefs.getBoolPref(name);
- // Only reset the pref if it hasn't changed
- if (userValue == prefs[name]) {
- Services.prefs.setBoolPref(name, originalPrefValues[name]);
- }
- }
- }
- function install() {
- actionOccurred("reloadAddonInstalled");
- }
- function uninstall() {}
|