Bug 1366823 - add Scratchpad manager APIs to DevToolsShim;r=ochameau draft
authorJulian Descottes <jdescottes@mozilla.com>
Mon, 29 May 2017 14:50:07 +0200
changeset 585965 83d93d5168ddb7f4310543ff6d12e0f809d3db87
parent 585964 e968f676304d406b28bfc6067b231b918668abf0
child 585966 eb051a1612598eb3ca11cff8be92f55f5cb3f7ca
push id61243
push userjdescottes@mozilla.com
push dateMon, 29 May 2017 12:50:59 +0000
reviewersochameau
bugs1366823
milestone55.0a1
Bug 1366823 - add Scratchpad manager APIs to DevToolsShim;r=ochameau MozReview-Commit-ID: 5JsSu9Spkgn
devtools/client/framework/devtools.js
devtools/shim/DevToolsShim.jsm
devtools/shim/tests/unit/test_devtools_shim.js
--- a/devtools/client/framework/devtools.js
+++ b/devtools/client/framework/devtools.js
@@ -9,16 +9,17 @@ const Services = require("Services");
 
 const {DevToolsShim} = Cu.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
 
 // Load gDevToolsBrowser toolbox lazily as they need gDevTools to be fully initialized
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
 loader.lazyRequireGetter(this, "ToolboxHostManager", "devtools/client/framework/toolbox-host-manager", true);
 loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
+loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm");
 
 const {defaultTools: DefaultTools, defaultThemes: DefaultThemes} =
   require("devtools/client/definitions");
 const EventEmitter = require("devtools/shared/event-emitter");
 const {JsonView} = require("devtools/client/jsonview/main");
 const AboutDevTools = require("devtools/client/framework/about-devtools-toolbox");
 const {Task} = require("devtools/shared/task");
 const {getTheme, setTheme, addThemeObserver, removeThemeObserver} =
@@ -390,16 +391,37 @@ DevTools.prototype = {
         definitions.push(definition);
       }
     }
 
     return definitions.sort(this.ordinalSort);
   },
 
   /**
+   * Get the array of currently opened scratchpad windows.
+   *
+   * @return {Array} array of currently opened scratchpad windows.
+   *         Empty array if the scratchpad manager is not loaded.
+   */
+  getOpenedScratchpads: function () {
+    // Check if the module is loaded to avoid loading ScratchpadManager for no reason.
+    if (!Cu.isModuleLoaded("resource://devtools/client/scratchpad/scratchpad-manager.jsm")) {
+      return [];
+    }
+    return ScratchpadManager.getSessionState();
+  },
+
+  /**
+   * Restore the provided array of scratchpad window states.
+   */
+  restoreScratchpadSession: function (scratchpads) {
+    ScratchpadManager.restoreSession(scratchpads);
+  },
+
+  /**
    * Show a Toolbox for a target (either by creating a new one, or if a toolbox
    * already exists for the target, by bring to the front the existing one)
    * If |toolId| is specified then the displayed toolbox will have the
    * specified tool selected.
    * If |hostType| is specified then the toolbox will be displayed using the
    * specified HostType.
    *
    * @param {Target} target
@@ -535,19 +557,24 @@ DevTools.prototype = {
     }
 
     JsonView.destroy();
 
     gDevTools.unregisterDefaults();
 
     removeThemeObserver(this._onThemeChanged);
 
-    // Notify the DevToolsShim that DevTools are no longer available, particularly if the
-    // destroy was caused by disabling/removing the DevTools add-on.
-    DevToolsShim.unregister();
+    // Do not unregister devtools from the DevToolsShim if the destroy is caused by an
+    // application shutdown. For instance SessionStore needs to save the Scratchpad
+    // manager state on shutdown.
+    if (!shuttingDown) {
+      // Notify the DevToolsShim that DevTools are no longer available, particularly if
+      // the destroy was caused by disabling/removing the DevTools add-on.
+      DevToolsShim.unregister();
+    }
 
     // Cleaning down the toolboxes: i.e.
     //   for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
     // Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
   },
 
   /**
    * Iterator that yields each of the toolboxes.
--- a/devtools/shim/DevToolsShim.jsm
+++ b/devtools/shim/DevToolsShim.jsm
@@ -148,16 +148,40 @@ this.DevToolsShim = {
   unregisterTheme: function (theme) {
     if (this.isInstalled()) {
       this.gDevTools.unregisterTheme(theme);
     } else {
       removeItem(this.themes, t => t === theme);
     }
   },
 
+  /**
+   * Called from SessionStore.jsm in mozilla-central when saving the current state.
+   *
+   * @return {Array} array of currently opened scratchpad windows. Empty array if devtools
+   *         are not installed
+   */
+  getOpenedScratchpads: function () {
+    if (!this.isInstalled()) {
+      return [];
+    }
+    return this.gDevTools.getOpenedScratchpads();
+  },
+
+  /**
+   * Called from SessionStore.jsm in mozilla-central when restoring a state that contained
+   * opened scratchpad windows.
+   */
+  restoreScratchpadSession: function (scratchpads) {
+    if (!this.isInstalled()) {
+      return;
+    }
+    this.gDevTools.restoreScratchpadSession(scratchpads);
+  },
+
   _onDevToolsRegistered: function () {
     // Register all pending event listeners on the real gDevTools object.
     for (let [event, listener] of this.listeners) {
       this.gDevTools.on(event, listener);
     }
 
     for (let tool of this.tools) {
       this.gDevTools.registerTool(tool);
--- a/devtools/shim/tests/unit/test_devtools_shim.js
+++ b/devtools/shim/tests/unit/test_devtools_shim.js
@@ -17,16 +17,18 @@ function createMockDevTools() {
   let methods = [
     "on",
     "off",
     "registerTool",
     "registerTheme",
     "unregisterTool",
     "unregisterTheme",
     "emit",
+    "getOpenedScratchpads",
+    "restoreScratchpadSession",
   ];
 
   let mock = {
     callLog: {}
   };
 
   for (let method of methods) {
     // Create a stub for method, that only pushes its arguments in the inner callLog
@@ -183,16 +185,40 @@ function test_events() {
   DevToolsShim.register(mock);
   checkCalls(mock, "emit", 1, ["devtools-registered"]);
 
   // Check emit is called once with the devtools-unregistered event.
   DevToolsShim.unregister();
   checkCalls(mock, "emit", 2, ["devtools-unregistered"]);
 }
 
+function test_scratchpad_apis() {
+  ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
+
+  // Check that restoreScratchpadSession doesn't crash.
+  DevToolsShim.restoreScratchpadSession([{}]);
+
+  let scratchpads = DevToolsShim.getOpenedScratchpads();
+  equal(scratchpads.length, 0,
+      "getOpenedScratchpads returns [] when DevTools are not installed");
+
+  let mock = createMockDevTools();
+  DevToolsShim.register(mock);
+
+  // Check that calls to restoreScratchpadSession are not held.
+  checkCalls(mock, "restoreScratchpadSession", 0);
+
+  DevToolsShim.getOpenedScratchpads();
+  checkCalls(mock, "getOpenedScratchpads", 1, []);
+
+  let scratchpadSessions = [{}];
+  DevToolsShim.restoreScratchpadSession(scratchpadSessions);
+  checkCalls(mock, "restoreScratchpadSession", 1, [scratchpadSessions]);
+}
+
 function run_test() {
   test_register_unregister();
   DevToolsShim.unregister();
 
   test_on_is_forwarded_to_devtools();
   DevToolsShim.unregister();
 
   test_off_called_before_registering_devtools();
@@ -202,10 +228,13 @@ function run_test() {
   DevToolsShim.unregister();
 
   test_registering_tool();
   DevToolsShim.unregister();
 
   test_registering_theme();
   DevToolsShim.unregister();
 
+  test_scratchpad_apis();
+  DevToolsShim.unregister();
+
   test_events();
 }