Backed out changeset 30310d7d693a (bug 1582679) for mochitest assertions at nsWindow.cpp:3766. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Wed, 02 Oct 2019 00:14:31 +0300
changeset 495856 b277d1fdc9fb692fd84938d7d6a87f4e8eaf5acc
parent 495855 213ffedf9fc0faf9147cb5e47de47759981b2e45
child 495857 fbcd6b84b254279ec6296ab3bbfc486b7eed3478
push id114140
push userdvarga@mozilla.com
push dateWed, 02 Oct 2019 18:04:51 +0000
treeherdermozilla-inbound@32eb0ea893f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1582679
milestone71.0a1
backs out30310d7d693ae90f3154982ed13c5ae88096c169
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
Backed out changeset 30310d7d693a (bug 1582679) for mochitest assertions at nsWindow.cpp:3766. CLOSED TREE
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -402,16 +402,17 @@ nsWindow::nsWindow() {
   mHandleTouchEvent = false;
 #endif
   mIsDragPopup = false;
   mIsX11Display = GDK_IS_X11_DISPLAY(gdk_display_get_default());
 
   mContainer = nullptr;
   mGdkWindow = nullptr;
   mShell = nullptr;
+  mToplevelParentWindow = nullptr;
   mCompositorWidgetDelegate = nullptr;
   mHasMappedToplevel = false;
   mIsFullyObscured = false;
   mRetryPointerGrab = false;
   mWindowType = eWindowType_child;
   mSizeState = nsSizeMode_Normal;
   mAspectRatio = 0.0f;
   mLastSizeMode = nsSizeMode_Normal;
@@ -868,16 +869,17 @@ void nsWindow::SetParent(nsIWidget* aNew
       if (oldContainer == gInvisibleContainer) {
         CheckDestroyInvisibleContainer();
       }
     }
 
     gdk_window_reparent(mGdkWindow, newParentWindow,
                         DevicePixelsToGdkCoordRoundDown(mBounds.x),
                         DevicePixelsToGdkCoordRoundDown(mBounds.y));
+    mToplevelParentWindow = GTK_WINDOW(gtk_widget_get_toplevel(newContainer));
   }
 
   bool parentHasMappedToplevel = newParent && newParent->mHasMappedToplevel;
   if (mHasMappedToplevel != parentHasMappedToplevel) {
     SetHasMappedToplevel(parentHasMappedToplevel);
   }
 }
 
@@ -895,16 +897,17 @@ void nsWindow::ReparentNativeWidget(nsIW
       "nsWindow::ReparentNativeWidget() works on toplevel windows only.");
 
   auto* newParent = static_cast<nsWindow*>(aNewParent);
   GtkWindow* newParentWidget = GTK_WINDOW(newParent->GetGtkWidget());
   GtkWindow* shell = GTK_WINDOW(mShell);
 
   if (shell && gtk_window_get_transient_for(shell)) {
     gtk_window_set_transient_for(shell, newParentWidget);
+    mToplevelParentWindow = newParentWidget;
   }
 }
 
 void nsWindow::SetModal(bool aModal) {
   LOG(("nsWindow::SetModal [%p] %d\n", (void*)this, aModal));
   if (mIsDestroyed) return;
   if (!mIsTopLevel || !mShell) return;
   gtk_window_set_modal(GTK_WINDOW(mShell), aModal ? TRUE : FALSE);
@@ -1141,142 +1144,177 @@ bool nsWindow::IsWaylandPopup() {
 void nsWindow::HideWaylandTooltips() {
   while (gVisibleWaylandPopupWindows) {
     nsWindow* window =
         static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
     if (window->mPopupType != ePopupTypeTooltip) break;
     LOG(("nsWindow::HideWaylandTooltips [%p] hidding tooltip [%p].\n",
          (void*)this, window));
     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;
-  while (popupList) {
-    LOG(("  Looking for %p [nsWindow]\n", popupList->data));
-    nsWindow* waylandWnd = static_cast<nsWindow*>(popupList->data);
-    bool popupFound = false;
-    for (unsigned long i = 0; i < widgetChain.Length(); i++) {
-      if (waylandWnd == widgetChain[i]) {
-        popupFound = true;
-        break;
-      }
-    }
-    if (!popupFound) {
-      LOG(("    nsWindow [%p] not found in PopupManager, hiding it.\n",
-           waylandWnd));
-      waylandWnd->HideWaylandWindow();
-      popupList = gVisibleWaylandPopupWindows;
-    } else {
-      LOG(("    nsWindow [%p] is still open.\n", waylandWnd));
-      popupList = popupList->next;
-    }
-  }
-}
-
-// The MenuList popups are used as dropdown menus for example in WebRTC
-// microphone/camera chooser or autocomplete widgets.
-bool nsWindow::IsMainMenuWindow() {
-  nsIFrame* frame = GetFrame();
-  if (frame) {
-    nsMenuPopupFrame* menuPopupFrame = nullptr;
-    menuPopupFrame = do_QueryFrame(frame);
-    if (menuPopupFrame) {
-      LOG(("  nsMenuPopupFrame [%p] type: %d IsMenu: %d, IsMenuList: %d\n",
-           menuPopupFrame, menuPopupFrame->PopupType(),
-           menuPopupFrame->IsMenu(), menuPopupFrame->IsMenuList()));
-      return mPopupType == ePopupTypeMenu && !menuPopupFrame->IsMenuList();
-    }
+    gVisibleWaylandPopupWindows = g_list_delete_link(
+        gVisibleWaylandPopupWindows, gVisibleWaylandPopupWindows);
+  }
+}
+
+void nsWindow::HideWaylandPopupAndAllChildren() {
+  if (g_list_find(gVisibleWaylandPopupWindows, this) == nullptr) {
+    NS_WARNING("Popup window isn't in wayland popup list!");
+    return;
+  }
+
+  while (gVisibleWaylandPopupWindows) {
+    nsWindow* window =
+        static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
+    bool quit = gVisibleWaylandPopupWindows->data == this;
+    window->HideWaylandWindow();
+    gVisibleWaylandPopupWindows = g_list_delete_link(
+        gVisibleWaylandPopupWindows, gVisibleWaylandPopupWindows);
+    if (quit) break;
+  }
+}
+
+bool IsPopupWithoutToplevelParent(nsMenuPopupFrame* aMenuPopupFrame) {
+  // Check if the popup is autocomplete (like tags autocomplete
+  // in the bookmark edit popup).
+  nsAtom* popupId = aMenuPopupFrame->GetContent()->GetID();
+  if (popupId &&
+      popupId->Equals(NS_LITERAL_STRING("editBMPanel_tagsAutocomplete"))) {
+    return true;
+  }
+
+  nsIFrame* parentFrame = aMenuPopupFrame->GetParent();
+  if (!parentFrame) {
+    return false;
+  }
+
+  // Check if the popup is in the folder menu list
+  nsAtom* parentId = parentFrame->GetContent()->GetID();
+  if (parentId &&
+      parentId->Equals(NS_LITERAL_STRING("editBMPanel_folderMenuList"))) {
+    return true;
+  }
+
+  // Check if the popup is in popupnotificationcontent (like choosing capture
+  // device when starting webrtc session).
+  parentFrame = parentFrame->GetParent();
+  if (parentFrame && parentFrame->GetContent()->NodeName().EqualsLiteral(
+                         "popupnotificationcontent")) {
+    return true;
   }
   return false;
 }
 
 // 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));
-#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
 
   // Check if we're already configured.
   if (gVisibleWaylandPopupWindows &&
       g_list_find(gVisibleWaylandPopupWindows, this)) {
-    LOG(("  [%p] is already configured.\n", (void*)this));
+    LOG(("...[%p] is already configured.\n", (void*)this));
     return GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell)));
   }
 
   // If we're opening a new window we don't want to attach it to a tooltip
   // as it's short lived temporary window.
   HideWaylandTooltips();
 
-  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
-    // 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++) {
-      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;
+  GtkWindow* parentWidget = mToplevelParentWindow;
+  if (gVisibleWaylandPopupWindows) {
+    LOG(("... there's visible active popup [%p]\n",
+         gVisibleWaylandPopupWindows->data));
+
+    if (mPopupType == ePopupTypeTooltip) {
+      LOG(("...[%p] is tooltip, parent [%p]\n", (void*)this,
+           gVisibleWaylandPopupWindows->data));
+
+      // Attach tooltip window to the latest popup window
+      // to have both visible.
+      nsWindow* window =
+          static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
+      parentWidget = GTK_WINDOW(window->GetGtkWidget());
+    } else {
+      nsMenuPopupFrame* menuPopupFrame = nullptr;
+      nsIFrame* frame = GetFrame();
+      if (frame) {
+        menuPopupFrame = do_QueryFrame(frame);
+      }
+
+      // The popup is not fully created yet (we're called from
+      // nsWindow::Create()) or we're toplevel popup without parent.
+      // In both cases just use parent which was passed to nsWindow::Create().
+      if (!menuPopupFrame) {
+        LOG(("...[%p] menuPopupFrame = null, using given parent widget [%p]\n",
+             (void*)this, parentWidget));
+        return GTK_WIDGET(parentWidget);
+      }
+
+      LOG(("...[%p] is %s\n", (void*)this,
+           menuPopupFrame->IsContextMenu() ? "context menu" : "popup"));
+
+      nsWindow* parentWindow =
+          static_cast<nsWindow*>(menuPopupFrame->GetParentMenuWidget());
+      LOG(("...[%p] GetParentMenuWidget() = %p\n", (void*)this, parentWindow));
+
+      // If the popup is a regular menu but GetParentMenuWidget() returns
+      // nullptr which means is not a submenu of any other menu.
+      // In this case use a parent given at nsWindow::Create().
+      // But we have to avoid using mToplevelParentWindow in case the popup
+      // is in 'popupnotificationcontent' element or autocomplete popup,
+      //  otherwise the popupnotification would disappear when for
+      // example opening a popup with microphone selection.
+      if (!parentWindow && !menuPopupFrame->IsContextMenu() &&
+          !IsPopupWithoutToplevelParent(menuPopupFrame)) {
+        parentWindow =
+            get_window_for_gtk_widget(GTK_WIDGET(mToplevelParentWindow));
+      }
+
+      if (!parentWindow) {
+        LOG(("...[%p] using active/visible popups as a parent [%p]\n",
+             (void*)this, gVisibleWaylandPopupWindows->data));
+
+        // We're toplevel popup menu attached to another menu. Just use our
+        // latest popup as a parent.
+        parentWindow =
+            static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
+        parentWidget = GTK_WINDOW(parentWindow->GetGtkWidget());
+      } else {
+        // We're a regular menu in the same frame hierarchy.
+        // Close child popups on the same level as we can't have two popups
+        // with one parent on Wayland.
+        parentWidget = GTK_WINDOW(parentWindow->GetGtkWidget());
+        nsWindow* lastChildOnTheSameLevel = nullptr;
+        for (GList* popup = gVisibleWaylandPopupWindows; popup;
+             popup = popup->next) {
+          nsWindow* window =
+              static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
+          if (GTK_WINDOW(window->GetGtkWidget()) == parentWidget) {
+            break;
+          } else {
+            lastChildOnTheSameLevel = window;
+          }
+        }
+        if (lastChildOnTheSameLevel) {
+          lastChildOnTheSameLevel->HideWaylandPopupAndAllChildren();
+        }
       }
     }
-  } else {
-    // 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());
-    }
-  }
-  if (parentGtkWindow) {
-    MOZ_ASSERT(parentGtkWindow != GTK_WINDOW(this->GetGtkWidget()),
-               "Cannot set self as parent");
-    gtk_window_set_transient_for(GTK_WINDOW(mShell),
-                                 GTK_WINDOW(parentGtkWindow));
-  } else {
-    // Fallback to the parent given in nsWindow::Create (most likely the
-    // toplevel window).
-    parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell));
-  }
-  // Add current window to the visible popup list
+  }
+
+  MOZ_ASSERT(parentWidget, "Missing parent widget for wayland popup!");
+  if (parentWidget) {
+    LOG(("...[%p] set parent widget [%p]\n", (void*)this, parentWidget));
+    gtk_window_set_transient_for(GTK_WINDOW(mShell), parentWidget);
+  }
   gVisibleWaylandPopupWindows =
       g_list_prepend(gVisibleWaylandPopupWindows, this);
-
-  LOG(("  Parent window for %p: %p [GtkWindow]", this, parentGtkWindow));
-  return GTK_WIDGET(parentGtkWindow);
+  return GTK_WIDGET(parentWidget);
 }
 
 #ifdef DEBUG
 static void NativeMoveResizeWaylandPopupCallback(
     GdkWindow* window, const GdkRectangle* flipped_rect,
     const GdkRectangle* final_rect, gboolean flipped_x, gboolean flipped_y,
     void* aWindow) {
   LOG(("%s [%p] flipped %d %d\n", __FUNCTION__, aWindow, flipped_rect->x,
@@ -3542,24 +3580,16 @@ static GdkWindow* CreateGdkWindow(GdkWin
   gdk_window_set_user_data(window, widget);
 
   return window;
 }
 
 nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
                           const LayoutDeviceIntRect& aRect,
                           nsWidgetInitData* aInitData) {
-#ifdef MOZ_LOGGING
-  if (this->GetFrame() && this->GetFrame()->GetContent()) {
-    nsCString nodeName =
-        NS_ConvertUTF16toUTF8(this->GetFrame()->GetContent()->NodeName());
-    LOG(("nsWindow::Create: creating [%p]: nodename %s\n", this,
-         nodeName.get()));
-  }
-#endif
   // only set the base parent if we're going to be a dialog or a
   // toplevel
   nsIWidget* baseParent =
       aInitData && (aInitData->mWindowType == eWindowType_dialog ||
                     aInitData->mWindowType == eWindowType_toplevel ||
                     aInitData->mWindowType == eWindowType_invisible)
           ? nullptr
           : aParent;
@@ -3583,26 +3613,25 @@ nsresult nsWindow::Create(nsIWidget* aPa
 
   // and do our common creation
   CommonCreate(aParent, listenForResizes);
 
   // save our bounds
   mBounds = aRect;
   ConstrainSize(&mBounds.width, &mBounds.height);
 
-  GtkWidget* eventWidget = nullptr;
-  bool drawToContainer = false;
-  bool needsAlphaVisual = (mWindowType == eWindowType_popup &&
-                           (aInitData && aInitData->mSupportTranslucency));
-
-  // Figure out our parent window - only used for eWindowType_child
+  // figure out our parent window
   GtkWidget* parentMozContainer = nullptr;
   GtkContainer* parentGtkContainer = nullptr;
   GdkWindow* parentGdkWindow = nullptr;
   nsWindow* parentnsWindow = nullptr;
+  GtkWidget* eventWidget = nullptr;
+  bool drawToContainer = false;
+  bool needsAlphaVisual =
+      (mWindowType == eWindowType_popup && aInitData->mSupportTranslucency);
 
   if (aParent) {
     parentnsWindow = static_cast<nsWindow*>(aParent);
     parentGdkWindow = parentnsWindow->mGdkWindow;
   } else if (aNativeParent && GDK_IS_WINDOW(aNativeParent)) {
     parentGdkWindow = GDK_WINDOW(aNativeParent);
     parentnsWindow = get_window_for_gdk_window(parentGdkWindow);
     if (!parentnsWindow) return NS_ERROR_FAILURE;
@@ -3610,25 +3639,29 @@ nsresult nsWindow::Create(nsIWidget* aPa
   } else if (aNativeParent && GTK_IS_CONTAINER(aNativeParent)) {
     parentGtkContainer = GTK_CONTAINER(aNativeParent);
   }
 
   if (parentGdkWindow) {
     // get the widget for the window - it should be a moz container
     parentMozContainer = parentnsWindow->GetMozContainerWidget();
     if (!parentMozContainer) return NS_ERROR_FAILURE;
-  }
-  // ^^ only used for eWindowType_child
+
+    // get the toplevel window just in case someone needs to use it
+    // for setting transients or whatever.
+    mToplevelParentWindow =
+        GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer));
+  }
 
   if (!mIsX11Display) {
     if (mWindowType == eWindowType_child) {
       // eWindowType_child is not supported on Wayland. Just switch to toplevel
       // as a workaround.
       mWindowType = eWindowType_toplevel;
-    } else if (mWindowType == eWindowType_popup && !aNativeParent && !aParent) {
+    } else if (mWindowType == eWindowType_popup && !mToplevelParentWindow) {
       // Workaround for Wayland where the popup windows always need to have
       // parent window. For example webrtc ui is a popup window without parent.
       mWindowType = eWindowType_toplevel;
     }
   }
 
   mIsPIPWindow = aInitData && aInitData->mPIPWindow;
 
@@ -3756,27 +3789,17 @@ nsresult nsWindow::Create(nsIWidget* aPa
       NativeResize();
 
       if (mWindowType == eWindowType_dialog) {
         mGtkWindowRoleName = "Dialog";
 
         SetDefaultIcon();
         gtk_window_set_type_hint(GTK_WINDOW(mShell),
                                  GDK_WINDOW_TYPE_HINT_DIALOG);
-
-        MOZ_ASSERT(parentnsWindow != nullptr,
-                   "Dialog should always be created with parent!");
-        if (parentnsWindow) {
-          gtk_window_set_transient_for(
-              GTK_WINDOW(mShell), GTK_WINDOW(parentnsWindow->GetGtkWidget()));
-          LOG((
-              "nsWindow::Create(): dialog [%p], parent window %p [GdkWindow]\n",
-              this, aNativeParent));
-        }
-
+        gtk_window_set_transient_for(GTK_WINDOW(mShell), mToplevelParentWindow);
       } else if (mWindowType == eWindowType_popup) {
         mGtkWindowRoleName = "Popup";
 
         if (aInitData->mNoAutoHide) {
           // ... but the window manager does not decorate this window,
           // nor provide a separate taskbar icon.
           if (mBorderStyle == eBorderStyle_default) {
             gtk_window_set_decorated(GTK_WINDOW(mShell), FALSE);
@@ -3817,21 +3840,22 @@ nsresult nsWindow::Create(nsIWidget* aPa
               gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
               break;
             default:
               gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
               break;
           }
         }
         gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
-        if (parentnsWindow) {
-          LOG(("nsWindow::Create() [%p]: parent window for popup: %p\n", this,
-               parentnsWindow));
-          gtk_window_set_transient_for(
-              GTK_WINDOW(mShell), GTK_WINDOW(parentnsWindow->GetGtkWidget()));
+
+        if (mToplevelParentWindow) {
+          LOG(("nsWindow::Create [%p] Set popup parent %p\n", (void*)this,
+               mToplevelParentWindow));
+          gtk_window_set_transient_for(GTK_WINDOW(mShell),
+                                       mToplevelParentWindow);
         }
 
         // We need realized mShell at NativeMove().
         gtk_widget_realize(mShell);
 
         // With popup windows, we want to control their position, so don't
         // wait for the window manager to place them (which wouldn't
         // happen with override-redirect windows anyway).
@@ -4325,23 +4349,16 @@ void nsWindow::NativeMoveResize() {
   // Does it need to be shown because bounds were previously insane?
   if (mNeedsShow && mIsShown) {
     NativeShow(true);
   }
 }
 
 void nsWindow::HideWaylandWindow() {
 #ifdef MOZ_WAYLAND
-  if (mWindowType == eWindowType_popup) {
-    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(),
     // the current compositor cannot use it anymore. To avoid crash,
     // destroy the compositor & recreate a new compositor on next
     // expose event.
     DestroyLayerManager();
   }
 #endif
@@ -4355,33 +4372,31 @@ void nsWindow::NativeShow(bool aAction) 
 
     if (mIsTopLevel) {
       // Set up usertime/startupID metadata for the created window.
       if (mWindowType != eWindowType_invisible) {
         SetUserTimeAndStartupIDForActivatedWindow(mShell);
       }
       // Update popup window hierarchy run-time on Wayland.
       if (IsWaylandPopup()) {
-        if (!ConfigureWaylandPopupWindows()) {
-          mNeedsShow = true;
-          return;
-        }
+        ConfigureWaylandPopupWindows();
       }
       gtk_widget_show(mShell);
     } else if (mContainer) {
       gtk_widget_show(GTK_WIDGET(mContainer));
     } else if (mGdkWindow) {
       gdk_window_show_unraised(mGdkWindow);
     }
   } else {
     if (!mIsX11Display) {
-      if (IsWaylandPopup() && IsMainMenuWindow()) {
-        CleanupWaylandPopups();
+      if (IsWaylandPopup()) {
+        HideWaylandPopupAndAllChildren();
+      } else {
+        HideWaylandWindow();
       }
-      HideWaylandWindow();
     } else if (mIsTopLevel) {
       // Workaround window freezes on GTK versions before 3.21.2 by
       // ensuring that configure events get dispatched to windows before
       // they are unmapped. See bug 1225044.
       if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) {
         GtkAllocation allocation;
         gtk_widget_get_allocation(GTK_WIDGET(mShell), &allocation);
 
@@ -5279,17 +5294,17 @@ bool nsWindow::CheckForRollup(gdouble aM
     // if we're dealing with menus, we probably have submenus and
     // we don't want to rollup if the click is in a parent menu of
     // the current submenu
     uint32_t popupsToRollup = UINT32_MAX;
     if (!aAlwaysRollup) {
       AutoTArray<nsIWidget*, 5> widgetChain;
       uint32_t sameTypeCount =
           rollupListener->GetSubmenuWidgetChain(&widgetChain);
-      for (unsigned long i = 0; i < widgetChain.Length(); ++i) {
+      for (uint32_t i = 0; i < widgetChain.Length(); ++i) {
         nsIWidget* widget = widgetChain[i];
         auto* currWindow = (GdkWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
         if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
           // don't roll up if the mouse event occurred within a
           // menu of the same type. If the mouse event occurred
           // in a menu higher than that, roll up, but pass the
           // number of popups to Rollup so that only those of the
           // same type close up.
@@ -6642,47 +6657,21 @@ void nsWindow::SetDrawsInTitlebar(bool a
       UpdateTitlebarTransparencyBitmap();
     } else {
       ClearTransparencyBitmap();
     }
   }
 }
 
 gint nsWindow::GdkScaleFactor() {
-  GdkWindow* scaledGdkWindow = mGdkWindow;
-  if (!mIsX11Display) {
-    // For popup windows/dialogs with parent window we need to get scale factor
-    // of the topmost window. Otherwise the scale factor of the popup is
-    // not updated during it's hidden.
-    if (mWindowType == eWindowType_popup || mWindowType == eWindowType_dialog) {
-      // Get toplevel window for scale factor:
-      GtkWindow* parentWindow = GTK_WINDOW(GetGtkWidget());
-      GtkWindow* topmostParentWindow;
-      while (parentWindow) {
-        topmostParentWindow = parentWindow;
-        parentWindow = gtk_window_get_transient_for(parentWindow);
-      }
-      if (topmostParentWindow) {
-        scaledGdkWindow =
-            gtk_widget_get_window(GTK_WIDGET(topmostParentWindow));
-      } else {
-        NS_WARNING("Popup/Dialog has no parent.");
-      }
-      // Fallback for windows which parent has been unrealized.
-      if (!scaledGdkWindow) {
-        scaledGdkWindow = mGdkWindow;
-      }
-    }
-  }
   // Available as of GTK 3.10+
   static auto sGdkWindowGetScaleFactorPtr =
       (gint(*)(GdkWindow*))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
-  if (sGdkWindowGetScaleFactorPtr && scaledGdkWindow) {
-    return (*sGdkWindowGetScaleFactorPtr)(scaledGdkWindow);
-  }
+  if (sGdkWindowGetScaleFactorPtr && mGdkWindow)
+    return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
   return ScreenHelperGTK::GetGTKMonitorScaleFactor();
 }
 
 gint nsWindow::DevicePixelsToGdkCoordRoundUp(int pixels) {
   gint scale = GdkScaleFactor();
   return (pixels + scale - 1) / scale;
 }
 
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -478,16 +478,17 @@ class nsWindow final : public nsBaseWidg
 #endif
   nsCString mGtkWindowAppName;
   nsCString mGtkWindowRoleName;
   void RefreshWindowClass();
 
   GtkWidget* mShell;
   MozContainer* mContainer;
   GdkWindow* mGdkWindow;
+  GtkWindow* mToplevelParentWindow;
   bool mWindowShouldStartDragging = false;
   PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate;
 
   uint32_t mHasMappedToplevel : 1, mIsFullyObscured : 1, mRetryPointerGrab : 1;
   nsSizeMode mSizeState;
   float mAspectRatio;
   nsIntPoint mClientOffset;
 
@@ -615,22 +616,20 @@ class nsWindow final : public nsBaseWidg
   void CleanLayerManagerRecursive();
 
   virtual int32_t RoundsWidgetCoordinatesTo() override;
 
   void ForceTitlebarRedraw();
 
   void SetPopupWindowDecoration(bool aShowOnTaskbar);
 
-  bool IsMainMenuWindow();
   GtkWidget* ConfigureWaylandPopupWindows();
   void HideWaylandWindow();
   void HideWaylandTooltips();
   void HideWaylandPopupAndAllChildren();
-  void CleanupWaylandPopups();
 
   /**
    * |mIMContext| takes all IME related stuff.
    *
    * This is owned by the top-level nsWindow or the topmost child
    * nsWindow embedded in a non-Gecko widget.
    *
    * The instance is created when the top level widget is created.  And when