Bug 1354679 - Show the paused debugger overlay when script gets paused; r=ochameau draft
authoryulia <yulia@mozilla.com>
Mon, 16 Oct 2017 17:24:59 +0200
changeset 682187 c0349f5d4cf33396382ce7bd2b84dd27249a3741
parent 682186 91a0273d308e4ed8c7cd0a7fc8715898aad2df30
child 683361 9ba6d8bf7347751eea09f775d6d9b24c0e37e22a
child 683374 dc3a651ccd1bd47adfc691d65a98660b8d5ce35b
child 684711 705092c1dddd2b65b04d2c465ca8cbb4feeea07e
child 684715 8d79d2611fbd6e7c71bb1e1a13ace04b6c1084d3
push id85041
push userbmo:ystartsev@mozilla.com
push dateWed, 18 Oct 2017 09:29:34 +0000
reviewersochameau
bugs1354679
milestone58.0a1
Bug 1354679 - Show the paused debugger overlay when script gets paused; r=ochameau MozReview-Commit-ID: FhKLGEtocTl
devtools/server/actors/highlighters/paused-debugger.js
devtools/server/actors/script.js
devtools/server/tests/unit/test_pausedOverlay.js
--- a/devtools/server/actors/highlighters/paused-debugger.js
+++ b/devtools/server/actors/highlighters/paused-debugger.js
@@ -79,30 +79,27 @@ PausedDebuggerOverlay.prototype = {
   /**
    * Show this highlighter. This is the usual show method that all highlighters need to
    * implement so they can be used via the CustomHighlighterActor mechanism.
    * @param {DOMNode} node The context node for this highlighter.
    * @param {Object} options See showOverlay for doc about this.
    * @return {Boolean}
    */
   show(node, options = {}) {
-    return this.showOverlay(options);
-  },
 
-  /**
-   * This contains the actual logic to show the highlighter. In comparison to the show
-   * method, it does not need a first DOMNode parameter which makes it simpler to be
-   * called by other server-side modules if needed.
-   * @param {Object} options A config object that can take 2 properties:
-   * - {String} reason The text that will be shown in the toolbar. If not given, the
-   *   toolbar will not be displayed.
-   * - {Boolean} onlyToolbar Set to true to only show the toolbar, and not the overlay.
-   * @return {Boolean}
-   */
-  showOverlay(options = {}) {
+    /**
+     * This contains the actual logic to show the highlighter. In comparison to the show
+     * method, it does not need a first DOMNode parameter which makes it simpler to be
+     * called by other server-side modules if needed.
+     * @param {Object} options A config object that can take 2 properties:
+     * - {String} reason The text that will be shown in the toolbar. If not given, the
+     *   toolbar will not be displayed.
+     * - {Boolean} onlyToolbar Set to true to only show the toolbar, and not the overlay.
+     * @return {Boolean}
+     */
     if (this.env.isXUL) {
       return false;
     }
 
     // Show the highlighter's root element.
     let root = this.getElement("root");
     root.removeAttribute("hidden");
 
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -424,16 +424,18 @@ const ThreadActor = ActorClassWithSpec(t
     this._frameActors = [];
     this._parent = parent;
     this._dbg = null;
     this._gripDepth = 0;
     this._threadLifetimePool = null;
     this._tabClosed = false;
     this._scripts = null;
     this._pauseOnDOMEvents = null;
+    EventEmitter.decorate(this);
+    attachPauseStateListeners(this)
 
     this._options = {
       useSourceMaps: false,
       autoBlackBox: false
     };
 
     this.breakpointActorMap = new BreakpointActorMap();
     this.sourceActorStore = new SourceActorStore();
@@ -600,17 +602,17 @@ const ThreadActor = ActorClassWithSpec(t
     this._dbg.enabled = false;
     this._dbg = null;
   },
 
   /**
    * destroy the debugger and put the actor in the exited state.
    */
   exit: function () {
-    destroyPausedStateOverlays();
+    this.emit("exited");
     this.destroy();
     this._state = "exited";
   },
 
   // Request handlers
   onAttach: function (request) {
     if (this.state === "exited") {
       return { type: "exited" };
@@ -745,17 +747,16 @@ const ThreadActor = ActorClassWithSpec(t
             reportError(error);
             return {
               error: "unknownError",
               message: error.message + "\n" + error.stack
             };
           })
           .then(pkt => {
             this.conn.send(pkt);
-            showPausedStateOverlay(this._parent);
           });
 
                     return undefined;
                   });
 
       this._pushThreadPause();
     } catch (e) {
       reportError(e, "Got an exception during TA__pauseAndRespond: ");
@@ -1035,18 +1036,16 @@ const ThreadActor = ActorClassWithSpec(t
     let resumeLimitHandled;
     if (request && request.resumeLimit) {
       resumeLimitHandled = this._handleResumeLimit(request);
     } else {
       this._clearSteppingHooks(this.youngestFrame);
       resumeLimitHandled = resolve(true);
     }
 
-    hidePausedStateOverlay(this._parent);
-
     return resumeLimitHandled.then(() => {
       if (request) {
         this._options.pauseOnExceptions = request.pauseOnExceptions;
         this._options.ignoreCaughtExceptions = request.ignoreCaughtExceptions;
         this.maybePauseOnExceptions();
         this._maybeListenToEvents(request);
       }
 
@@ -1538,16 +1537,17 @@ const ThreadActor = ActorClassWithSpec(t
     // We don't want to actually have nested pauses (although we
     // have nested event loops).  If code runs in the debuggee during
     // a pause, it should cause the actor to resume (dropping
     // pause-lifetime actors etc) and then repause when complete.
 
     if (this.state === "paused") {
       return undefined;
     }
+    this.emit("pausing", this.state);
 
     // Clear stepping hooks.
     this.dbg.onEnterFrame = undefined;
     this.dbg.onExceptionUnwind = undefined;
     if (frame) {
       frame.onStep = undefined;
       frame.onPop = undefined;
     }
@@ -1603,16 +1603,17 @@ const ThreadActor = ActorClassWithSpec(t
   _resumed: function () {
     this._state = "running";
 
     // Drop the actors in the pause actor pool.
     this.conn.removeActorPool(this._pausePool);
 
     this._pausePool = null;
     this._pauseActor = null;
+    this.emit("resumed");
 
     return { from: this.actorID, type: "resumed" };
   },
 
   /**
    * Expire frame actors for frames that have been popped.
    *
    * @returns A list of actor IDs whose frames have been popped.
@@ -1897,18 +1898,16 @@ const ThreadActor = ActorClassWithSpec(t
       }
 
       packet.why = { type: "exception",
                      exception: createValueGrip(value, this._pausePool,
                                                 this.objectGrip)
       };
       this.conn.send(packet);
 
-      showPausedStateOverlay(this._parent);
-
       this._pushThreadPause();
     } catch (e) {
       reportError(e, "Got an exception during TA_onExceptionUnwind: ");
     }
 
     return undefined;
   },
 
@@ -2388,16 +2387,27 @@ exports.unwrapDebuggerObjectGlobal = wra
     return undefined;
   }
 };
 
 // Manage a collection of PausedDebuggerOverlays and their HighlighterEnvironments indexed
 // by TabActors (export it so it the paused state can be tested).
 const pausedStateOverlays = exports.pausedStateOverlays = new Map();
 
+function attachPauseStateListeners(threadActor) {
+  EventEmitter.on(threadActor, "pausing", (pausingState) => {
+    if (pausingState !== "attached") {
+      console.log(pausingState);
+      return showPausedStateOverlay(threadActor._parent);
+    }
+  });
+  EventEmitter.on(threadActor, "resumed",() => hidePausedStateOverlay(threadActor._parent));
+  EventEmitter.on(threadActor, "exiting",() => destroyPausedStateOverlay(threadActor._parent));
+}
+
 /**
  * Get the instance of the PausedDebuggerOverlay for a TabActor.
  *
  * @param {TabActor} tabActor
  *        The parent of the threadActor.
  *
  * @return {PausedDebuggerOverlay}
  *         The instance of the overlay, or null if it can't be created in this TabActor.
--- a/devtools/server/tests/unit/test_pausedOverlay.js
+++ b/devtools/server/tests/unit/test_pausedOverlay.js
@@ -24,17 +24,18 @@ var mockOverlay = {
       isOverlayVisible = true;
     },
     hide: () => {
       isOverlayVisible = false;
     }
   }
 };
 
-function run_test() {
+
+add_task(async function() {
   do_test_pending();
 
   Task.spawn(function* () {
     initTestDebuggerServer(DebuggerServer);
     gDebuggee = addTestGlobal("test-overlay", DebuggerServer);
     gClient = new DebuggerClient(DebuggerServer.connectPipe());
     yield gClient.connect();
 
@@ -49,17 +50,17 @@ function run_test() {
 
     yield test_debugger_statement();
     yield test_exception();
     yield test_breakpoint();
 
     yield gClient.close();
     do_test_finished();
   });
-}
+});
 
 function* test_debugger_statement() {
   ok(!isOverlayVisible, "The overlay is hidden at first");
 
   yield executeOnNextTickAndWaitForPause(() => {
     Cu.evalInSandbox("debugger;", gDebuggee);
   }, gClient);