[client] wayland: apply the surface scale before the first commit

The buffer scale and viewport were only set from the resize handling in
the swap path, which runs after the buffer has been committed. The first
commit therefore carried a buffer of scale x the window size with no
scale declared, so the compositor sized the window from the raw buffer.
On a scaled output that is larger than the work area GNOME maximizes it,
after which libdecor drops every resize as the frame is no longer
floating, leaving the window stuck at the size of the display.

Split the scaling out of the swap path and apply it when the EGL window
is created, so it is in place for the first commit.
This commit is contained in:
Amit Mendapara
2026-08-12 10:14:06 +05:30
committed by Geoffrey McRae
parent 52f7c3a896
commit 13b6e04256

View File

@@ -35,6 +35,40 @@
#include "egl_dynprocs.h"
#include "eglutil.h"
// Map the buffer onto width x height logical pixels, through the viewport for
// a fractional scale, or the buffer scale otherwise
static void applySurfaceScale(int width, int height)
{
if (wlWm.fractionalScale)
{
wl_surface_set_buffer_scale(wlWm.surface, 1);
if (!wlWm.viewport)
wlWm.viewport = wp_viewporter_get_viewport(wlWm.viewporter, wlWm.surface);
wp_viewport_set_source(
wlWm.viewport,
wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1)
);
wp_viewport_set_destination(wlWm.viewport, width, height);
}
else
{
if (wlWm.viewport)
{
// Clearing the source and destination rectangles should happen in wp_viewport_destroy.
// However, wlroots does not clear the rectangle until fixed in 456c6e22 (2021-08-02).
// This should be kept to work around old versions of wlroots.
wl_fixed_t clear = wl_fixed_from_int(-1);
wp_viewport_set_source(wlWm.viewport, clear, clear, clear, clear);
wp_viewport_set_destination(wlWm.viewport, -1, -1);
wp_viewport_destroy(wlWm.viewport);
wlWm.viewport = NULL;
}
wl_surface_set_buffer_scale(wlWm.surface, waylandScaleFloor(wlWm.scale));
}
}
bool waylandEGLInit(int w, int h)
{
wlWm.eglWindow = wl_egl_window_create(wlWm.surface, w, h);
@@ -44,6 +78,13 @@ bool waylandEGLInit(int w, int h)
return false;
}
// The compositor sizes the window from the first buffer committed, so the
// scale has to be applied before then
int width, height;
wlWm.desktop->getSize(&width, &height);
if (width > 0 && height > 0)
applySurfaceScale(width, height);
return true;
}
@@ -277,34 +318,8 @@ bool waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface,
if (width == 0 || height == 0)
skipResize = true;
else if (wlWm.fractionalScale)
{
wl_surface_set_buffer_scale(wlWm.surface, 1);
if (!wlWm.viewport)
wlWm.viewport = wp_viewporter_get_viewport(wlWm.viewporter, wlWm.surface);
wp_viewport_set_source(
wlWm.viewport,
wl_fixed_from_int(-1), wl_fixed_from_int(-1),
wl_fixed_from_int(-1), wl_fixed_from_int(-1)
);
wp_viewport_set_destination(wlWm.viewport, width, height);
}
else
{
if (wlWm.viewport)
{
// Clearing the source and destination rectangles should happen in wp_viewport_destroy.
// However, wlroots does not clear the rectangle until fixed in 456c6e22 (2021-08-02).
// This should be kept to work around old versions of wlroots.
wl_fixed_t clear = wl_fixed_from_int(-1);
wp_viewport_set_source(wlWm.viewport, clear, clear, clear, clear);
wp_viewport_set_destination(wlWm.viewport, -1, -1);
wp_viewport_destroy(wlWm.viewport);
wlWm.viewport = NULL;
}
wl_surface_set_buffer_scale(wlWm.surface, waylandScaleFloor(wlWm.scale));
}
applySurfaceScale(width, height);
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
wl_region_add(region, 0, 0, width, height);