From 5de9e1a99d6642c2d09d589aa37ff0a8945dcee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A4in=C3=B6=20M=C3=A4kel=C3=A4?= Date: Wed, 1 Nov 2023 08:51:18 +0200 Subject: [PATCH] wlr-output-management: Send custom modes to clients Since commit 5567aefb, fixed modes haven't been automatically generated for custom modes, so the output management implementation needs to be able to handle them directly. To avoid polluting the mode list, only a single custom mode can be listed at a time and will be removed when a fixed mode is set. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3744 --- types/wlr_output_management_v1.c | 46 +++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index b6dfb93d..b90d227e 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -32,7 +32,7 @@ static struct wlr_output_head_v1 *head_from_resource( static const struct zwlr_output_mode_v1_interface output_mode_impl; -// Can return NULL if the mode is inert +// Can return NULL if the mode is custom or inert static struct wlr_output_mode *mode_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, @@ -86,6 +86,28 @@ static struct wlr_output_head_v1 *head_create( return head; } +static void head_destroy_custom_mode_resources(struct wlr_output_head_v1 *head) { + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &head->mode_resources) { + if (wl_resource_get_user_data(resource) != NULL) { + continue; + } + zwlr_output_mode_v1_send_finished(resource); + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); + } +} + +static bool head_has_custom_mode_resources(const struct wlr_output_head_v1 *head) { + struct wl_resource *resource; + wl_resource_for_each(resource, &head->mode_resources) { + if (wl_resource_get_user_data(resource) == NULL) { + return true; + } + } + return false; +} + static void config_head_destroy( struct wlr_output_configuration_head_v1 *config_head) { @@ -161,12 +183,12 @@ static void config_head_handle_set_mode(struct wl_client *client, return; } - // Mode can be NULL if the output doesn't support modes (in which case we - // expose only one "virtual" mode, the current mode) + // Mode can be NULL if the output uses a custom mode (in which case we + // expose a virtual mode with user data set to NULL). struct wlr_output_mode *mode = mode_from_resource(mode_resource); struct wlr_output *output = config_head->state.output; - bool found = (mode == NULL && wl_list_empty(&output->modes)); + bool found = mode == NULL; struct wlr_output_mode *m; wl_list_for_each(m, &output->modes, link) { if (mode == m) { @@ -737,9 +759,6 @@ static void head_send_state(struct wlr_output_head_v1 *head, } if (state & HEAD_STATE_MODE) { - assert(head->state.mode != NULL || - wl_list_empty(&head->state.output->modes)); - bool found = false; struct wl_resource *mode_resource; wl_resource_for_each(mode_resource, &head->mode_resources) { @@ -847,8 +866,8 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager, head_send_mode(head, head_resource, mode); } - if (wl_list_empty(&output->modes)) { - // Output doesn't support modes. Send a virtual one. + if (output->current_mode == NULL) { + // Output doesn't have a fixed mode set. Send a virtual one. head_send_mode(head, head_resource, NULL); } @@ -907,6 +926,15 @@ static bool manager_update_head(struct wlr_output_manager_v1 *manager, } } + if (next->mode == NULL && !head_has_custom_mode_resources(head)) { + struct wl_resource *resource; + wl_resource_for_each(resource, &head->resources) { + head_send_mode(head, resource, NULL); + } + } else if (next->mode != NULL) { + head_destroy_custom_mode_resources(head); + } + if (state != 0) { *current = *next;