Bug 1585918 Show only one remote content panel at a time; r=stransky
authorJan Horak <jhorak@redhat.com>
Thu, 21 Nov 2019 12:19:19 +0000
changeset 503216 6e1f760e5b8dc7e363962fb1ec2f8084c5a95f7d
parent 503215 fd4631c7d8cb0a07c3713894879d22be070a6b6b
child 503217 2ac10349166012fa4d1237a099470a4c88621a7c
push id101195
push userbtara@mozilla.com
push dateThu, 21 Nov 2019 22:19:37 +0000
treeherderautoland@6e1f760e5b8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstransky
bugs1585918
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1585918 Show only one remote content panel at a time; r=stransky Items in overflow-widget which belongs to addons cannot have the overflow-widget panel set as a popup parent because the overflow-widget is replaced by them. We also need to close the addon panel before we return back to overflow-widget to avoid simillar problem. Differential Revision: https://phabricator.services.mozilla.com/D53011
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1160,16 +1160,24 @@ void nsWindow::HideWaylandTooltips() {
         static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
     if (window->mPopupType != ePopupTypeTooltip) break;
     LOG(("nsWindow::HideWaylandTooltips [%p] hidding tooltip [%p].\n",
          (void*)this, window));
     window->HideWaylandWindow();
   }
 }
 
+void nsWindow::HideWaylandOpenedPopups() {
+  while (gVisibleWaylandPopupWindows) {
+    nsWindow* window =
+        static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
+    window->HideWaylandWindow();
+  }
+}
+
 // Hide popup nsWindows which are no longer in the nsXULPopupManager widget
 // chain list.
 void nsWindow::CleanupWaylandPopups() {
   LOG(("nsWindow::CleanupWaylandPopups...\n"));
   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   AutoTArray<nsIWidget*, 5> widgetChain;
   pm->GetSubmenuWidgetChain(&widgetChain);
   GList* popupList = gVisibleWaylandPopupWindows;
@@ -1213,17 +1221,20 @@ bool nsWindow::IsMainMenuWindow() {
 }
 
 // Wayland keeps strong popup window hierarchy. We need to track active
 // (visible) popup windows and make sure we hide popup on the same level
 // before we open another one on that level. It means that every open
 // popup needs to have an unique parent.
 GtkWidget* nsWindow::ConfigureWaylandPopupWindows() {
   MOZ_ASSERT(this->mWindowType == eWindowType_popup);
-  LOG(("nsWindow::ConfigureWaylandPopupWindows [%p]\n", (void*)this));
+  LOG(
+      ("nsWindow::ConfigureWaylandPopupWindows [%p], frame %p hasRemoteContent "
+       "%d\n",
+       (void*)this, this->GetFrame(), this->HasRemoteContent()));
 #if DEBUG
   if (this->GetFrame() && this->GetFrame()->GetContent()->GetID()) {
     nsCString nodeId;
     this->GetFrame()->GetContent()->GetID()->ToUTF8String(nodeId);
     LOG(("  [%p] popup node id=%s\n", this, nodeId.get()));
   }
 #endif
 
@@ -1240,35 +1251,58 @@ GtkWidget* nsWindow::ConfigureWaylandPop
 
   GtkWindow* parentGtkWindow = nullptr;
 
   if (IsMainMenuWindow()) {
     // Remove and hide already closed popups from the
     // gVisibleWaylandPopupWindows which were not yet been hidden.
     CleanupWaylandPopups();
     // Since the popups are shown by unknown order it can happen that child
-    // popup is shown before parent popup. The
+    // popup is shown before parent popup.
     // We look for the current window parent in nsXULPopupManager since it
     // always has correct popup hierarchy while gVisibleWaylandPopupWindows may
     // not.
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     AutoTArray<nsIWidget*, 5> widgetChain;
     pm->GetSubmenuWidgetChain(&widgetChain);
-    for (unsigned long i = 0; i < widgetChain.Length(); i++) {
+    for (unsigned long i = 0; i < widgetChain.Length() - 1; i++) {
       unsigned long parentIndex = i + 1;
       if (widgetChain.Length() > parentIndex && widgetChain[i] == this) {
         nsWindow* parentWindow =
             static_cast<nsWindow*>(widgetChain[parentIndex]);
         parentGtkWindow = GTK_WINDOW(parentWindow->GetGtkWidget());
         LOG(("  [%p] Found %p as parent in nsXULPopupManager.", this,
              parentWindow));
         break;
       }
     }
   } else {
+    // Panels usually ends there
+    if (gVisibleWaylandPopupWindows && HasRemoteContent()) {
+      // If the new panel is remote content, we need to close all other popups
+      // before to keep the correct hierarchy because the remote content popup
+      // can replace the overflow-widget panel.
+      HideWaylandOpenedPopups();
+    } else if (gVisibleWaylandPopupWindows) {
+      // If there is any remote content panel currently opened, close all
+      // opened popups to keep the correct hierarchy.
+      GList* popupList = gVisibleWaylandPopupWindows;
+      while (popupList) {
+        nsWindow* waylandWnd = static_cast<nsWindow*>(popupList->data);
+        LOG(("  Checking [%p] IsRemoteContent %d\n", popupList->data,
+             waylandWnd->IsRemoteContent()));
+        if (waylandWnd->IsRemoteContent()) {
+          // close all popups including remote content before showing our panel
+          // Most likely returning from addon panel to overflow-widget.
+          HideWaylandOpenedPopups();
+          break;
+        }
+        popupList = popupList->next;
+      }
+    }
     // For popups in panels use the last opened popup window as parent,
     // panels are not stored in nsXULPopupManager.
     if (gVisibleWaylandPopupWindows) {
       nsWindow* parentWindow =
           static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
       parentGtkWindow = GTK_WINDOW(parentWindow->GetGtkWidget());
     }
   }
@@ -4364,16 +4398,17 @@ void nsWindow::NativeMoveResize() {
   if (mNeedsShow && mIsShown) {
     NativeShow(true);
   }
 }
 
 void nsWindow::HideWaylandWindow() {
 #ifdef MOZ_WAYLAND
   if (mWindowType == eWindowType_popup) {
+    LOG(("nsWindow::HideWaylandWindow: popup [%p]\n", this));
     GList* foundWindow = g_list_find(gVisibleWaylandPopupWindows, this);
     if (foundWindow) {
       gVisibleWaylandPopupWindows =
           g_list_delete_link(gVisibleWaylandPopupWindows, foundWindow);
     }
   }
   if (mContainer && moz_container_has_wl_egl_window(mContainer)) {
     // Because wl_egl_window is destroyed on moz_container_unmap(),
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -396,16 +396,18 @@ class nsWindow final : public nsBaseWidg
   static CSDSupportLevel GetSystemCSDSupportLevel();
 
   static bool HideTitlebarByDefault();
   static bool GetTopLevelWindowActiveState(nsIFrame* aFrame);
   static bool TitlebarCanUseShapeMask();
 #ifdef MOZ_WAYLAND
   virtual nsresult GetScreenRect(LayoutDeviceIntRect* aRect) override;
 #endif
+  bool IsRemoteContent() { return HasRemoteContent(); }
+  static void HideWaylandOpenedPopups();
 
  protected:
   virtual ~nsWindow();
 
   // event handling code
   void DispatchActivateEvent(void);
   void DispatchDeactivateEvent(void);
   void DispatchResized();