commit b36fee37f4924ba852068fac06f0f1b9438244c6
parent ad022d937a6b2cd1740c3224f55fb860c6e258fd
Author: Narcis Beleuzu <nbeleuzu@mozilla.com>
Date: Wed, 22 Oct 2025 12:59:03 +0300
Revert "Bug 1992198 [Linux] Use logical (widget) coordinates to calculate widget size/positions/boundaries r=emilio,layout-reviewers" for causing bustages on nsWindow.cpp
This reverts commit 7b404e65ccff32c43e4f2b8fb268b52c1f04f3c2.
Diffstat:
6 files changed, 331 insertions(+), 563 deletions(-)
diff --git a/layout/base/Units.h b/layout/base/Units.h
@@ -178,7 +178,6 @@ typedef gfx::SizeTyped<DesktopPixel> DesktopSize;
typedef gfx::IntSizeTyped<DesktopPixel> DesktopIntSize;
typedef gfx::RectTyped<DesktopPixel> DesktopRect;
typedef gfx::IntRectTyped<DesktopPixel> DesktopIntRect;
-typedef gfx::IntMarginTyped<DesktopPixel> DesktopIntMargin;
typedef gfx::CoordTyped<ExternalPixel> ExternalCoord;
typedef gfx::IntCoordTyped<ExternalPixel> ExternalIntCoord;
@@ -707,9 +706,6 @@ struct ParentLayerPixel {};
* - on Windows *with* per-monitor DPI support, they are physical device pixels
* on each screen; note that this means the scaling between CSS pixels and
* desktop pixels may vary across multiple displays.
- * - on Linux, they're "Gdk points", which correspond to widget coordinates
- * used by Gdk and X11 or Wayland compositor and are mapped to actual
- * screen pixels by per-monitor screen scale.
*/
struct DesktopPixel {};
@@ -954,15 +950,6 @@ gfx::MarginTyped<Dst, F> operator/(
aMargin.bottom.value / aScale.yScale, aMargin.left.value / aScale.xScale);
}
-template <class Src, class Dst>
-gfx::MarginTyped<Dst> operator*(const gfx::IntMarginTyped<Src>& aMargin,
- const gfx::ScaleFactor<Src, Dst>& aScale) {
- return gfx::MarginTyped<Dst>(float(aMargin.top.value) * aScale.scale,
- float(aMargin.right.value) * aScale.scale,
- float(aMargin.bottom.value) * aScale.scale,
- float(aMargin.left.value) * aScale.scale);
-}
-
// Calculate the max or min or the ratios of the widths and heights of two
// sizes, returning a scale factor in the correct units.
diff --git a/widget/gtk/ScreenHelperGTK.cpp b/widget/gtk/ScreenHelperGTK.cpp
@@ -78,12 +78,21 @@ static already_AddRefed<Screen> MakeScreenGtk(unsigned int aMonitor,
workarea.width * geometryScaleFactor,
workarea.height * geometryScaleFactor);
+ LayoutDeviceIntRect rect;
DesktopToLayoutDeviceScale contentsScale(1.0);
CSSToLayoutDeviceScale defaultCssScale(geometryScaleFactor);
- contentsScale.scale = geometryScaleFactor;
+ if (GdkIsX11Display()) {
+ GdkRectangle monitor;
+ gdk_screen_get_monitor_geometry(defaultScreen, aMonitor, &monitor);
+ rect = LayoutDeviceIntRect(monitor.x * geometryScaleFactor,
+ monitor.y * geometryScaleFactor,
+ monitor.width * geometryScaleFactor,
+ monitor.height * geometryScaleFactor);
+ } else {
+ // Use per-monitor scaling factor in Wayland.
+ contentsScale.scale = geometryScaleFactor;
#ifdef MOZ_WAYLAND
- if (GdkIsWaylandDisplay()) {
if (StaticPrefs::widget_wayland_fractional_scale_enabled()) {
// Check if we're using fractional scale (see Bug 1985720).
// In such case use workarea is already scaled by fractional scale factor.
@@ -101,21 +110,10 @@ static already_AddRefed<Screen> MakeScreenGtk(unsigned int aMonitor,
contentsScale.scale = fractionalScale;
}
}
+#endif
// Don't report screen shift in Wayland, see bug 1795066.
availRect.MoveTo(0, 0);
- }
-#endif
-
- // Use workarea as screen rect on Wayland (Bug 1732682).
- LayoutDeviceIntRect rect;
- if (GdkIsX11Display()) {
- GdkRectangle monitor;
- gdk_screen_get_monitor_geometry(defaultScreen, aMonitor, &monitor);
- rect = LayoutDeviceIntRect(monitor.x * geometryScaleFactor,
- monitor.y * geometryScaleFactor,
- monitor.width * geometryScaleFactor,
- monitor.height * geometryScaleFactor);
- } else {
+ // We use Gtk workarea on Wayland as it matches our needs (Bug 1732682).
rect = availRect;
}
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
@@ -455,7 +455,7 @@ nsWindow::nsWindow()
mConfiguredClearColor(false),
mGotNonBlankPaint(false),
mNeedsToRetryCapturingMouse(false) {
- SetSafeWindowSize(mSizeConstraints.mMaxSize);
+ mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
if (!gGlobalsInitialized) {
gGlobalsInitialized = true;
@@ -592,14 +592,15 @@ void nsWindow::DispatchResized() {
auto clientSize = GetClientSize();
- LOG("nsWindow::DispatchResized() client size [%d, %d]", (int)clientSize.width,
+ LOG("nsWindow::DispatchResized() size [%d, %d] client size [%d, %d]",
+ (int)(mBounds.width), (int)(mBounds.height), (int)clientSize.width,
(int)clientSize.height);
- // Check out painting texture size
+ // Check mBounds size
if (mCompositorSession &&
- !wr::WindowSizeSanityCheck(clientSize.width, clientSize.height)) {
- gfxCriticalNoteOnce << "Invalid mClientArea in MaybeDispatchResized "
- << clientSize << " size state " << mSizeMode;
+ !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
+ gfxCriticalNoteOnce << "Invalid mBounds in MaybeDispatchResized " << mBounds
+ << " size state " << mSizeMode;
}
// Notify the GtkCompositorWidget of a ClientSizeChange
@@ -654,7 +655,7 @@ void nsWindow::OnDestroy(void) {
}
bool nsWindow::AreBoundsSane() {
- // Check requested size, as mClientArea might not have been updated.
+ // Check requested size, as mBounds might not have been updated.
return !mLastSizeRequest.IsEmpty();
}
@@ -770,7 +771,14 @@ float nsWindow::GetDPI() {
double nsWindow::GetDefaultScaleInternal() { return FractionalScaleFactor(); }
DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScale() {
- return DesktopToLayoutDeviceScale(FractionalScaleFactor());
+#ifdef MOZ_WAYLAND
+ if (GdkIsWaylandDisplay()) {
+ return DesktopToLayoutDeviceScale(FractionalScaleFactor());
+ }
+#endif
+
+ // In Gtk/X11, we manage windows using device pixels.
+ return DesktopToLayoutDeviceScale(1.0);
}
bool nsWindow::WidgetTypeSupportsAcceleration() {
@@ -887,9 +895,8 @@ void nsWindow::ConstrainPosition(DesktopIntPoint& aPoint) {
double dpiScale = GetDefaultScale().scale;
// we need to use the window size in logical screen pixels
- auto bounds = GetScreenBounds();
- int32_t logWidth = std::max(NSToIntRound(bounds.width / dpiScale), 1);
- int32_t logHeight = std::max(NSToIntRound(bounds.height / dpiScale), 1);
+ int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1);
+ int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1);
/* get our playing field. use the current screen, or failing that
for any reason, use device caps for the default screen. */
@@ -920,43 +927,33 @@ void nsWindow::ConstrainPosition(DesktopIntPoint& aPoint) {
aPoint = ConstrainPositionToBounds(aPoint, {logWidth, logHeight}, screenRect);
}
-bool nsWindow::ConstrainSizeWithScale(int* aWidth, int* aHeight,
- double aScale) {
+void nsWindow::ConstrainSize(int* aWidth, int* aHeight) {
// We store our constraints in inner sizes for convenience, but that means we
// need to also constrain inner sizes as inner, rather than outer.
- int scaledWidth = (*aWidth - mClientMargin.LeftRight()) * aScale;
- int scaledHeight = (*aHeight - mClientMargin.TopBottom()) * aScale;
- int tmpWidth = scaledWidth, tmpHeight = scaledHeight;
- nsIWidget::ConstrainSize(&tmpWidth, &tmpHeight);
- if (tmpWidth != scaledWidth || tmpHeight != scaledHeight) {
- *aWidth = int(round(tmpWidth / aScale)) + mClientMargin.LeftRight();
- *aHeight = int(round(tmpHeight / aScale)) + mClientMargin.TopBottom();
- return true;
- }
- return false;
+ *aWidth -= mClientMargin.LeftRight();
+ *aHeight -= mClientMargin.TopBottom();
+ nsIWidget::ConstrainSize(aWidth, aHeight);
+ *aWidth += mClientMargin.LeftRight();
+ *aHeight += mClientMargin.TopBottom();
}
-// aConstrains are set is in device pixel sizes as it describes
-// max texture / window size in pixels.
void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
- mSizeConstraints = aConstraints;
- SetSafeWindowSize(mSizeConstraints.mMinSize);
- SetSafeWindowSize(mSizeConstraints.mMaxSize);
+ mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
+ mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
// Store constraints as inner sizes rather than outer sizes.
if (SizeMode() == nsSizeMode_Normal) {
- auto margin = ToLayoutDevicePixels(mClientMargin);
if (mSizeConstraints.mMinSize.height) {
- mSizeConstraints.mMinSize.height -= margin.TopBottom();
+ mSizeConstraints.mMinSize.height -= mClientMargin.TopBottom();
}
if (mSizeConstraints.mMinSize.width) {
- mSizeConstraints.mMinSize.width -= margin.LeftRight();
+ mSizeConstraints.mMinSize.width -= mClientMargin.LeftRight();
}
if (mSizeConstraints.mMaxSize.height != NS_MAXSIZE) {
- mSizeConstraints.mMaxSize.height -= margin.TopBottom();
+ mSizeConstraints.mMaxSize.height -= mClientMargin.TopBottom();
}
if (mSizeConstraints.mMaxSize.width != NS_MAXSIZE) {
- mSizeConstraints.mMaxSize.width -= margin.LeftRight();
+ mSizeConstraints.mMaxSize.width -= mClientMargin.LeftRight();
}
}
@@ -1003,21 +1000,19 @@ void nsWindow::ApplySizeConstraints() {
if (constraints.mMinSize != LayoutDeviceIntSize()) {
gtk_widget_set_size_request(
GTK_WIDGET(mContainer),
- DevicePixelsToGdkCoordRound(constraints.mMinSize.width),
- DevicePixelsToGdkCoordRound(constraints.mMinSize.height));
+ DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.width),
+ DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.height));
if (ToplevelUsesCSD()) {
- auto margin = ToLayoutDevicePixels(mClientMargin);
- constraints.mMinSize.height += margin.TopBottom();
- constraints.mMinSize.width += margin.LeftRight();
+ constraints.mMinSize.height += mClientMargin.TopBottom();
+ constraints.mMinSize.width += mClientMargin.LeftRight();
}
hints |= GDK_HINT_MIN_SIZE;
}
if (mSizeConstraints.mMaxSize !=
LayoutDeviceIntSize(NS_MAXSIZE, NS_MAXSIZE)) {
if (ToplevelUsesCSD()) {
- auto margin = ToLayoutDevicePixels(mClientMargin);
- constraints.mMaxSize.height += margin.TopBottom();
- constraints.mMaxSize.width += margin.LeftRight();
+ constraints.mMaxSize.height += mClientMargin.TopBottom();
+ constraints.mMaxSize.width += mClientMargin.LeftRight();
}
hints |= GDK_HINT_MAX_SIZE;
}
@@ -1025,10 +1020,11 @@ void nsWindow::ApplySizeConstraints() {
// Constraints for the shell are outer sizes, but with SSD we need to use
// inner sizes.
GdkGeometry geometry{
- .min_width = DevicePixelsToGdkCoordRound(constraints.mMinSize.width),
- .min_height = DevicePixelsToGdkCoordRound(constraints.mMinSize.height),
- .max_width = DevicePixelsToGdkCoordRound(constraints.mMaxSize.width),
- .max_height = DevicePixelsToGdkCoordRound(constraints.mMaxSize.height),
+ .min_width = DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.width),
+ .min_height = DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.height),
+ .max_width = DevicePixelsToGdkCoordRoundDown(constraints.mMaxSize.width),
+ .max_height =
+ DevicePixelsToGdkCoordRoundDown(constraints.mMaxSize.height),
};
if (mAspectRatio != 0.0f && !mAspectResizer) {
@@ -1076,58 +1072,33 @@ void nsWindow::Show(bool aState) {
RefreshWindowClass();
}
-LayoutDeviceIntPoint nsWindow::ToLayoutDevicePixels(
- const DesktopIntPoint& aPoint) {
- return LayoutDeviceIntPoint::Round(aPoint * GetDesktopToDeviceScale());
-}
-
-LayoutDeviceIntSize nsWindow::ToLayoutDevicePixels(
- const DesktopIntSize& aSize) {
- return LayoutDeviceIntSize::Round(aSize * GetDesktopToDeviceScale());
-}
-
-LayoutDeviceIntRect nsWindow::ToLayoutDevicePixels(
- const DesktopIntRect& aRect) {
- return LayoutDeviceIntRect::Round(aRect * GetDesktopToDeviceScale());
-}
-
-LayoutDeviceIntMargin nsWindow::ToLayoutDevicePixels(
- const DesktopIntMargin& aMargin) {
- return (aMargin * GetDesktopToDeviceScale()).Rounded();
-}
-
-DesktopIntPoint nsWindow::ToDesktopPixels(const LayoutDeviceIntPoint& aPoint) {
- return DesktopIntPoint::Round(aPoint / GetDesktopToDeviceScale());
-}
-
-DesktopIntSize nsWindow::ToDesktopPixels(const LayoutDeviceIntSize& aSize) {
- return DesktopIntSize::Round(aSize / GetDesktopToDeviceScale());
-}
-
-DesktopIntRect nsWindow::ToDesktopPixels(const LayoutDeviceIntRect& aRect) {
- return DesktopIntRect::Round(aRect / GetDesktopToDeviceScale());
-}
-
-void nsWindow::ResizeInt(const Maybe<DesktopIntPoint>& aMove,
- DesktopIntSize aSize) {
+void nsWindow::ResizeInt(const Maybe<LayoutDeviceIntPoint>& aMove,
+ LayoutDeviceIntSize aSize) {
LOG("nsWindow::ResizeInt w:%d h:%d\n", aSize.width, aSize.height);
-
const bool moved =
- aMove && (*aMove != mLastMoveRequest || mClientArea.TopLeft() != *aMove);
+ aMove && (*aMove != mLastMoveRequest || mBounds.TopLeft() != *aMove);
if (moved) {
LOG(" with move to left:%d top:%d", aMove->x.value, aMove->y.value);
mLastMoveRequest = *aMove;
}
- const bool resized = aSize != mLastSizeRequest || mClientArea.Size() != aSize;
+ ConstrainSize(&aSize.width, &aSize.height);
+ LOG(" ConstrainSize: w:%d h;%d\n", aSize.width, aSize.height);
+
+ const bool resized = aSize != mLastSizeRequest || mBounds.Size() != aSize;
#if MOZ_LOGGING
- LOG(" resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] "
- "mClientArea [%d, %d]",
+ LOG(" resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] mBounds [%d, %d]",
resized, aSize.width, aSize.height, mLastSizeRequest.width,
- mLastSizeRequest.height, mClientArea.width, mClientArea.height);
+ mLastSizeRequest.height, mBounds.width, mBounds.height);
#endif
mLastSizeRequest = aSize;
+ // Check size
+ if (mCompositorSession &&
+ !wr::WindowSizeSanityCheck(aSize.width, aSize.height)) {
+ gfxCriticalNoteOnce << "Invalid aSize in ResizeInt " << aSize
+ << " size state " << mSizeMode;
+ }
// Recalculate aspect ratio when resized from DOM
if (mAspectRatio != 0.0) {
@@ -1147,47 +1118,23 @@ void nsWindow::ResizeInt(const Maybe<DesktopIntPoint>& aMove,
}
void nsWindow::Resize(const DesktopSize& aSize, bool aRepaint) {
+ auto size = LayoutDeviceIntSize::Round(aSize * GetDesktopToDeviceScale());
LOG("nsWindow::Resize %s (scaled %s)", ToString(aSize).c_str(),
- ToString(aSize).c_str());
-
- double scale = GetDesktopToDeviceScale().scale;
- auto size = DesktopIntSize::Round(aSize);
- auto scaledSize = ToLayoutDevicePixels(size);
-
- if (ConstrainSizeWithScale(&size.width, &size.height, scale)) {
- LOG(" ConstrainSizeWithScale: w:%d h:%d coord scale %f", size.width,
- size.height, scale);
- }
- if (mCompositorSession &&
- !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) {
- gfxCriticalNoteOnce << "Invalid aSize in ResizeInt " << scaledSize
- << " size state " << mSizeMode;
- }
-
+ ToString(size).c_str());
ResizeInt(Nothing(), size);
}
void nsWindow::Resize(const DesktopRect& aRect, bool aRepaint) {
- double scale = GetDesktopToDeviceScale().scale;
- auto size = DesktopIntSize::Round(aRect.Size());
- auto topLeft = DesktopIntPoint::Round(aRect.TopLeft());
- auto scaledSize = ToLayoutDevicePixels(size);
+ auto size =
+ LayoutDeviceIntSize::Round(aRect.Size() * GetDesktopToDeviceScale());
+ auto topLeft =
+ LayoutDeviceIntPoint::Round(aRect.TopLeft() * GetDesktopToDeviceScale());
LOG("nsWindow::Resize [%.2f,%.2f] -> [%.2f x %.2f] scaled [%d,%d] -> "
- "[%d x %d] repaint %d",
+ "[%d x %d] repaint %d\n",
aRect.x, aRect.y, aRect.width, aRect.height, topLeft.x.value,
topLeft.y.value, size.width, size.height, aRepaint);
- if (ConstrainSizeWithScale(&size.width, &size.height, scale)) {
- LOG(" ConstrainSizeWithScale: w:%d h:%d coord scale %f", size.width,
- size.height, scale);
- }
- if (mCompositorSession &&
- !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) {
- gfxCriticalNoteOnce << "Invalid aSize in ResizeInt " << scaledSize
- << " size state " << mSizeMode;
- }
-
ResizeInt(Some(topLeft), size);
}
@@ -1196,30 +1143,27 @@ void nsWindow::Enable(bool aState) { mEnabled = aState; }
bool nsWindow::IsEnabled() const { return mEnabled; }
void nsWindow::Move(const DesktopPoint& aTopLeft) {
- double scale = GetDesktopToDeviceScale().scale;
- auto request = DesktopIntPoint::Round(aTopLeft);
-
- LOG("nsWindow::Move to [%d x %d] scale %f scaled [%.2f x %.2f]",
- request.x.value, request.y.value, scale, request.x.value * scale,
- request.y.value * scale);
+ auto request =
+ LayoutDeviceIntPoint::Round(aTopLeft * GetDesktopToDeviceScale());
+ LOG("nsWindow::Move to %d x %d\n", request.x.value, request.y.value);
if (mSizeMode != nsSizeMode_Normal && IsTopLevelWidget()) {
- LOG(" size state is not normal, can't move, bailing");
+ LOG(" size state is not normal, bailing");
return;
}
// Since a popup window's x/y coordinates are in relation to to
// the parent, the parent might have moved so we always move a
// popup window.
- auto pos = GetScreenBoundsUnscaled().TopLeft();
- LOG(" bounds %d x %d\n", int(pos.x), int(pos.y));
- if (pos == request && mLastMoveRequest == request &&
+ LOG(" bounds %d x %d\n", mBounds.x, mBounds.y);
+ if (mBounds.TopLeft() == request && mLastMoveRequest == request &&
mWindowType != WindowType::Popup) {
LOG(" position is the same, return\n");
return;
}
// XXX Should we do some AreBoundsSane check here?
+
mLastMoveRequest = request;
if (!mCreated) {
@@ -1624,8 +1568,10 @@ void nsWindow::WaylandPopupHierarchyCalculatePositions() {
// Anchored window has mPopupPosition already calculated against
// its parent, no need to recalculate.
LOG(" popup [%p] bounds [%d, %d] -> [%d x %d]", popup,
- (int)(popup->mClientArea.x), (int)(popup->mClientArea.y),
- (int)(popup->mClientArea.width), (int)(popup->mClientArea.height));
+ (int)(popup->mBounds.x / FractionalScaleFactor()),
+ (int)(popup->mBounds.y / FractionalScaleFactor()),
+ (int)(popup->mBounds.width / FractionalScaleFactor()),
+ (int)(popup->mBounds.height / FractionalScaleFactor()));
#ifdef MOZ_LOGGING
if (LOG_ENABLED()) {
if (nsMenuPopupFrame* popupFrame = GetPopupFrame()) {
@@ -1715,8 +1661,7 @@ GdkPoint nsWindow::WaylandGetParentPosition() {
GdkPoint topLeft = {0, 0};
nsWindow* window = GetEffectiveParent();
if (window->IsPopup()) {
- auto offset = window->WidgetToScreenOffsetUnscaled();
- topLeft = GdkPoint{offset.x, offset.y};
+ topLeft = DevicePixelsToGdkPointRoundDown(window->WidgetToScreenOffset());
}
LOG("nsWindow::WaylandGetParentPosition() [%d, %d]\n", topLeft.x, topLeft.y);
return topLeft;
@@ -2070,16 +2015,11 @@ void nsWindow::WaylandPopupPropagateChangesToLayout(bool aMove, bool aResize) {
}
}
if (aMove) {
- auto pos = ToLayoutDevicePixels(mClientArea);
- LOG(" needPositionUpdate, bounds [%d, %d]", pos.x, pos.y);
- NotifyWindowMoved(pos.x, pos.y, ByMoveToRect::Yes);
+ LOG(" needPositionUpdate, bounds [%d, %d]", mBounds.x, mBounds.y);
+ NotifyWindowMoved(mBounds.x, mBounds.y, ByMoveToRect::Yes);
}
}
-LayoutDeviceIntSize nsWindow::GetMoveToRectPopupSize() {
- return ToLayoutDevicePixels(mMoveToRectPopupSize);
-}
-
void nsWindow::NativeMoveResizeWaylandPopupCallback(
const GdkRectangle* aFinalSize, bool aFlippedX, bool aFlippedY) {
// We're getting move-to-rect callback without move-to-rect call.
@@ -2122,8 +2062,7 @@ void nsWindow::NativeMoveResizeWaylandPopupCallback(
// perfectly round-trip. Compare gdk rects to check whether size or positions
// have changed from what we'd request otherwise, in order to avoid
// flickering.
- const GdkRectangle currentGdkRect{mClientArea.x, mClientArea.y,
- mClientArea.width, mClientArea.height};
+ const GdkRectangle currentGdkRect = DevicePixelsToGdkRectRoundOut(mBounds);
auto scale = GdkCeiledScaleFactor();
auto IsSubstantiallyDifferent = [=](gint a, gint b) {
return std::abs(a - b) > scale;
@@ -2135,17 +2074,17 @@ void nsWindow::NativeMoveResizeWaylandPopupCallback(
const bool needsSizeUpdate =
IsSubstantiallyDifferent(finalGdkRect.width, currentGdkRect.width) ||
IsSubstantiallyDifferent(finalGdkRect.height, currentGdkRect.height);
- const DesktopIntRect newClientArea = DesktopIntRect(
- finalGdkRect.x, finalGdkRect.y, finalGdkRect.width, finalGdkRect.height);
- LOG(" orig gdk [%d, %d] -> [%d x %d]", currentGdkRect.x, currentGdkRect.y,
+ const LayoutDeviceIntRect newBounds =
+ MaybeRoundToDisplayPixels(GdkRectToDevicePixels(finalGdkRect));
+ LOG(" orig gdk [%d, %d] -> [%d x %d]\n", currentGdkRect.x, currentGdkRect.y,
currentGdkRect.width, currentGdkRect.height);
LOG(" new gdk [%d, %d] -> [%d x %d]\n", finalGdkRect.x, finalGdkRect.y,
finalGdkRect.width, finalGdkRect.height);
- LOG(" orig mClientArea [%d, %d] -> [%d x %d]", mClientArea.x, mClientArea.y,
- mClientArea.width, mClientArea.height);
- LOG(" new mClientArea [%d, %d] -> [%d x %d]", newClientArea.x,
- newClientArea.y, newClientArea.width, newClientArea.height);
+ LOG(" orig mBounds [%d, %d] -> [%d x %d]\n", mBounds.x, mBounds.y,
+ mBounds.width, mBounds.height);
+ LOG(" new mBounds [%d, %d] -> [%d x %d]", newBounds.x, newBounds.y,
+ newBounds.width, newBounds.height);
if (!needsSizeUpdate && !needsPositionUpdate) {
return;
@@ -2154,27 +2093,24 @@ void nsWindow::NativeMoveResizeWaylandPopupCallback(
// Wayland compositor changed popup size request from layout.
// Set the constraints to use them in nsMenuPopupFrame::SetPopupPosition().
// Beware that gtk_window_resize() requests sizes asynchronously and so
- // newClientArea might not have the size from the most recent
+ // newBounds might not have the size from the most recent
// gtk_window_resize().
- if (mClientArea.width < mLastSizeRequest.width) {
- mMoveToRectPopupSize.width = newClientArea.width;
+ if (newBounds.width < mLastSizeRequest.width) {
+ mMoveToRectPopupSize.width = newBounds.width;
}
- if (mClientArea.height < mLastSizeRequest.height) {
- mMoveToRectPopupSize.height = newClientArea.height;
+ if (newBounds.height < mLastSizeRequest.height) {
+ mMoveToRectPopupSize.height = newBounds.height;
}
LOG(" mMoveToRectPopupSize set to [%d, %d]", mMoveToRectPopupSize.width,
mMoveToRectPopupSize.height);
}
-
- mClientArea = newClientArea;
- mLastSizeRequest = newClientArea.Size();
- mLastMoveRequest = newClientArea.TopLeft();
-
- // Check mClientArea size
- auto scaledSize = ToLayoutDevicePixels(mClientArea);
+ mBounds = newBounds;
+ mLastSizeRequest = newBounds.Size();
+ mLastMoveRequest = newBounds.TopLeft();
+ // Check mBounds size
if (mCompositorSession &&
- !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) {
- gfxCriticalNoteOnce << "Invalid mClientArea in PopupCallback " << scaledSize
+ !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
+ gfxCriticalNoteOnce << "Invalid mBounds in PopupCallback " << mBounds
<< " size state " << mSizeMode;
}
WaylandPopupPropagateChangesToLayout(needsPositionUpdate, needsSizeUpdate);
@@ -2215,15 +2151,14 @@ bool nsWindow::IsPopupDirectionRTL() {
// It's used when we position noautihode popup and we don't use xdg_positioner.
// See Bug 1718867
void nsWindow::WaylandPopupSetDirectPosition() {
- GdkRectangle rect{mLastMoveRequest.x, mLastMoveRequest.y,
- mLastSizeRequest.width, mLastSizeRequest.height};
+ const LayoutDeviceIntRect frameRect(mLastMoveRequest, mLastSizeRequest);
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(frameRect);
LOG("nsWindow::WaylandPopupSetDirectPosition %d,%d -> %d x %d\n", rect.x,
rect.y, rect.width, rect.height);
mPopupPosition = {rect.x, rect.y};
- mClientArea.MoveTo(mLastMoveRequest);
- mClientArea.SizeTo(mLastSizeRequest);
+ mBounds = frameRect;
if (mIsDragPopup) {
gtk_window_move(GTK_WINDOW(mShell), rect.x, rect.y);
@@ -2270,8 +2205,8 @@ void nsWindow::WaylandPopupSetDirectPosition() {
gtk_window_resize(GTK_WINDOW(mShell), rect.width, rect.height);
if (mPopupPosition.x != rect.x) {
- mClientArea.MoveTo(mPopupPosition.x, mPopupPosition.y);
- LOG(" setting new client area [%d, %d]\n", mClientArea.x, mClientArea.y);
+ mBounds.MoveTo(GdkPointToDevicePixels(mPopupPosition));
+ LOG(" setting new bounds [%d, %d]\n", mBounds.x, mBounds.y);
WaylandPopupPropagateChangesToLayout(/* move */ true, /* resize */ false);
}
}
@@ -2293,8 +2228,8 @@ bool nsWindow::WaylandPopupFitsToplevelWindow() {
int parentHeight = gdk_window_get_height(toplevelGdkWindow);
LOG(" parent size %d x %d", parentWidth, parentHeight);
- GdkRectangle requestedRect{mLastMoveRequest.x, mLastMoveRequest.y,
- mLastSizeRequest.width, mLastSizeRequest.height};
+ GdkRectangle requestedRect = DevicePixelsToGdkRectRoundOut(
+ LayoutDeviceIntRect(mLastMoveRequest, mLastSizeRequest));
LOG(" popup topleft %d, %d size %d x %d", requestedRect.x, requestedRect.y,
requestedRect.width, requestedRect.height);
bool fits = requestedRect.x >= 0 && requestedRect.y >= 0 &&
@@ -2305,10 +2240,10 @@ bool nsWindow::WaylandPopupFitsToplevelWindow() {
}
void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) {
- GdkRectangle rect{mLastMoveRequest.x, mLastMoveRequest.y,
- mLastSizeRequest.width, mLastSizeRequest.height};
+ const LayoutDeviceIntRect frameRect(mLastMoveRequest, mLastSizeRequest);
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(frameRect);
- LOG("nsWindow::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move %d "
+ LOG("nsWindow::NativeMoveResizeWaylandPopup Bounds %d,%d -> %d x %d move %d "
"resize %d\n",
rect.x, rect.y, rect.width, rect.height, aMove, aResize);
@@ -2320,24 +2255,10 @@ void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) {
return;
}
- // We expect all Wayland popus have zero margin. If not, just position
- // it as is and throw an error message.
- if (!mClientMargin.IsAllZero()) {
- gfxCriticalNoteOnce << "Invalid non-zero margin for WaylandPopup!";
- if (aMove) {
- gtk_window_move(GTK_WINDOW(mShell), mLastMoveRequest.x,
- mLastMoveRequest.y);
- }
- if (aResize) {
- gtk_window_resize(GTK_WINDOW(mShell), mLastSizeRequest.width,
- mLastSizeRequest.height);
- }
- }
-
if (mWaitingForMoveToRectCallback) {
LOG(" waiting for move to rect, scheduling");
- // mClientArea position must not be overwritten before it is applied.
- // OnShellConfigureEvent() will not set mClientArea to an old position for
+ // mBounds position must not be overwritten before it is applied.
+ // OnShellConfigureEvent() will not set mBounds to an old position for
// GTK_WINDOW_POPUP.
MOZ_ASSERT(gtk_window_get_window_type(GTK_WINDOW(mShell)) ==
GTK_WINDOW_POPUP);
@@ -2383,8 +2304,7 @@ void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) {
LOG(" popup position changed from [%d, %d] to [%d, %d]\n", mPopupPosition.x,
mPopupPosition.y, rect.x, rect.y);
mPopupPosition = {rect.x, rect.y};
- mClientArea.MoveTo(mLastMoveRequest);
- mClientArea.SizeTo(mLastSizeRequest);
+ mBounds = frameRect;
UpdateWaylandPopupHierarchy();
}
@@ -2698,18 +2618,15 @@ bool nsWindow::WaylandPopupCheckAndGetAnchor(GdkRectangle* aPopupAnchor,
// Update popup layout coordinates from layout by recent popup hierarchy
// (calculate correct position according to parent window)
// and convert to Gtk coordinates.
- DesktopIntRect anchorRect =
- ToDesktopPixels(mPopupMoveToRectParams.mAnchorRect);
+ LayoutDeviceIntRect anchorRect = mPopupMoveToRectParams.mAnchorRect;
if (!WaylandPopupIsFirst()) {
GdkPoint parent = WaylandGetParentPosition();
LOG(" subtract parent position from anchor [%d, %d]\n", parent.x,
parent.y);
- anchorRect.x -= parent.x;
- anchorRect.y -= parent.y;
+ anchorRect.MoveBy(-GdkPointToDevicePixels(parent));
}
- *aPopupAnchor = GdkRectangle{anchorRect.x, anchorRect.y, anchorRect.width,
- anchorRect.height};
+ *aPopupAnchor = DevicePixelsToGdkRectRoundOut(anchorRect);
LOG(" anchored to rectangle [%d, %d] -> [%d x %d]", aPopupAnchor->x,
aPopupAnchor->y, aPopupAnchor->width, aPopupAnchor->height);
@@ -3266,32 +3183,16 @@ void nsWindow::SetFocus(Raise aRaise, mozilla::dom::CallerType aCallerType) {
LOG(" widget now has focus in SetFocus()");
}
-DesktopIntRect nsWindow::GetScreenBoundsUnscaled() {
- DesktopIntRect bounds = mClientArea;
- bounds.Inflate(mClientMargin);
- return bounds;
-}
-
-LayoutDeviceIntRect nsWindow::GetScreenBounds() {
- return ToLayoutDevicePixels(GetScreenBoundsUnscaled());
-}
-
-LayoutDeviceIntRect nsWindow::GetBounds() {
- return ToLayoutDevicePixels(GetScreenBoundsUnscaled());
-}
+LayoutDeviceIntRect nsWindow::GetScreenBounds() { return mBounds; }
LayoutDeviceIntSize nsWindow::GetClientSize() {
- return ToLayoutDevicePixels(mClientArea).Size();
+ return GetClientBounds().Size();
}
LayoutDeviceIntRect nsWindow::GetClientBounds() {
- return ToLayoutDevicePixels(mClientArea);
-}
-
-LayoutDeviceIntPoint nsWindow::GetClientOffset() {
- auto scale = FractionalScaleFactor();
- return LayoutDeviceIntPoint(int(round(mClientMargin.left * scale)),
- int(round(mClientMargin.top * scale)));
+ LayoutDeviceIntRect rect = GetBounds();
+ rect.Deflate(mClientMargin);
+ return rect;
}
nsresult nsWindow::GetRestoredBounds(LayoutDeviceIntRect& aRect) {
@@ -3304,13 +3205,12 @@ nsresult nsWindow::GetRestoredBounds(LayoutDeviceIntRect& aRect) {
// though it's a bit unfortunate.
aRect = GetScreenBounds();
aRect.SizeTo(GetClientSize());
- LOG("nsWindow::GetRestoredBounds() %s", ToString(aRect).c_str());
return NS_OK;
}
LayoutDeviceIntMargin nsWindow::NormalSizeModeClientToWindowMargin() {
if (SizeMode() == nsSizeMode_Normal) {
- return ToLayoutDevicePixels(mClientMargin);
+ return mClientMargin;
}
// TODO(emilio): When not using CSD decorations or not in the normal
// sizemode, we can't know the size of the titlebar and window borders before
@@ -3331,109 +3231,85 @@ LayoutDeviceIntCoord GetXWindowBorder(GdkWindow* aWin) {
}
#endif
-/*
- Window bounds are computed differently on X11, X11 CSD and Wayland CSD.
- Let's say a non-maximized toplevel window is visible at 100,100:
-
- X11 (titlebar height is 40, decoration size 0):
- Frame bounds: contains window position which includes window
- decoration and system titlebar (100, 60)
- Toplevel bounds: contains window position without tilebar (100,100)
- mGdkWindow position: 0,0 (located at toplevel origin)
-
- X11 CSD (without system titlebar, CSD size is 40,40):
- Frame bounds: contains window position which includes CSD
- decorations (60,60).
- Toplevel bounds: same as frame bounds.
- mGdkWindow position: Relative position to toplevel decoration left
- top corner, so matches CSD size - (40,40).
-
- Wayland CSD (with system titlebar, CSD size is 40,40, titlebar height 50):
- Frame bounds: zero as Wayland doesn't report window position (0,0)
- Toplevel bounds: same as frame bounds.
- mGdkWindow position: Relative position to toplevel decoration left
- top corner, so matches CSD + titlebar size - (40, 90).
-
- Wayland CSD (without system titlebar, CSD size is 40,40):
- Frame bounds: zero as Wayland doesn't report window position (0,0)
- Toplevel bounds: same as frame bounds.
- mGdkWindow position: Relative position to toplevel decoration left
- top corner, so matches CSD size - (40,40).
-*/
-#ifdef MOZ_X11
-void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
- LOG("RecomputeBoundsX11(%d)", aMayChangeCsdMargin);
+void nsWindow::RecomputeBounds(MayChangeCsdMargin aMayChangeCsdMargin) {
+ const bool mayChangeCsdMargin =
+ aMayChangeCsdMargin == MayChangeCsdMargin::Yes;
+ LOG("RecomputeBounds(%d)", mayChangeCsdMargin);
+ mPendingBoundsChange = false;
+ mPendingBoundsChangeMayChangeCsdMargin = false;
auto* toplevel = GetToplevelGdkWindow();
+ if (!toplevel || mIsDestroyed) {
+ return;
+ }
- // Window position and size with window decoration AND system titlebar.
- auto GetFrameTitlebarBounds = [&](GdkWindow* aWin) {
+ auto GetFrameBounds = [&](GdkWindow* aWin) {
GdkRectangle b{0};
gdk_window_get_frame_extents(aWin, &b);
- if (gtk_check_version(3, 24, 35) &&
+#ifdef MOZ_X11
+ const bool isX11 = GdkIsX11Display();
+ if (isX11 && gtk_check_version(3, 24, 35) &&
gdk_window_get_window_type(aWin) == GDK_WINDOW_TEMP) {
// Workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4820
// Bug 1775017 Gtk < 3.24.35 returns scaled values for
// override redirected window on X11.
- double scale = FractionalScaleFactor();
- return DesktopIntRect(int(round(b.x / scale)), int(round(b.y / scale)),
- int(round(b.width / scale)),
- int(round(b.height / scale)));
+ return LayoutDeviceRect(b.x, b.y, b.width, b.height);
}
- auto result = DesktopIntRect(b.x, b.y, b.width, b.height);
- if (gtk_check_version(3, 24, 50)) {
+#endif
+ auto result = GdkRectToFloatDevicePixels(b);
+#ifdef MOZ_X11
+ if (isX11 && gtk_check_version(3, 24, 50)) {
if (auto border = GetXWindowBorder(aWin)) {
// Workaround for
// https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/8423
// Bug 1958174 Gtk doesn't account for window border sizes on X11.
- double scale = FractionalScaleFactor();
- result.width += 2 * border / scale;
- result.height += 2 * border / scale;
+ result.width += 2 * border;
+ result.height += 2 * border;
}
}
+#endif
return result;
};
- // Window position and size with decoration byt WITHOUT system titlebar.
auto GetBounds = [&](GdkWindow* aWin) {
GdkRectangle b{0};
- if (IsTopLevelWidget() && aWin == toplevel) {
+ if (IsTopLevelWidget() && GdkIsX11Display() && aWin == toplevel) {
// We want the up-to-date size from the X server, not the last configure
// event size, to avoid spurious resizes on e.g. sizemode changes.
gdk_window_get_geometry(aWin, nullptr, nullptr, &b.width, &b.height);
gdk_window_get_origin(aWin, &b.x, &b.y);
- return DesktopIntRect(b.x, b.y, b.width, b.height);
+ return GdkRectToFloatDevicePixels(b);
}
gdk_window_get_position(aWin, &b.x, &b.y);
b.width = gdk_window_get_width(aWin);
b.height = gdk_window_get_height(aWin);
- return DesktopIntRect(b.x, b.y, b.width, b.height);
+ return GdkRectToFloatDevicePixels(b);
};
- const auto toplevelBoundsWithTitlebar = GetFrameTitlebarBounds(toplevel);
+ const auto oldBounds = mBounds;
+ const auto oldMargin = mClientMargin;
+ const auto frameBounds = GetFrameBounds(toplevel);
+ const bool decorated =
+ IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated;
const auto toplevelBounds = GetBounds(toplevel);
- // Unscaled bounds include decorations and titlebar (X11)
- DesktopIntRect finalBounds = [&] {
- auto bounds = toplevelBoundsWithTitlebar;
- // The toplevelBoundsWithTitlebar should always really be as wide as the
- // toplevel bounds, but when opening multiple windows in quick succession on
- // X11 they might not (see bug 1988787). This prevents having a really small
- // window in such case.
+ mBounds = [&] {
+ auto bounds = frameBounds;
+ // The frameBounds should always really be as wide as the toplevel bounds,
+ // but when opening multiple windows in quick succession on X11 they might
+ // not (see bug 1988787). This prevents having a really small window in such
+ // case.
bounds.width = std::max(bounds.width, toplevelBounds.width);
bounds.height = std::max(bounds.height, toplevelBounds.height);
- return bounds;
+ return LayoutDeviceIntRect::Round(bounds);
}();
- const bool decorated =
- IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated;
if (!decorated) {
mClientMargin = {};
- } else if (aMayChangeCsdMargin) {
- // TODO: Do we really need so complex margin calculation on X11?
- const DesktopIntRect clientRectRelativeToFrame = [&] {
+ } else if (mayChangeCsdMargin) {
+ const auto clientRectRelativeToFrame = [&] {
auto topLevelBoundsRelativeToFrame = toplevelBounds;
- topLevelBoundsRelativeToFrame -= toplevelBoundsWithTitlebar.TopLeft();
+ topLevelBoundsRelativeToFrame -= frameBounds.TopLeft();
if (!mGdkWindow) {
return topLevelBoundsRelativeToFrame;
}
@@ -3447,115 +3323,45 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
return gdkWindowBounds + topLevelBoundsRelativeToFrame.TopLeft();
}();
- mClientMargin = DesktopIntRect(DesktopIntPoint(), finalBounds.Size()) -
- clientRectRelativeToFrame;
- mClientMargin.EnsureAtLeast(DesktopIntMargin());
- } else {
- // Assume the client margin remains the same.
- }
-
- mClientArea = finalBounds;
- mClientArea.Deflate(mClientMargin);
-}
-#endif
-#ifdef MOZ_WAYLAND
-void nsWindow::RecomputeBoundsWayland(bool aMayChangeCsdMargin) {
- LOG("RecomputeBoundsWayland(%d)", aMayChangeCsdMargin);
-
- auto GetBounds = [&](GdkWindow* aWin) {
- GdkRectangle b{0};
- gdk_window_get_position(aWin, &b.x, &b.y);
- b.width = gdk_window_get_width(aWin);
- b.height = gdk_window_get_height(aWin);
- return DesktopIntRect(b.x, b.y, b.width, b.height);
- };
-
- const auto toplevelBounds = GetBounds(GetToplevelGdkWindow());
-
- mClientArea = GetBounds(mGdkWindow);
- if (mClientArea.X() < 0 || mClientArea.Y() < 0 || mClientArea.Width() <= 1 ||
- mClientArea.Height() <= 1) {
- // If we don't have gdkwindow bounds, assume we take the whole toplevel.
- mClientArea = toplevelBounds;
- }
-
- const bool decorated =
- IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated;
- if (!decorated) {
- mClientMargin = {};
- } else if (aMayChangeCsdMargin) {
+ // This is a bit tricky. For fractional scaling, we want the size and
+ // position to be rounded independently, to match the compositor scale,
+ // which is not the behavior of LayoutDeviceIntRect::Round (which rounds the
+ // edges instead). See bug 1849092.
+ const LayoutDeviceIntRect roundedClientRect(
+ LayoutDeviceIntPoint::Round(clientRectRelativeToFrame.TopLeft()),
+ LayoutDeviceIntSize::Round(clientRectRelativeToFrame.Size()));
mClientMargin =
- DesktopIntRect(DesktopIntPoint(), toplevelBounds.Size()) - mClientArea;
- mClientMargin.EnsureAtLeast(DesktopIntMargin());
+ LayoutDeviceIntRect(LayoutDeviceIntPoint(), mBounds.Size()) -
+ roundedClientRect;
+ mClientMargin.EnsureAtLeast(LayoutDeviceIntMargin());
} else {
// Assume the client margin remains the same.
}
-}
-#endif
-
-void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) {
- LOG("RecomputeBounds() margin %d scale change %d", aMayChangeCsdMargin,
- aScaleChange);
-
- mPendingBoundsChange = false;
- mPendingBoundsChangeMayChangeCsdMargin = false;
-
- auto* toplevel = GetToplevelGdkWindow();
- if (!toplevel || mIsDestroyed) {
- return;
- }
-
- const auto oldClientArea = mClientArea;
- const auto oldMargin = mClientMargin;
-
-#ifdef MOZ_X11
- if (GdkIsX11Display()) {
- RecomputeBoundsX11(aMayChangeCsdMargin);
- }
-#endif
-#ifdef MOZ_WAYLAND
- if (GdkIsWaylandDisplay()) {
- RecomputeBoundsWayland(aMayChangeCsdMargin);
- }
-#endif
-
-#ifdef MOZ_LOGGING
- if (LOG_ENABLED()) {
- if (mHasReceivedSizeAllocate) {
- if (!(mClientArea == mReceivedClientArea)) {
- LOG("Received and calculated client areas are different! received %s "
- "calculated %s",
- ToString(mReceivedClientArea).c_str(),
- ToString(mClientArea).c_str());
- }
- }
- }
-#endif
if (IsPopup()) {
- // Popup windows is not moved by the window manager, and so any change in
+ // Popup windows not be moved by the window manager, and so any change in
// position is a result of our direction.
//
- // mClientArea has already been set in Move() or Resize(), and that is more
+ // mBounds has already been set in Move() or Resize(), and that is more
// up-to-date than the position in the ConfigureNotify event if the event
// is from an earlier window move.
//
- // NOTE(emilio): If we remove the early mClientArea change in Move() /
+ // NOTE(emilio): If we remove the early mBounds change in Move() /
// Resize(), we should be able to remove this special case (but some tests
// would need to be adjusted to deal with the async popup moves).
- MOZ_ASSERT(mLastMoveRequest == oldClientArea.TopLeft());
- mClientArea.MoveTo(oldClientArea.TopLeft());
+ MOZ_ASSERT(mLastMoveRequest == oldBounds.TopLeft());
+ mBounds.MoveTo(oldBounds.TopLeft());
}
// Sometimes the window manager gives us garbage sizes (way past the maximum
// texture size) causing crashes if we don't enforce sane sizes here.
- auto size = mClientArea.Size();
- if (SetSafeWindowSize(size)) {
- mClientArea.SizeTo(size);
- }
+ auto unconstrainedBounds = mBounds;
+ mBounds.SizeTo(GetSafeWindowSize(mBounds.Size()));
- LOG("client area old: %s new -> %s", ToString(oldClientArea).c_str(),
- ToString(mClientArea).c_str());
+ LOG("bounds old: %s new -> %s (%s unconstrained, frame = %s, toplevel = %s)",
+ ToString(oldBounds).c_str(), ToString(mBounds).c_str(),
+ ToString(unconstrainedBounds).c_str(), ToString(frameBounds).c_str(),
+ ToString(toplevelBounds).c_str());
LOG("margin old: %s new -> %s", ToString(oldMargin).c_str(),
ToString(mClientMargin).c_str());
@@ -3570,10 +3376,10 @@ void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) {
// We need to send WindowMoved even if only the client margins changed
// so that BrowserParent picks up the new offsets.
- const bool moved = aScaleChange || aMayChangeCsdMargin ||
- oldClientArea.TopLeft() != mClientArea.TopLeft();
- const bool resized = aScaleChange || aMayChangeCsdMargin ||
- oldClientArea.Size() != mClientArea.Size();
+ const bool moved =
+ clientMarginsChanged || oldBounds.TopLeft() != mBounds.TopLeft();
+ const bool resized =
+ clientMarginsChanged || oldBounds.Size() != mBounds.Size();
if (moved) {
if (IsTopLevelWidget()) {
@@ -3581,8 +3387,7 @@ void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) {
// from Cygwin/X (bug 672103).
RollupAllMenus();
}
- auto pos = ToLayoutDevicePixels(mClientArea.TopLeft());
- NotifyWindowMoved(pos.x, pos.y);
+ NotifyWindowMoved(mBounds.x, mBounds.y);
}
if (resized) {
DispatchResized();
@@ -3880,11 +3685,7 @@ void nsWindow::SetIcon(const nsAString& aIconSpec) {
}
LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
- return ToLayoutDevicePixels(mClientArea.TopLeft());
-}
-
-DesktopIntPoint nsWindow::WidgetToScreenOffsetUnscaled() {
- return DesktopIntPoint(mClientArea.x, mClientArea.y);
+ return mBounds.TopLeft() + GetClientOffset();
}
void nsWindow::CaptureRollupEvents(bool aDoCapture) {
@@ -4321,20 +4122,20 @@ gboolean nsWindow::OnShellConfigureEvent(GdkEventConfigure* aEvent) {
}
void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) {
- LOG("nsWindow::OnContainerSizeAllocate [%d,%d] -> [%d x %d] scaled [%.2f] "
- "[%.2f x %.2f]",
+ LOG("nsWindow::OnContainerSizeAllocate [%d,%d] -> [%d x %d] scaled[%.2f] "
+ "[%.2f x "
+ "%.2f]",
aAllocation->x, aAllocation->y, aAllocation->width, aAllocation->height,
FractionalScaleFactor(), aAllocation->width * FractionalScaleFactor(),
aAllocation->height * FractionalScaleFactor());
mHasReceivedSizeAllocate = true;
- mReceivedClientArea = DesktopIntRect(aAllocation->x, aAllocation->y,
- aAllocation->width, aAllocation->height);
-
if (!mGdkWindow) {
return;
}
+ auto oldClientBounds = GetClientBounds();
+
// Bounds will get updated on the main configure.
// Gecko permits running nested event loops during processing of events,
// GtkWindow callers of gtk_widget_size_allocate expect the signal handlers
@@ -4347,19 +4148,21 @@ void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) {
// Invalidate the new part of the window now for the pending paint to
// minimize background flashes (GDK does not do this for external
// renewClientSizes of toplevels.)
- if (mClientArea.Size() == mReceivedClientArea.Size()) {
+ LayoutDeviceIntRect newClientBounds = GdkRectToDevicePixels(*aAllocation);
+ if (oldClientBounds.Size() == newClientBounds.Size()) {
return;
}
- if (mClientArea.width < mReceivedClientArea.width) {
- GdkRectangle rect{mClientArea.width, 0,
- mReceivedClientArea.width - mClientArea.width,
- mReceivedClientArea.height};
+ if (oldClientBounds.width < newClientBounds.width) {
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect(
+ oldClientBounds.width, 0, newClientBounds.width - oldClientBounds.width,
+ newClientBounds.height));
gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
}
- if (mClientArea.height < mReceivedClientArea.height) {
- GdkRectangle rect{0, mClientArea.height, mReceivedClientArea.width,
- mReceivedClientArea.height - mClientArea.height};
+ if (oldClientBounds.height < newClientBounds.height) {
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
+ LayoutDeviceIntRect(0, oldClientBounds.height, newClientBounds.width,
+ newClientBounds.height - oldClientBounds.height));
gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
}
}
@@ -4378,7 +4181,7 @@ void nsWindow::SchedulePendingBounds(MayChangeCsdMargin aMayChangeCsdMargin) {
void nsWindow::MaybeRecomputeBounds() {
LOG("MaybeRecomputeBounds %d", mPendingBoundsChange);
if (mPendingBoundsChange) {
- RecomputeBounds(mPendingBoundsChangeMayChangeCsdMargin);
+ RecomputeBounds(MayChangeCsdMargin(mPendingBoundsChangeMayChangeCsdMargin));
}
}
@@ -4517,11 +4320,10 @@ Maybe<GdkWindowEdge> nsWindow::CheckResizerEdge(
const int resizerHeight = 15 * GdkCeiledScaleFactor();
const int resizerWidth = resizerHeight * 4;
- auto bounds = GetScreenBounds();
const int topDist = aPoint.y;
const int leftDist = aPoint.x;
- const int rightDist = bounds.width - aPoint.x;
- const int bottomDist = bounds.height - aPoint.y;
+ const int rightDist = mBounds.width - aPoint.x;
+ const int bottomDist = mBounds.height - aPoint.y;
// We can't emulate resize of North/West edges on Wayland as we can't shift
// toplevel window.
@@ -4588,7 +4390,7 @@ void nsWindow::EmulateResizeDrag(GdkEventMotion* aEvent) {
auto oldPoint = mLastResizePoint;
mLastResizePoint = newPoint;
- auto size = GetScreenBoundsUnscaled().Size();
+ GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
size.width += newPoint.x - oldPoint.x;
size.height += newPoint.y - oldPoint.y;
@@ -5682,7 +5484,7 @@ void nsWindow::OnWindowStateEvent(GtkWidget* aWidget,
}();
if (mSizeMode != oldSizeMode || mIsTiled != oldIsTiled) {
- RecomputeBounds(/* MayChangeCsdMargin */ false);
+ RecomputeBounds(MayChangeCsdMargin::No);
}
if (mSizeMode != oldSizeMode) {
if (mWidgetListener) {
@@ -5778,7 +5580,7 @@ void nsWindow::RefreshScale(bool aRefreshScreen, bool aForceRefresh) {
return;
}
- RecomputeBounds(/* MayChangeCsdMargin */ true, /* ScaleChanged*/ true);
+ RecomputeBounds(MayChangeCsdMargin::Yes);
if (mWidgetListener) {
if (PresShell* presShell = mWidgetListener->GetPresShell()) {
@@ -6264,6 +6066,7 @@ void nsWindow::ConfigureCompositor() {
nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
const widget::InitData& aInitData) {
MOZ_DIAGNOSTIC_ASSERT(aInitData.mWindowType != WindowType::Invisible);
+
#ifdef ACCESSIBILITY
// Send a DBus message to check whether a11y is enabled
a11y::PreInit();
@@ -6286,14 +6089,13 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
LOG("nsWindow::Create()");
// save our bounds
- LOG(" mBounds: x:%d y:%d w:%d h:%d\n", aRect.x, aRect.y, aRect.width,
- aRect.height);
+ mBounds = aRect;
+ LOG(" mBounds: x:%d y:%d w:%d h:%d\n", mBounds.x, mBounds.y, mBounds.width,
+ mBounds.height);
- mClientArea = ToDesktopPixels(aRect);
- ConstrainSizeWithScale(&mClientArea.width, &mClientArea.height,
- GetDesktopToDeviceScale().scale);
- mLastSizeRequest = mClientArea.Size();
- mLastMoveRequest = mClientArea.TopLeft();
+ ConstrainSize(&mBounds.width, &mBounds.height);
+ mLastSizeRequest = mBounds.Size();
+ mLastMoveRequest = mBounds.TopLeft();
const bool popupNeedsAlphaVisual =
mWindowType == WindowType::Popup &&
@@ -6304,6 +6106,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
LOG(" parent window [%p]", parentnsWindow);
MOZ_ASSERT_IF(mWindowType == WindowType::Popup, parentnsWindow);
+
if (mWindowType != WindowType::Dialog && mWindowType != WindowType::Popup &&
mWindowType != WindowType::TopLevel) {
MOZ_ASSERT_UNREACHABLE("Unexpected eWindowType");
@@ -6383,10 +6186,10 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
// actually placed the window somewhere. If no placement has taken
// place, we just let the window manager Do The Right Thing.
if (AreBoundsSane()) {
- LOG(" nsWindow::Create() Initial resize to %d x %d\n", mClientArea.width,
- mClientArea.height);
- gtk_window_resize(GTK_WINDOW(mShell), mClientArea.width,
- mClientArea.height);
+ GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
+ LOG(" nsWindow::Create() Initial resize to %d x %d\n", size.width,
+ size.height);
+ gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
}
if (mIsPIPWindow) {
LOG(" Is PIP window\n");
@@ -6455,7 +6258,8 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
if (GdkIsX11Display()) {
NativeMoveResize(/* move */ true, /* resize */ false);
} else if (AreBoundsSane()) {
- mPopupPosition = {mClientArea.x, mClientArea.y};
+ GdkRectangle rect = DevicePixelsToGdkRectRoundOut(mBounds);
+ mPopupPosition = {rect.x, rect.y};
}
} else { // must be WindowType::TopLevel
mGtkWindowRoleName = "Toplevel";
@@ -6480,7 +6284,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
mSurface = new WaylandSurface(
parentnsWindow ? MOZ_WL_SURFACE(parentnsWindow->GetMozContainer())
: nullptr,
- gfx::IntSize(ToLayoutDevicePixels(mLastSizeRequest).ToUnknownSize()));
+ gfx::IntSize(mLastSizeRequest.width, mLastSizeRequest.height));
}
container = moz_container_new(this, mSurface);
#else
@@ -6815,28 +6619,21 @@ nsAutoCString nsWindow::GetDebugTag() const {
}
void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
- const DesktopIntRect frameRect(mLastMoveRequest, mLastSizeRequest);
-
- // Window size is calculated without decorations, Gtk adds decorations
- // size to our request at gtk_window_resize().
+ const LayoutDeviceIntRect frameRect(mLastMoveRequest, mLastSizeRequest);
GdkRectangle moveResizeRect = [&] {
auto cr = frameRect;
- // In CSD mode gtk_window_move() / gtk_window_resize() expects coordinates
- // without CSD frame so remove it.
cr.Deflate(mClientMargin);
- // SSD mode expects coordinates with decorations (outer frame)
- // so put the margin offset back.
+ // gtk_window_move will undo the csd offset properly on its own, but
+ // nothing else, so do it manually if not drawing to the CSD titlebar.
if (!ToplevelUsesCSD()) {
- cr -= DesktopIntPoint(mClientMargin.left, mClientMargin.top);
+ cr -= GetClientOffset();
}
- return GdkRectangle{cr.x, cr.y, cr.width, cr.height};
+ return DevicePixelsToGdkRectRoundOut(cr);
}();
- LOG("nsWindow::NativeMoveResize mLastMoveRequest [%d,%d] mClientMargin "
- "[%d,%d] move %d resize %d to [%d,%d] -> [%d x %d]\n",
- int(mLastMoveRequest.x), int(mLastMoveRequest.y), int(mClientMargin.left),
- int(mClientMargin.top), aMoved, aResized, moveResizeRect.x,
- moveResizeRect.y, moveResizeRect.width, moveResizeRect.height);
+ LOG("nsWindow::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n",
+ aMoved, aResized, moveResizeRect.x, moveResizeRect.y,
+ moveResizeRect.width, moveResizeRect.height);
if (aResized && !AreBoundsSane()) {
LOG(" bounds are insane, hidding the window");
@@ -6862,11 +6659,10 @@ void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
// and move it when it's shown.
if (aMoved && GdkIsX11Display() && IsPopup() &&
!gtk_widget_get_visible(GTK_WIDGET(mShell))) {
+ LOG(" store position of hidden popup window");
mHiddenPopupPositioned = true;
mPopupPosition = {moveResizeRect.x, moveResizeRect.y};
- mClientArea.MoveTo(mLastMoveRequest);
- LOG(" store position of hidden popup window [%d, %d]", mPopupPosition.x,
- mPopupPosition.y);
+ mBounds.MoveTo(mLastMoveRequest);
}
if (IsWaylandPopup()) {
@@ -6911,17 +6707,16 @@ void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
// honored: "If the configure request has not changed, we don't ever resend
// it, because it could mean fighting the user or window manager."
// https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.31/gtk/gtkwindow.c#L9782
- // So we don't update mClientArea until OnContainerSizeAllocate() when we know
+ // So we don't update mBounds until OnContainerSizeAllocate() when we know
// the request is granted.
bool isOrWillBeVisible = mHasReceivedSizeAllocate || mNeedsShow || mIsShown;
if (!isOrWillBeVisible || IsPopup()) {
if (aResized) {
- mClientArea.SizeTo(mLastSizeRequest);
+ mBounds.SizeTo(mLastSizeRequest);
}
if (aMoved) {
- mClientArea.MoveTo(mLastMoveRequest);
- auto pos = ToLayoutDevicePixels(mLastMoveRequest);
- NotifyWindowMoved(pos.x, pos.y);
+ mBounds.MoveTo(mLastMoveRequest);
+ NotifyWindowMoved(mBounds.x, mBounds.y);
}
if (aResized) {
DispatchResized();
@@ -7013,8 +6808,7 @@ void nsWindow::NativeShow(bool aAction) {
#endif
}
if (mHiddenPopupPositioned && IsPopup()) {
- LOG(" re-position hidden popup window [%d, %d]", mPopupPosition.x,
- mPopupPosition.y);
+ LOG(" re-position hidden popup window");
gtk_window_move(GTK_WINDOW(mShell), mPopupPosition.x, mPopupPosition.y);
mHiddenPopupPositioned = false;
}
@@ -7080,38 +6874,26 @@ void nsWindow::SetHasMappedToplevel(bool aState) {
}
}
-bool nsWindow::SetSafeWindowSize(LayoutDeviceIntSize& aSize) {
+LayoutDeviceIntSize nsWindow::GetSafeWindowSize(LayoutDeviceIntSize aSize) {
// The X protocol uses CARD32 for window sizes, but the server (1.11.3)
// reads it as CARD16. Sizes of pixmaps, used for drawing, are (unsigned)
// CARD16 in the protocol, but the server's ProcCreatePixmap returns
// BadAlloc if dimensions cannot be represented by signed shorts.
// Because we are creating Cairo surfaces to represent window buffers,
// we also must ensure that the window can fit in a Cairo surface.
- // Keep some reserve for window margin/decorations.
- bool changed = false;
- int32_t maxSize = 32000;
+ LayoutDeviceIntSize result = aSize;
+ int32_t maxSize = 32767;
if (mWindowRenderer && mWindowRenderer->AsKnowsCompositor()) {
maxSize = std::min(
maxSize, mWindowRenderer->AsKnowsCompositor()->GetMaxTextureSize());
}
- if (aSize.width > maxSize) {
- aSize.width = maxSize;
- changed = true;
+ if (result.width > maxSize) {
+ result.width = maxSize;
}
- if (aSize.height > maxSize) {
- aSize.height = maxSize;
- changed = true;
+ if (result.height > maxSize) {
+ result.height = maxSize;
}
- return changed;
-}
-
-bool nsWindow::SetSafeWindowSize(DesktopIntSize& aSize) {
- auto layoutDeviceSize = ToLayoutDevicePixels(aSize);
- auto ret = SetSafeWindowSize(layoutDeviceSize);
- if (ret) {
- aSize = ToDesktopPixels(layoutDeviceSize);
- }
- return ret;
+ return result;
}
void nsWindow::SetTransparencyMode(TransparencyMode aMode) {
@@ -7178,10 +6960,10 @@ void nsWindow::SetInputRegion(const InputRegion& aInputRegion) {
if (aInputRegion.mFullyTransparent) {
region = cairo_region_create_rectangle(&rect);
} else if (aInputRegion.mMargin != 0) {
- DesktopIntRect inputRegion(DesktopIntPoint(), mLastSizeRequest);
+ LayoutDeviceIntRect inputRegion(LayoutDeviceIntPoint(), mLastSizeRequest);
inputRegion.Deflate(aInputRegion.mMargin);
- rect = {inputRegion.x, inputRegion.y, inputRegion.width,
- inputRegion.height};
+ GdkRectangle gdkRect = DevicePixelsToGdkRectRoundOut(inputRegion);
+ rect = {gdkRect.x, gdkRect.y, gdkRect.width, gdkRect.height};
region = cairo_region_create_rectangle(&rect);
}
@@ -7470,9 +7252,11 @@ already_AddRefed<widget::Screen> nsWindow::GetWidgetScreen() {
}
}
+ // GetScreenBounds() is slow for the GTK port so we override and use
+ // mBounds directly.
ScreenManager& screenManager = ScreenManager::GetSingleton();
- DesktopIntRect deskBounds =
- RoundedToInt(GetScreenBounds() / GetDesktopToDeviceScale());
+ LayoutDeviceIntRect bounds = mBounds;
+ DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
return screenManager.ScreenForRect(deskBounds);
}
@@ -9179,8 +8963,10 @@ void nsWindow::SetCustomTitlebar(bool aState) {
g_object_set_data(G_OBJECT(GetToplevelGdkWindow()), "nsWindow", this);
if (AreBoundsSane()) {
- gtk_window_resize(GTK_WINDOW(mShell), mClientArea.width,
- mClientArea.height);
+ GdkRectangle size =
+ DevicePixelsToGdkSizeRoundUp(GetClientBounds().Size());
+ LOG(" resize to %d x %d\n", size.width, size.height);
+ gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
}
if (visible) {
@@ -9243,9 +9029,9 @@ double nsWindow::FractionalScaleFactor() {
return ScreenHelperGTK::GetGTKMonitorFractionalScaleFactor();
}
-gint nsWindow::DevicePixelsToGdkCoordRound(int aPixels) {
+gint nsWindow::DevicePixelsToGdkCoordRoundUp(int aPixels) {
double scale = FractionalScaleFactor();
- return int(round(aPixels / scale));
+ return ceil(aPixels / scale);
}
gint nsWindow::DevicePixelsToGdkCoordRoundDown(int aPixels) {
@@ -9279,6 +9065,18 @@ GdkRectangle nsWindow::DevicePixelsToGdkRectRoundIn(
return {x, y, std::max(right - x, 0), std::max(bottom - y, 0)};
}
+GdkRectangle nsWindow::DevicePixelsToGdkSizeRoundUp(
+ const LayoutDeviceIntSize& aSize) {
+ double scale = FractionalScaleFactor();
+ gint width = ceil(aSize.width / scale);
+ gint height = ceil(aSize.height / scale);
+ return {0, 0, width, height};
+}
+
+int nsWindow::GdkCoordToDevicePixels(gint aCoord) {
+ return (int)(aCoord * FractionalScaleFactor());
+}
+
LayoutDeviceIntPoint nsWindow::GdkEventCoordsToDevicePixels(gdouble aX,
gdouble aY) {
double scale = FractionalScaleFactor();
@@ -9291,6 +9089,26 @@ LayoutDeviceIntPoint nsWindow::GdkPointToDevicePixels(const GdkPoint& aPoint) {
(float)(aPoint.y * scale));
}
+LayoutDeviceIntMargin nsWindow::GtkBorderToDevicePixels(
+ const GtkBorder& aBorder) {
+ double scale = FractionalScaleFactor();
+ return LayoutDeviceIntMargin{
+ (int)(aBorder.top * scale), (int)(aBorder.right * scale),
+ (int)(aBorder.bottom * scale), (int)(aBorder.left * scale)};
+}
+
+LayoutDeviceIntRect nsWindow::GdkRectToDevicePixels(const GdkRectangle& aRect) {
+ return LayoutDeviceIntRect::Round(GdkRectToFloatDevicePixels(aRect));
+}
+
+LayoutDeviceRect nsWindow::GdkRectToFloatDevicePixels(
+ const GdkRectangle& aRect) {
+ double scale = FractionalScaleFactor();
+ return LayoutDeviceRect((float)(aRect.x * scale), (float)(aRect.y * scale),
+ (float)(aRect.width * scale),
+ (float)(aRect.height * scale));
+}
+
nsresult nsWindow::SynthesizeNativeMouseEvent(
LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
@@ -9928,8 +9746,8 @@ void nsWindow::LockAspectRatio(bool aShouldLock) {
}
if (aShouldLock) {
- float width = mLastSizeRequest.width;
- float height = mLastSizeRequest.height;
+ float width = DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.width);
+ float height = DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.height);
mAspectRatio = width / height;
LOG("nsWindow::LockAspectRatio() width %.2f height %.2f aspect %.2f", width,
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
@@ -203,30 +203,25 @@ class nsWindow final : public nsIWidget {
void MoveToWorkspace(const nsAString& workspaceID) override;
void Enable(bool aState) override;
void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
- LayoutDeviceIntRect GetBounds() override;
LayoutDeviceIntRect GetScreenBounds() override;
- DesktopIntRect GetScreenBoundsUnscaled();
LayoutDeviceIntRect GetClientBounds() override;
+ LayoutDeviceIntRect GetBounds() override { return mBounds; }
LayoutDeviceIntSize GetClientSize() override;
- LayoutDeviceIntPoint GetClientOffset() override;
+ LayoutDeviceIntPoint GetClientOffset() override {
+ return LayoutDeviceIntPoint(mClientMargin.left, mClientMargin.top);
+ }
GdkPoint GetCsdOffsetInGdkCoords();
LayoutDeviceIntPoint GetScreenEdgeSlop() override;
nsresult GetRestoredBounds(LayoutDeviceIntRect&) override;
bool PersistClientBounds() const override { return true; }
LayoutDeviceIntMargin NormalSizeModeClientToWindowMargin() override;
- bool ConstrainSizeWithScale(int* aWidth, int* aHeight, double aScale);
+ void ConstrainSize(int* aWidth, int* aHeight) override;
// Recomputes the bounds according to our current window position. Dispatches
// move / resizes as needed.
- void RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange = false);
-#ifdef MOZ_X11
- void RecomputeBoundsX11(bool aMayChangeCsdMargin);
-#endif
-#ifdef MOZ_WAYLAND
- void RecomputeBoundsWayland(bool aMayChangeCsdMargin);
-#endif
enum class MayChangeCsdMargin : bool { No = false, Yes };
+ void RecomputeBounds(MayChangeCsdMargin);
void SchedulePendingBounds(MayChangeCsdMargin);
void MaybeRecomputeBounds();
@@ -238,7 +233,6 @@ class nsWindow final : public nsIWidget {
void SetWindowClass(const nsAString& xulWinType, const nsAString& xulWinClass,
const nsAString& xulWinName) override;
LayoutDeviceIntPoint WidgetToScreenOffset() override;
- DesktopIntPoint WidgetToScreenOffsetUnscaled();
void CaptureRollupEvents(bool aDoCapture) override;
[[nodiscard]] nsresult GetAttention(int32_t aCycleCount) override;
bool HasPendingInputEvent() override;
@@ -429,25 +423,21 @@ class nsWindow final : public nsIWidget {
gint GdkCeiledScaleFactor();
double FractionalScaleFactor();
- LayoutDeviceIntPoint ToLayoutDevicePixels(const DesktopIntPoint&);
- LayoutDeviceIntSize ToLayoutDevicePixels(const DesktopIntSize&);
- LayoutDeviceIntRect ToLayoutDevicePixels(const DesktopIntRect&);
- LayoutDeviceIntMargin ToLayoutDevicePixels(const DesktopIntMargin&);
- DesktopIntSize ToDesktopPixels(const LayoutDeviceIntSize&);
- DesktopIntRect ToDesktopPixels(const LayoutDeviceIntRect&);
- DesktopIntPoint ToDesktopPixels(const LayoutDeviceIntPoint&);
-
// To GDK
- gint DevicePixelsToGdkCoordRound(int);
-
+ gint DevicePixelsToGdkCoordRoundUp(int);
gint DevicePixelsToGdkCoordRoundDown(int);
GdkPoint DevicePixelsToGdkPointRoundDown(const LayoutDeviceIntPoint&);
+ GdkRectangle DevicePixelsToGdkSizeRoundUp(const LayoutDeviceIntSize&);
GdkRectangle DevicePixelsToGdkRectRoundOut(const LayoutDeviceIntRect&);
GdkRectangle DevicePixelsToGdkRectRoundIn(const LayoutDeviceIntRect&);
// From GDK
+ int GdkCoordToDevicePixels(gint);
LayoutDeviceIntPoint GdkPointToDevicePixels(const GdkPoint&);
LayoutDeviceIntPoint GdkEventCoordsToDevicePixels(gdouble aX, gdouble aY);
+ LayoutDeviceIntRect GdkRectToDevicePixels(const GdkRectangle&);
+ LayoutDeviceIntMargin GtkBorderToDevicePixels(const GtkBorder&);
+ LayoutDeviceRect GdkRectToFloatDevicePixels(const GdkRectangle&);
bool WidgetTypeSupportsAcceleration() override;
bool WidgetTypeSupportsNativeCompositing() override;
@@ -496,7 +486,9 @@ class nsWindow final : public nsIWidget {
const LayoutDeviceIntPoint& aLockCenter) override;
void LockNativePointer() override;
void UnlockNativePointer() override;
- LayoutDeviceIntSize GetMoveToRectPopupSize() override;
+ LayoutDeviceIntSize GetMoveToRectPopupSize() const override {
+ return mMoveToRectPopupSize;
+ };
#endif
void ResumeCompositorImpl();
@@ -536,9 +528,7 @@ class nsWindow final : public nsIWidget {
void NativeShow(bool aAction);
void SetHasMappedToplevel(bool aState);
-
- bool SetSafeWindowSize(LayoutDeviceIntSize& aSize);
- bool SetSafeWindowSize(DesktopIntSize& aSize);
+ LayoutDeviceIntSize GetSafeWindowSize(LayoutDeviceIntSize aSize);
void DispatchContextMenuEventFromMouseEvent(
uint16_t domButton, GdkEventButton* aEvent,
@@ -575,8 +565,8 @@ class nsWindow final : public nsIWidget {
nsWindow* GetTransientForWindowIfPopup();
bool IsHandlingTouchSequence(GdkEventSequence* aSequence);
- void ResizeInt(const mozilla::Maybe<DesktopIntPoint>& aMove,
- DesktopIntSize aSize);
+ void ResizeInt(const mozilla::Maybe<LayoutDeviceIntPoint>& aMove,
+ LayoutDeviceIntSize aSize);
void NativeMoveResizeWaylandPopup(bool aMove, bool aResize);
// Returns a window edge if the given point (in device pixels) is within a
@@ -624,41 +614,18 @@ class nsWindow final : public nsIWidget {
constexpr static const int sNoScale = -1;
int mCeiledScaleFactor = sNoScale;
- // Client area received by OnContainerSizeAllocate().
- // We don't use it directly but as a reference.
- DesktopIntRect mReceivedClientArea{};
-
- // The size requested, which might not be reflected in mClientArea. Used in
+ // The size requested, which might not be reflected in mBounds. Used in
// WaylandPopupSetDirectPosition() to remember intended size for popup
// positioning, in LockAspect() to remember the intended aspect ratio, and
// to remember a size requested while waiting for moved-to-rect when
- // OnSizeAllocate() might change mClientArea.Size().
- // All these values are in unscaled (Gdk) coordinates.
- DesktopIntSize mLastSizeRequest;
+ // OnSizeAllocate() might change mBounds.Size().
+ LayoutDeviceIntSize mLastSizeRequest;
// Same but for positioning. Used to track move requests.
- DesktopIntPoint mLastMoveRequest;
-
- // Window bounds (mBounds) are composed as
- // mClientArea.Inflate(mClientMargin)*scale, i.e.:
- //
- // mBounds.x = (mClientArea.x - mClientMargin.left) * scale;
- // mBounds.y = (mClientArea.y - mClientMargin.top) * scale;
- // mBounds.width = (mClientArea.width +
- // (mClientMargin.right + mClientMargin.left)) * scale;
- // mBounds.height = (mClientArea.height +
- // (mClientMargin.top + mClientMargin.bottom)) * scale;
- //
- // We use mClientMargin and mClientArea in Gdk (logical, widget) coordinates
- // instead of mBounds i device pixel coordinates to avoid
- // rounding errors.
-
- // mClientMargin contains CSD decorations size on Wayland and
- // CSD decorations and system titlebar size on X11.
- DesktopIntMargin mClientMargin{};
-
- // mClientArea is window rendering area. mClientArea.x, mClientArea.y are
- // equal to mClientMargin.left, mClientMargin.top.
- DesktopIntRect mClientArea{};
+ LayoutDeviceIntPoint mLastMoveRequest;
+ // Margin from mBounds to the client rect (including CSD decorations).
+ LayoutDeviceIntMargin mClientMargin;
+ // Bounds of the window, as in GetBounds().
+ LayoutDeviceIntRect mBounds;
// This field omits duplicate scroll events caused by GNOME bug 726878.
guint32 mLastScrollEventTime = GDK_CURRENT_TIME;
@@ -968,7 +935,7 @@ class nsWindow final : public nsIWidget {
// When popup is resized by Gtk by move-to-rect callback,
// we store final popup size here. Then we use mMoveToRectPopupSize size
// in following popup operations unless mLayoutPopupSizeCleared is set.
- DesktopIntSize mMoveToRectPopupSize;
+ LayoutDeviceIntSize mMoveToRectPopupSize;
#ifdef MOZ_ENABLE_DBUS
RefPtr<mozilla::widget::DBusMenuBar> mDBusMenuBar;
diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
@@ -446,8 +446,6 @@ class nsIWidget : public nsSupportsWeakReference {
typedef mozilla::DesktopIntRect DesktopIntRect;
typedef mozilla::DesktopPoint DesktopPoint;
typedef mozilla::DesktopIntPoint DesktopIntPoint;
- typedef mozilla::DesktopIntSize DesktopIntSize;
- typedef mozilla::DesktopIntMargin DesktopIntMargin;
typedef mozilla::DesktopRect DesktopRect;
typedef mozilla::DesktopSize DesktopSize;
typedef mozilla::CSSPoint CSSPoint;
@@ -1923,7 +1921,7 @@ class nsIWidget : public nsSupportsWeakReference {
/**
* Wayland specific routines.
*/
- virtual LayoutDeviceIntSize GetMoveToRectPopupSize() {
+ virtual LayoutDeviceIntSize GetMoveToRectPopupSize() const {
NS_WARNING("GetLayoutPopupRect implemented only for wayland");
return LayoutDeviceIntSize();
}