commit 0f2aaec1be54619203d398febf4921c5eba06213
parent 0ae81b46738fd8c776bb8b2c6d139ae4a8aa1193
Author: stransky <stransky@redhat.com>
Date: Mon, 24 Nov 2025 18:53:47 +0000
Bug 1999838 [Linux] Always get window margin and check if it's actually changed before resize/move r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D273792
Diffstat:
2 files changed, 35 insertions(+), 41 deletions(-)
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
@@ -426,7 +426,6 @@ nsWindow::nsWindow()
mHasMappedToplevel(false),
mPanInProgress(false),
mPendingBoundsChange(false),
- mPendingBoundsChangeMayChangeCsdMargin(false),
mTitlebarBackdropState(false),
mAlwaysOnTop(false),
mIsTransparent(false),
@@ -3361,8 +3360,8 @@ LayoutDeviceIntCoord GetXWindowBorder(GdkWindow* aWin) {
top corner, so matches CSD size - (40,40).
*/
#ifdef MOZ_X11
-void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
- LOG("RecomputeBoundsX11(%d)", aMayChangeCsdMargin);
+void nsWindow::RecomputeBoundsX11() {
+ LOGVERBOSE("RecomputeBoundsX11()");
auto* toplevel = GetToplevelGdkWindow();
@@ -3370,6 +3369,10 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
auto GetFrameTitlebarBounds = [&](GdkWindow* aWin) {
GdkRectangle b{0};
gdk_window_get_frame_extents(aWin, &b);
+ LOGVERBOSE(
+ " GetFrameTitlebarBounds(): gdk_window_get_frame_extents() [%d,%d] -> "
+ "[%d x %d]",
+ b.x, b.y, b.width, b.height);
if (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
@@ -3402,11 +3405,15 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
// 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);
+ LOGVERBOSE(" GetBounds(): toplevel [%d,%d] -> [%d x %d]", b.x, b.y,
+ b.width, b.height);
return DesktopIntRect(b.x, b.y, b.width, b.height);
}
gdk_window_get_position(aWin, &b.x, &b.y);
b.width = gdk_window_get_width(aWin);
b.height = gdk_window_get_height(aWin);
+ LOGVERBOSE(" GetBounds(): popup [%d,%d] -> [%d x %d]", b.x, b.y, b.width,
+ b.height);
return DesktopIntRect(b.x, b.y, b.width, b.height);
};
@@ -3429,7 +3436,7 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated;
if (!decorated) {
mClientMargin = {};
- } else if (aMayChangeCsdMargin) {
+ } else {
// TODO: Do we really need so complex margin calculation on X11?
const DesktopIntRect clientRectRelativeToFrame = [&] {
auto topLevelBoundsRelativeToFrame = toplevelBounds;
@@ -3450,8 +3457,6 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
mClientMargin = DesktopIntRect(DesktopIntPoint(), finalBounds.Size()) -
clientRectRelativeToFrame;
mClientMargin.EnsureAtLeast(DesktopIntMargin());
- } else {
- // Assume the client margin remains the same.
}
mClientArea = finalBounds;
@@ -3459,7 +3464,7 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) {
}
#endif
#ifdef MOZ_WAYLAND
-void nsWindow::RecomputeBoundsWayland(bool aMayChangeCsdMargin) {
+void nsWindow::RecomputeBoundsWayland() {
auto GetBounds = [&](GdkWindow* aWin) {
GdkRectangle b{0};
gdk_window_get_position(aWin, &b.x, &b.y);
@@ -3471,11 +3476,11 @@ void nsWindow::RecomputeBoundsWayland(bool aMayChangeCsdMargin) {
const auto toplevelBounds = GetBounds(GetToplevelGdkWindow());
mClientArea = GetBounds(mGdkWindow);
- LOG("RecomputeBoundsWayland(%d) GetBounds(mGdkWindow) [%d,%d] -> [%d x %d] "
+ LOG("RecomputeBoundsWayland() GetBounds(mGdkWindow) [%d,%d] -> [%d x %d] "
"GetBounds(mShell) [%d,%d] -> [%d x %d]",
- aMayChangeCsdMargin, mClientArea.x, mClientArea.y, mClientArea.width,
- mClientArea.height, toplevelBounds.x, toplevelBounds.y,
- toplevelBounds.width, toplevelBounds.height);
+ mClientArea.x, mClientArea.y, mClientArea.width, mClientArea.height,
+ toplevelBounds.x, toplevelBounds.y, toplevelBounds.width,
+ toplevelBounds.height);
if (mClientArea.X() < 0 || mClientArea.Y() < 0 || mClientArea.Width() <= 1 ||
mClientArea.Height() <= 1) {
@@ -3487,22 +3492,18 @@ void nsWindow::RecomputeBoundsWayland(bool aMayChangeCsdMargin) {
IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated;
if (!decorated) {
mClientMargin = {};
- } else if (aMayChangeCsdMargin) {
+ } else {
mClientMargin =
DesktopIntRect(DesktopIntPoint(), toplevelBounds.Size()) - mClientArea;
mClientMargin.EnsureAtLeast(DesktopIntMargin());
- } 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);
+void nsWindow::RecomputeBounds(bool aScaleChange) {
+ LOG("RecomputeBounds() scale change %d", aScaleChange);
mPendingBoundsChange = false;
- mPendingBoundsChangeMayChangeCsdMargin = false;
auto* toplevel = GetToplevelGdkWindow();
if (!toplevel || mIsDestroyed) {
@@ -3514,15 +3515,17 @@ void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) {
#ifdef MOZ_X11
if (GdkIsX11Display()) {
- RecomputeBoundsX11(aMayChangeCsdMargin);
+ RecomputeBoundsX11();
}
#endif
#ifdef MOZ_WAYLAND
if (GdkIsWaylandDisplay()) {
- RecomputeBoundsWayland(aMayChangeCsdMargin);
+ RecomputeBoundsWayland();
}
#endif
+ bool marginChanged = (oldMargin != mClientMargin);
+
#ifdef MOZ_LOGGING
if (LOG_ENABLED()) {
if (mHasReceivedSizeAllocate) {
@@ -3574,9 +3577,9 @@ 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 ||
+ const bool moved = aScaleChange || marginChanged ||
oldClientArea.TopLeft() != mClientArea.TopLeft();
- const bool resized = aScaleChange || aMayChangeCsdMargin ||
+ const bool resized = aScaleChange || marginChanged ||
oldClientArea.Size() != mClientArea.Size();
if (moved) {
@@ -3592,7 +3595,7 @@ gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget,
GdkEventProperty* aEvent) {
if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) {
LOG("OnPropertyNotifyEvent(_NET_FRAME_EXTENTS)");
- SchedulePendingBounds(MayChangeCsdMargin::Yes);
+ SchedulePendingBounds();
return FALSE;
}
if (!mGdkWindow) {
@@ -4278,7 +4281,7 @@ gboolean nsWindow::OnShellConfigureEvent(GdkEventConfigure* aEvent) {
// X11 calc bounds from outer window while Wayland uses
// container size after container allocation event.
if (GdkIsX11Display()) {
- SchedulePendingBounds(MayChangeCsdMargin::No);
+ SchedulePendingBounds();
}
return FALSE;
}
@@ -4301,7 +4304,7 @@ void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) {
// Also, this runs for both top level size_allocate and MozContainer size
// allocate, so even if the client bounds are the same, we need to recompute
// the bounds because the client margin might not.
- SchedulePendingBounds(MayChangeCsdMargin::Yes);
+ SchedulePendingBounds();
// Invalidate the new part of the window now for the pending paint to
// minimize background flashes (GDK does not do this for external
@@ -4323,9 +4326,7 @@ void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) {
}
}
-void nsWindow::SchedulePendingBounds(MayChangeCsdMargin aMayChangeCsdMargin) {
- mPendingBoundsChangeMayChangeCsdMargin |=
- aMayChangeCsdMargin == MayChangeCsdMargin::Yes;
+void nsWindow::SchedulePendingBounds() {
if (mPendingBoundsChange) {
return;
}
@@ -4337,7 +4338,7 @@ void nsWindow::SchedulePendingBounds(MayChangeCsdMargin aMayChangeCsdMargin) {
void nsWindow::MaybeRecomputeBounds() {
LOG("MaybeRecomputeBounds %d", mPendingBoundsChange);
if (mPendingBoundsChange) {
- RecomputeBounds(mPendingBoundsChangeMayChangeCsdMargin);
+ RecomputeBounds();
}
}
@@ -5721,7 +5722,7 @@ void nsWindow::RefreshScale(bool aRefreshScreen, bool aForceRefresh) {
return;
}
- RecomputeBounds(/* MayChangeCsdMargin */ true, /* ScaleChanged*/ true);
+ RecomputeBounds(/* ScaleChanged*/ true);
if (PresShell* presShell = GetPresShell()) {
presShell->BackingScaleFactorChanged();
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
@@ -216,15 +216,14 @@ class nsWindow final : public nsIWidget {
// Recomputes the bounds according to our current window position. Dispatches
// move / resizes as needed.
- void RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange = false);
+ void RecomputeBounds(bool aScaleChange = false);
#ifdef MOZ_X11
- void RecomputeBoundsX11(bool aMayChangeCsdMargin);
+ void RecomputeBoundsX11();
#endif
#ifdef MOZ_WAYLAND
- void RecomputeBoundsWayland(bool aMayChangeCsdMargin);
+ void RecomputeBoundsWayland();
#endif
- enum class MayChangeCsdMargin : bool { No = false, Yes };
- void SchedulePendingBounds(MayChangeCsdMargin);
+ void SchedulePendingBounds();
void MaybeRecomputeBounds();
void SetCursor(const Cursor&) override;
@@ -730,12 +729,6 @@ class nsWindow final : public nsIWidget {
bool mHasMappedToplevel : 1;
bool mPanInProgress : 1;
bool mPendingBoundsChange : 1;
- // Whether our pending bounds change event might change the window CSD margin.
- // This is needed because we might get two configures (one for mShell, one
- // for mContainer's window) in quick succession, which might cause us to send
- // spurious sequences of resizes if we don't do this on some compositors
- // (older mutter at least).
- bool mPendingBoundsChangeMayChangeCsdMargin : 1;
// Draw titlebar with :backdrop css state (inactive/unfocused).
bool mTitlebarBackdropState : 1;
bool mAlwaysOnTop : 1;