diff --git a/view/nsView.cpp b/view/nsView.cpp index 8acedb73d731..3f17afc92c4c 100644 --- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -320,7 +320,6 @@ void nsView::DoResetWidgetBounds(bool aMoveOnly, // Stash a copy of these and use them so we can handle this being deleted (say // from sync painting/flushing from Show/Move/Resize on the widget). LayoutDeviceIntRect newBounds; - RefPtr dx = mViewManager->GetDeviceContext(); nsWindowType type = widget->WindowType(); @@ -360,7 +359,8 @@ void nsView::DoResetWidgetBounds(bool aMoveOnly, // because of the potential for device-pixel coordinate spaces for mixed // hidpi/lodpi screens to overlap each other and result in bad placement // (bug 814434). - DesktopToLayoutDeviceScale scale = dx->GetDesktopToDeviceScale(); + + DesktopToLayoutDeviceScale scale = widget->GetDesktopToDeviceScaleByScreen(); DesktopRect deskRect = newBounds / scale; if (changedPos) { diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 5203b24f28dc..8957d4755bf4 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -57,6 +57,7 @@ #if defined(MOZ_WAYLAND) #include +#include "nsView.h" #endif #include "nsGkAtoms.h" @@ -841,6 +842,37 @@ nsWindow::GetDesktopToDeviceScale() return DesktopToLayoutDeviceScale(1.0); } +DesktopToLayoutDeviceScale +nsWindow::GetDesktopToDeviceScaleByScreen() +{ +#ifdef MOZ_WAYLAND + GdkDisplay* gdkDisplay = gdk_display_get_default(); + // In Wayland there's no way to get absolute position of the window and use it to + // determine the screen factor of the monitor on which the window is placed. + // The window is notified of the current scale factor but not at this point, + // so the GdkScaleFactor can return wrong value which can lead to wrong popup + // placement. + // We need to use parent's window scale factor for the new one. + if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) { + nsView* view = nsView::GetViewFor(this); + if (view) { + nsView* parentView = view->GetParent(); + if (parentView) { + nsIWidget* parentWidget = parentView->GetNearestWidget(nullptr); + if (parentWidget) { + return DesktopToLayoutDeviceScale(parentWidget->RoundsWidgetCoordinatesTo()); + } else { + NS_WARNING("Widget has no parent"); + } + } + } else { + NS_WARNING("Cannot find widget view"); + } + } +#endif + return nsBaseWidget::GetDesktopToDeviceScale(); +} + void nsWindow::SetParent(nsIWidget *aNewParent) { diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index d3f0182745d5..f0ad1ebaf83b 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -125,6 +125,7 @@ public: virtual float GetDPI() override; virtual double GetDefaultScaleInternal() override; mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override; + mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen() override; virtual void SetParent(nsIWidget* aNewParent) override; virtual void SetModal(bool aModal) override; virtual bool IsVisible() const override; diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index c47707b000f7..38a9d2ff5299 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -84,6 +84,8 @@ #include "mozilla/layers/CompositorSession.h" #include "VRManagerChild.h" #include "gfxConfig.h" +#include "nsView.h" +#include "nsViewManager.h" #ifdef DEBUG #include "nsIObserver.h" @@ -2090,6 +2092,12 @@ nsBaseWidget::GetWidgetScreen() return screen.forget(); } +mozilla::DesktopToLayoutDeviceScale +nsBaseWidget::GetDesktopToDeviceScaleByScreen() +{ + return (nsView::GetViewFor(this)->GetViewManager()->GetDeviceContext())->GetDesktopToDeviceScale(); +} + nsresult nsIWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint, bool aLongTap, nsIObserver* aObserver) diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 947424ca2390..013b51bdd64b 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -24,6 +24,7 @@ #include "nsIWidgetListener.h" #include "nsPIDOMWindow.h" #include "nsWeakReference.h" + #include #if defined(XP_WIN) @@ -238,6 +239,8 @@ public: mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override { return mozilla::DesktopToLayoutDeviceScale(1.0); } + mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen() override; + virtual void ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) override {} diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 2ae236124883..e8fa4ec88300 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -577,6 +577,13 @@ class nsIWidget : public nsISupports */ virtual mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() = 0; + /** + * Return the scaling factor between device pixels and the platform- + * dependent "desktop pixels" by looking up the screen by the position + * of the widget. + */ + virtual mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen() = 0; + /** * Return the default scale factor for the window. This is the * default number of device pixels per CSS pixel to use. This should