From 3379adebe117ff9f342e52c1ac24e58e3a2f81fd Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 28 Oct 2024 11:47:10 +0100 Subject: [PATCH] desktop/output: Store output config on request_state An output backend might request any change to an output state at any time, although currently only this is currently only used for changing window size on the wayland and x11 backend. Applying the configuration directly means that the current output state becomes inconsistent with the configured state, which can cause the new state to be reverted later if apply_stored_output_configs is called. Before 4f9ce4675cf4. the output geometry would be updated by arrange_outputs, but this is only done by the modeset logic now, resulting in the stored geometry never being updated on wayland backend window resize. This was not discovered as the stored geometry is not used particularly often. Solve both by storing a new output configuration and relying on the modeset logic to apply a new state. Fixes: 4f9ce4675cf4 ("tree/arrange: Remove redundant output geometry update") --- sway/desktop/output.c | 48 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 18a04c090..394c545de 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -457,19 +457,47 @@ static void handle_request_state(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, request_state); const struct wlr_output_event_request_state *event = data; + const struct wlr_output_state *state = event->state; - uint32_t committed = event->state->committed; - wlr_output_commit_state(output->wlr_output, event->state); + // Store the requested changes so that the active configuration is + // consistent with the current state, and to avoid duplicate logic to apply + // the changes. + struct output_config *oc = new_output_config(output->wlr_output->name); + if (!oc) { + sway_log(SWAY_ERROR, "Allocation failed"); + return; + } - if (committed & ( - WLR_OUTPUT_STATE_MODE | - WLR_OUTPUT_STATE_TRANSFORM | - WLR_OUTPUT_STATE_SCALE)) { - arrange_layers(output); - arrange_output(output); - transaction_commit_dirty(); + int committed = state->committed; + if (committed & WLR_OUTPUT_STATE_MODE) { + if (state->mode != NULL) { + oc->width = state->mode->width; + oc->height = state->mode->height; + oc->refresh_rate = state->mode->refresh / 1000.f; + } else { + oc->width = state->custom_mode.width; + oc->height = state->custom_mode.height; + oc->refresh_rate = state->custom_mode.refresh / 1000.f; + } + committed &= ~WLR_OUTPUT_STATE_MODE; + } + if (committed & WLR_OUTPUT_STATE_SCALE) { + oc->scale = state->scale; + committed &= ~WLR_OUTPUT_STATE_SCALE; + } + if (committed & WLR_OUTPUT_STATE_TRANSFORM) { + oc->transform = state->transform; + committed &= ~WLR_OUTPUT_STATE_TRANSFORM; + } - update_output_manager_config(output->server); + // We do not expect or support any other changes here + assert(committed == 0); + store_output_config(oc); + apply_stored_output_configs(); + + if (server.delayed_modeset != NULL) { + wl_event_source_remove(server.delayed_modeset); + server.delayed_modeset = NULL; } }