Bug 1310957 - listen to XUL Panel wrapper hidden event to hide HTML tooltip;r=gl draft
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 19 Oct 2016 00:08:00 +0200
changeset 426866 84d6d664b274354387c239a84b4b7b4244c619ce
parent 426771 90d8afaddf9150853b0b68b35b30c1e54a8683e7
child 534295 1d66266f02153afdc211e650fb7ae610d94202ba
push id32833
push userjdescottes@mozilla.com
push dateWed, 19 Oct 2016 09:06:54 +0000
reviewersgl
bugs1310957
milestone52.0a1
Bug 1310957 - listen to XUL Panel wrapper hidden event to hide HTML tooltip;r=gl MozReview-Commit-ID: 7iyc2QY0KbP
devtools/client/shared/test/browser_html_tooltip-03.js
devtools/client/shared/widgets/tooltip/HTMLTooltip.js
--- a/devtools/client/shared/test/browser_html_tooltip-03.js
+++ b/devtools/client/shared/test/browser_html_tooltip-03.js
@@ -38,24 +38,17 @@ add_task(function* () {
   let [, , doc] = yield createHost("bottom", TEST_URI);
 
   info("Run tests for a Tooltip without using a XUL panel");
   useXulWrapper = false;
   yield runTests(doc);
 
   info("Run tests for a Tooltip with a XUL panel");
   useXulWrapper = true;
-
-  let isLinux = Services.appinfo.OS === "Linux";
-  if (!isLinux) {
-    // Skip these tests on linux when using a XUL Panel wrapper because some linux window
-    // manager don't support nicely XUL Panels with noautohide _and_ noautofocus.
-    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1301342#c11
-    yield runTests(doc);
-  }
+  yield runTests(doc);
 });
 
 function* runTests(doc) {
   yield testNoAutoFocus(doc);
   yield testAutoFocus(doc);
   yield testAutoFocusPreservesFocusChange(doc);
 }
 
--- a/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
+++ b/devtools/client/shared/widgets/tooltip/HTMLTooltip.js
@@ -224,16 +224,17 @@ function HTMLTooltip(toolboxDoc, {
 
   // The top window is used to attach click event listeners to close the tooltip if the
   // user clicks on the content page.
   this.topWindow = this._getTopWindow();
 
   this._position = null;
 
   this._onClick = this._onClick.bind(this);
+  this._onXulPanelHidden = this._onXulPanelHidden.bind(this);
 
   this._toggle = new TooltipToggle(this);
   this.startTogglingOnHover = this._toggle.start.bind(this._toggle);
   this.stopTogglingOnHover = this._toggle.stop.bind(this._toggle);
 
   this.container = this._createContainer();
 
   if (stylesheet) {
@@ -534,16 +535,22 @@ HTMLTooltip.prototype = {
         return this.panel.contains(win.frameElement);
       }
       win = win.parent;
     }
 
     return false;
   },
 
+  _onXulPanelHidden: function () {
+    if (this.isVisible()) {
+      this.hide();
+    }
+  },
+
   /**
    * If the tootlip is configured to autofocus and a focusable element can be found,
    * focus it.
    */
   _maybeFocusTooltip: function () {
     // Simplied selector targetting elements that can receive the focus, full version at
     // http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus .
     let focusableSelector = "a, button, iframe, input, select, textarea";
@@ -567,36 +574,43 @@ HTMLTooltip.prototype = {
   _createXulPanelWrapper: function () {
     let panel = this.doc.createElementNS(XUL_NS, "panel");
 
     // XUL panel is only a way to display DOM elements outside of the document viewport,
     // so disable all features that impact the behavior.
     panel.setAttribute("animate", false);
     panel.setAttribute("consumeoutsideclicks", false);
     panel.setAttribute("noautofocus", true);
-    panel.setAttribute("noautohide", true);
     panel.setAttribute("ignorekeys", true);
     panel.setAttribute("tooltip", "aHTMLTooltip");
 
     // Use type="arrow" to prevent side effects (see Bug 1285206)
     panel.setAttribute("type", "arrow");
 
     panel.setAttribute("level", "top");
     panel.setAttribute("class", "tooltip-xul-wrapper");
 
     return panel;
   },
 
   _showXulWrapperAt: function (left, top) {
+    this.xulPanelWrapper.addEventListener("popuphidden", this._onXulPanelHidden);
     let onPanelShown = listenOnce(this.xulPanelWrapper, "popupshown");
     this.xulPanelWrapper.openPopupAtScreen(left, top, false);
     return onPanelShown;
   },
 
   _hideXulWrapper: function () {
+    this.xulPanelWrapper.removeEventListener("popuphidden", this._onXulPanelHidden);
+
+    if (this.xulPanelWrapper.state === "closed") {
+      // XUL panel is already closed, resolve immediately.
+      return Promise.resolve();
+    }
+
     let onPanelHidden = listenOnce(this.xulPanelWrapper, "popuphidden");
     this.xulPanelWrapper.hidePopup();
     return onPanelHidden;
   },
 
   /**
    * Convert from coordinates relative to the tooltip's document, to coordinates relative
    * to the "available" screen. By "available" we mean the screen, excluding the OS bars