Bug 1320361 - Popup notifications don't hide when the window is minimized on Linux. r=johannh draft
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Wed, 22 Feb 2017 14:10:27 +0000
changeset 488071 e9dfd76c4a56adcb8131a5dafd8ef2593f4ef412
parent 487354 b69d4316561aa125612509a202922455d2de03e5
child 546632 25a879485de2158e5909a8a78787e5bbc4df5f27
push id46417
push userpaolo.mozmail@amadzone.org
push dateWed, 22 Feb 2017 15:17:31 +0000
reviewersjohannh
bugs1320361
milestone54.0a1
Bug 1320361 - Popup notifications don't hide when the window is minimized on Linux. r=johannh MozReview-Commit-ID: Lu4GOmzsuBx
toolkit/modules/PopupNotifications.jsm
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -882,19 +882,41 @@ PopupNotifications.prototype = {
 
     if (checked) {
       this._setNotificationUIState(notificationEl, notification.options.checkbox.checkedState);
     } else {
       this._setNotificationUIState(notificationEl, notification.options.checkbox.uncheckedState);
     }
   },
 
-  _showPanel: function PopupNotifications_showPanel(notificationsToShow, anchorElement) {
+  /**
+   * Sets the "noautohide" mode of the notification panel while it is closed.
+   */
+  _setNoAutoHide(value) {
+    // This method can only be used while the panel is closed because the
+    // "noautohide" attribute is stored in the initialization data of the widget
+    // associated to the <panel> element. Platforms other than Linux keep track
+    // of changes made to the attribute, but on Linux this isn't currently done
+    // because the type of GTK window created for the two cases is different
+    // anyways. In practice, this means that on Linux the panel mode can only be
+    // changed while the element is not part of the layout, in other words the
+    // panel should be closed and the <panel> element should be hidden.
+    if (value) {
+      this.panel.setAttribute("noautohide", "true");
+    } else {
+      this.panel.removeAttribute("noautohide");
+    }
+
+    // Force a layout flush to update the widget initialization data on Linux.
+    this.panel.hidden = true;
+    this.panel.clientWidth; // flush
     this.panel.hidden = false;
+  },
 
+  _showPanel: function PopupNotifications_showPanel(notificationsToShow, anchorElement) {
     notificationsToShow = notificationsToShow.filter(n => {
       if (anchorElement != n.anchorElement) {
         return false;
       }
 
       let dismiss = this._fireCallback(n, NOTIFICATION_EVENT_SHOWING);
       if (dismiss)
         n.dismissed = true;
@@ -921,43 +943,37 @@ PopupNotifications.prototype = {
       }
     }
 
     if (this.isPanelOpen && this._currentAnchorElement == anchorElement) {
       notificationsToShow.forEach(function(n) {
         this._fireCallback(n, NOTIFICATION_EVENT_SHOWN);
       }, this);
 
-      // Make sure we update the noautohide attribute on the panel, in case it changed.
-      if (notificationsToShow.some(n => n.options.persistent)) {
-        this.panel.setAttribute("noautohide", "true");
-      } else {
-        this.panel.removeAttribute("noautohide");
-      }
-
       // Let tests know that the panel was updated and what notifications it was
       // updated with so that tests can wait for the correct notifications to be
       // added.
       let event = new this.window.CustomEvent("PanelUpdated",
                                               {"detail": notificationIds});
       this.panel.dispatchEvent(event);
       return;
     }
 
     // If the panel is already open but we're changing anchors, we need to hide
     // it first.  Otherwise it can appear in the wrong spot.  (_hidePanel is
     // safe to call even if the panel is already hidden.)
     this._hidePanel().then(() => {
       this._currentAnchorElement = anchorElement;
 
-      if (notificationsToShow.some(n => n.options.persistent)) {
-        this.panel.setAttribute("noautohide", "true");
-      } else {
-        this.panel.removeAttribute("noautohide");
-      }
+      // Update the "noautohide" attribute on the panel based on the type of
+      // notifications displayed. This attribute cannot change until the panel
+      // is closed, but this is only relevant if we use the same panel to show
+      // multiple notifications with different persistence, which rarely, if
+      // ever, happens in practice.
+      this._setNoAutoHide(notificationsToShow.some(n => n.options.persistent));
 
       // On OS X and Linux we need a different panel arrow color for
       // click-to-play plugins, so copy the popupid and use css.
       this.panel.setAttribute("popupid", this.panel.firstChild.getAttribute("popupid"));
       notificationsToShow.forEach(function(n) {
         // Record that the notification was actually displayed on screen.
         // Notifications that were opened a second time or that were originally
         // shown with "options.dismissed" will be recorded in a separate bucket.