mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
wayland: latch xdg_toplevel configure state until xdg_surface.configure
Per xdg-shell, xdg_toplevel.configure events describe pending state that only becomes current when the compositor sends xdg_surface.configure, which the client must acknowledge. RetroArch applied toplevel state (size, fullscreen/maximized flags, the EGL window resize via the driver hook) immediately at toplevel.configure and blind-acked xdg_surface.configure from the shared input-common listener, i.e. state was applied before the compositor's atomic point and the ack carried no meaning. This is the suspected root of the long-standing fullscreen state cluster on stricter compositors: fullscreen reverting to a window on core launch with core-dependent (timing-dependent) reproduction (#14481), fullscreen re-entry wedging on KWin until restart including via internal-resolution switches (forum 48446), wrong-size/offset fullscreen repaired by alt-tab - i.e. by the next configure cycle - (#16779, #17372), and the pre-fullscreen splash artifact (#14408) that the in-tree ignore_configuration / legacy-fullscreen hacks were added to paper over. xdg_toplevel.configure now only records the advertised size and states into an embedded cfg_pending struct (last-wins on repeated events, no allocation); a gfx-local xdg_surface listener applies the latched state, invokes the per-backend hook, clears 'configured', and acknowledges with the serial. ignore_configuration is evaluated at the apply point and drops the latched configuration exactly as the old code dropped the toplevel event; the legacy-fullscreen fallback is preserved unchanged inside the apply. No commits are added to the configure path: as before, acknowledged state takes effect on the frame loop's next commit. The libdecor path is untouched - libdecor's configure callback is already the atomic point and commits via libdecor_frame_commit. Validated under headless Weston 13 (Vulkan/lavapipe, imageviewer content), A/B against master: - windowed startup: structurally identical protocol traces; - fullscreen startup (the bug-cluster path): identical request sequences (set_fullscreen, fullscreen configure 1024x640 with 4 states, ack), identical applied swapchain resolution, zero protocol errors. So: no regression on the one compositor testable here, with the intended behavioral difference confined to when state is applied. NOT verified: Mutter and KWin, interactive resize, and runtime libdecor (compile-covered only; Weston runs took the plain xdg path). The issues above double as the test plan - this should be confirmed against KWin (forum 48446 repro: fullscreen -> windowed -> fullscreen, and internal-resolution switching) and a multi-monitor Mutter/KWin setup (#16779/#17372 repro) before or promptly after merging, and backed out if the cluster does not improve.
This commit is contained in:
1 parent
35dcafb253
commit
7eefa407e0
2 files changed
+97
-40
No files matched your search
+84
-40
@@ -102,41 +102,22 @@ static bool gfx_ctx_wl_should_use_legacy_fullscreen_configure(
|
||||
return false;
|
||||
}
|
||||
|
||||
static void xdg_toplevel_handle_configure_common(gfx_ctx_wayland_data_t *wl,
|
||||
void *toplevel,
|
||||
int32_t width, int32_t height, struct wl_array *states)
|
||||
/* Apply a latched xdg_toplevel configuration. Runs from the
|
||||
* xdg_surface.configure handler: per xdg-shell, toplevel configure
|
||||
* events describe pending state that only becomes current when the
|
||||
* compositor sends xdg_surface.configure. */
|
||||
static void xdg_configure_apply(gfx_ctx_wayland_data_t *wl)
|
||||
{
|
||||
const uint32_t *state;
|
||||
bool floating = true;
|
||||
int32_t width = wl->cfg_pending.width;
|
||||
int32_t height = wl->cfg_pending.height;
|
||||
bool floating = wl->cfg_pending.floating;
|
||||
|
||||
wl->fullscreen = false;
|
||||
wl->maximized = false;
|
||||
|
||||
WL_ARRAY_FOR_EACH(state, states, const uint32_t*)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
wl->fullscreen = true;
|
||||
floating = false;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
wl->maximized = true;
|
||||
/* fall-through */
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
||||
floating = false;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
wl->resize = true;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
wl->activated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wl->fullscreen = wl->cfg_pending.fullscreen;
|
||||
wl->maximized = wl->cfg_pending.maximized;
|
||||
if (wl->cfg_pending.resizing)
|
||||
wl->resize = true;
|
||||
if (wl->cfg_pending.activated)
|
||||
wl->activated = true;
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
{
|
||||
@@ -307,14 +288,77 @@ static void xdg_toplevel_handle_configure(void *data,
|
||||
int32_t width, int32_t height, struct wl_array *states)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
if (wl->ignore_configuration)
|
||||
return;
|
||||
xdg_toplevel_handle_configure_common(wl, toplevel, width, height, states);
|
||||
if (wl->driver_configure_handler)
|
||||
wl->driver_configure_handler(wl);
|
||||
wl->configured = false;
|
||||
const uint32_t *state;
|
||||
|
||||
/* Record only; the state is pending until xdg_surface.configure.
|
||||
* A later toplevel.configure before the surface.configure
|
||||
* supersedes this one (last-wins), matching the protocol. */
|
||||
wl->cfg_pending.width = width;
|
||||
wl->cfg_pending.height = height;
|
||||
wl->cfg_pending.fullscreen = false;
|
||||
wl->cfg_pending.maximized = false;
|
||||
wl->cfg_pending.resizing = false;
|
||||
wl->cfg_pending.activated = false;
|
||||
wl->cfg_pending.floating = true;
|
||||
|
||||
WL_ARRAY_FOR_EACH(state, states, const uint32_t*)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
wl->cfg_pending.fullscreen = true;
|
||||
wl->cfg_pending.floating = false;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
wl->cfg_pending.maximized = true;
|
||||
/* fall-through */
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
||||
wl->cfg_pending.floating = false;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
wl->cfg_pending.resizing = true;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
wl->cfg_pending.activated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wl->cfg_pending.pending = true;
|
||||
}
|
||||
|
||||
static void xdg_surface_handle_configure_latch(void *data,
|
||||
struct xdg_surface *xdg_surface, uint32_t serial)
|
||||
{
|
||||
gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;
|
||||
|
||||
if (wl->cfg_pending.pending)
|
||||
{
|
||||
wl->cfg_pending.pending = false;
|
||||
/* ignore_configuration drops the configuration exactly as the
|
||||
* pre-latching code dropped it at toplevel.configure time;
|
||||
* evaluated here, at the atomic point. */
|
||||
if (!wl->ignore_configuration)
|
||||
{
|
||||
xdg_configure_apply(wl);
|
||||
if (wl->driver_configure_handler)
|
||||
wl->driver_configure_handler(wl);
|
||||
wl->configured = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always acknowledge; the new state takes effect on the next
|
||||
* wl_surface.commit, which the frame loop performs. */
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener wl_xdg_surface_listener = {
|
||||
xdg_surface_handle_configure_latch,
|
||||
};
|
||||
|
||||
static const struct xdg_toplevel_listener wl_xdg_toplevel_listener = {
|
||||
xdg_toplevel_handle_configure,
|
||||
xdg_toplevel_handle_close,
|
||||
@@ -988,7 +1032,7 @@ bool gfx_ctx_wl_init_common(
|
||||
#endif
|
||||
{
|
||||
wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_shell, wl->surface);
|
||||
xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
|
||||
xdg_surface_add_listener(wl->xdg_surface, &wl_xdg_surface_listener, wl);
|
||||
|
||||
wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
|
||||
xdg_toplevel_add_listener(wl->xdg_toplevel, &wl_xdg_toplevel_listener, wl);
|
||||
|
||||
@@ -268,6 +268,19 @@ typedef struct gfx_ctx_wayland_data
|
||||
bool configured;
|
||||
bool ignore_configuration;
|
||||
driver_configure_handler_t driver_configure_handler;
|
||||
/* State from xdg_toplevel.configure, held until the compositor's
|
||||
* xdg_surface.configure marks it current (xdg-shell latching). */
|
||||
struct
|
||||
{
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
bool fullscreen;
|
||||
bool maximized;
|
||||
bool resizing;
|
||||
bool activated;
|
||||
bool floating;
|
||||
bool pending;
|
||||
} cfg_pending;
|
||||
bool activated;
|
||||
bool reported_display_size;
|
||||
bool swap_complete;
|
||||
|
||||
Reference in new issue
Block a user