https://bugs.documentfoundation.org/show_bug.cgi?id=173298
Bug ID: 173298
Summary: gtk3: moving a window from a lower-scale to a
higher-scale monitor upscales the whole window,
because GtkSalFrame::AllocateFrame() only reallocates
on a logical size change and not on a device scale
change
Product: LibreOffice
Version: 26.2.5.2 release
Hardware: All
OS: Linux (All)
Status: UNCONFIRMED
Severity: normal
Priority: medium
Component: graphics stack
Assignee: [email protected]
Reporter: [email protected]
Description:
On a multi-monitor Wayland setup where the monitors have different scale
factors,
moving a LibreOffice window from the lower-scale monitor to the higher-scale
one
leaves the whole window blurry. Everything is affected: document text,
toolbars,
the ruler and the status bar.
The window keeps drawing from the backing surface it allocated on the old
monitor, and that surface is stretched to fit the new one.
GtkSalFrame::AllocateFrame() (vcl/unx/gtk3/gtkframe.cxx:2133) recreates
m_pSurface only when the frame's logical size changes:
bool GtkSalFrame::AllocateFrame()
{
basegfx::B2IVector aFrameSize( maGeometry.width(), maGeometry.height()
);
if (m_pSurface && m_aFrameSize.getX() == aFrameSize.getX() &&
m_aFrameSize.getY() == aFrameSize.getY() )
return false;
...
maGeometry is in logical units, set from GTK's size-allocate in
DrawingAreaResized(). Moving a window between monitors at the same logical size
therefore hits the early return, even though the GDK surface scale has changed
from 2 to 3.
The surface itself is created with gdk_window_create_similar_surface(), so it
carries the device scale it had when it was allocated. GtkSalFrame::
DrawingAreaDraw() then does cairo_set_source_surface(cr, m_pSurface, 0, 0) into
the new destination, and cairo scales the stale surface up.
The three call sites of AllocateFrame() are AcquireGraphics(),
DrawingAreaResized()
and signalRealize(). None of them is a scale-change notification, and
gtkframe.cxx has no notify::scale-factor handler.
Direction matters. Moving from a HIGHER to a LOWER scale monitor also keeps the
stale surface, but it is then downsampled, so it still looks sharp and the bug
is easy to miss. Only the low-to-high direction is visible.
Steps to Reproduce:
Requires two monitors with different scale factors. Here: an internal panel at
235% (GTK integer scale 3) and an external at 120% (GTK integer scale 2).
1. Start LibreOffice with the gtk3 plugin on Wayland:
SAL_USE_VCLPLUGIN=gtk3 GDK_BACKEND=wayland soffice --writer
2. Move the Writer window to the LOWER-scale monitor and type some text.
This is the important step: the backing surface must be allocated there.
3. Make sure the window is floating, not maximized, so that moving it does not
also resize it.
4. Drag the window to the HIGHER-scale monitor without resizing it.
5. Click in the document so it repaints.
Zooming to 200% makes it easier to see.
Actual Results:
The entire window is blurry: document text, toolbars, ruler and status bar. It
stays blurry until something forces a resize; resizing the window even slightly
clears it.
Expected Results:
The window should be redrawn at the new monitor's resolution, as it is when the
window is first opened on that monitor.
Reproducible: Always
User Profile Reset: No
Additional Info:
Confirmed by runtime observation rather than by eye, using an LD_PRELOAD
interposer that logs gdk_window_create_similar_surface(),
cairo_surface_create_similar() and cairo_set_source_surface() and then calls
the
real function unchanged. LibreOffice itself was not modified or rebuilt.
During a move from the scale-2 monitor to the scale-3 monitor at constant frame
geometry:
- the last frame allocation before the move is 2000x1410 at device scale 2;
- no frame allocation happens during the move;
- ten whole-frame copies follow, each 2000x1410 @2 into 3000x2196 @3, at
offset (0,0), which is the DrawingAreaDraw() blit.
Moving back to the scale-2 monitor produces the mirror image: the stale @3
surface is downsampled into an @2 destination, which is why that direction
looks
fine.
A caution for anyone measuring this: whole-window sharpness metrics do not
detect it reliably. Comparing captures from the two monitors gave nearly
identical edge statistics (13.32 vs 13.86 mean absolute gradient) on a pair
that
was independently proven stale, because a downsampled stale surface still has
sharp edges. The allocation and copy trace is what establishes it.
Environment:
LibreOffice 26.2.5.2 (30643f3b95f81f04449dc87ba649cc313a42270e)
gtk3 3.24.52, cairo 1.18.4
KDE Plasma / KWin 6.7.4 on Wayland
eDP-1 at KWin scale 2.35 (GDK surface scale 3)
HDMI-A-1 at KWin scale 1.2 (GDK surface scale 2)
The Qt/KF6 backend has a related but separate problem in the same area, where
persistent VirtualDevices keep the device scale of the frame surface they were
constructed against. That is being looked at alongside gerrit change 209137 and
is not part of this report.
--
You are receiving this mail because:
You are the assignee for the bug.