From a9c295fd6709e788d9b12167a53d2f8c031718f0 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Mon, 9 Sep 2024 15:28:22 +0200 Subject: [PATCH] config/output: Accept a list of output_configs to use Instead of using a single finalized output config per output, accept a regular list of output configs like the one ultimately stored for configuration purposes. This allows the output management code to test an augmented configuration while still using the same output config logic, without having to mutate the stored configuration. This in turn allows us to make a few APIs private. A bug note about an existing issue with derade to off is added as well. (cherry picked from 29b3f00e6fd99296cde7e94b7063acfd075c559c) --- include/sway/config.h | 15 ++------ sway/config/output.c | 47 ++++++++++++++++++------- sway/desktop/output.c | 80 ++++++++++++++++--------------------------- 3 files changed, 67 insertions(+), 75 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 2f5a17fa..33cebe2a 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -297,14 +297,6 @@ struct output_config { char *background_fallback; }; -/** - * An output config pre-matched to an output - */ -struct matched_output_config { - struct sway_output *output; - struct output_config *config; -}; - /** * Stores size of gaps for each side */ @@ -694,14 +686,11 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt struct output_config *new_output_config(const char *name); -bool apply_output_configs(struct matched_output_config *configs, - size_t configs_len, bool test_only, bool degrade_to_off); +bool apply_output_configs(struct output_config **ocs, size_t ocs_len, + bool test_only, bool degrade_to_off); void apply_all_output_configs(void); -void sort_output_configs_by_priority(struct matched_output_config *configs, - size_t configs_len); - /** * store_output_config stores a new output config. An output may be matched by * three different config types, in order of precedence: Identifier, name and diff --git a/sway/config/output.c b/sway/config/output.c index b182f4b4..60718bf0 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -593,9 +593,11 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output return true; } -// find_output_config returns a merged output_config containing all stored -// configuration that applies to the specified output. -struct output_config *find_output_config(struct sway_output *sway_output) { +// find_output_config_from_list returns a merged output_config containing all +// stored configuration that applies to the specified output. +static struct output_config *find_output_config_from_list( + struct output_config **configs, size_t configs_len, + struct sway_output *sway_output) { const char *name = sway_output->wlr_output->name; struct output_config *result = new_output_config(name); if (result == NULL) { @@ -620,8 +622,8 @@ struct output_config *find_output_config(struct sway_output *sway_output) { struct output_config *oc = NULL; const char *names[] = {"*", name, id, NULL}; for (const char **name = &names[0]; *name; name++) { - for (int idx = 0; idx < config->output_configs->length; idx++) { - oc = config->output_configs->items[idx]; + for (size_t idx = 0; idx < configs_len; idx++) { + oc = configs[idx]; if (strcmp(oc->name, *name) == 0) { merge_output_config(result, oc); } @@ -631,6 +633,12 @@ struct output_config *find_output_config(struct sway_output *sway_output) { return result; } +struct output_config *find_output_config(struct sway_output *sway_output) { + return find_output_config_from_list( + (struct output_config **)config->output_configs->items, + config->output_configs->length, sway_output); +} + static bool config_has_manual_mode(struct output_config *oc) { if (!oc) { return false; @@ -643,6 +651,14 @@ static bool config_has_manual_mode(struct output_config *oc) { return false; } +/** + * An output config pre-matched to an output + */ +struct matched_output_config { + struct sway_output *output; + struct output_config *config; +}; + struct search_context { struct wlr_output_swapchain_manager *swapchain_mgr; struct wlr_backend_output_state *states; @@ -869,12 +885,12 @@ static int compare_matched_output_config_priority(const void *a, const void *b) return 0; } -void sort_output_configs_by_priority(struct matched_output_config *configs, - size_t configs_len) { +static void sort_output_configs_by_priority( + struct matched_output_config *configs, size_t configs_len) { qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority); } -bool apply_output_configs(struct matched_output_config *configs, +static bool apply_resolved_output_configs(struct matched_output_config *configs, size_t configs_len, bool test_only, bool degrade_to_off) { struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); if (!states) { @@ -982,11 +998,12 @@ out: return ok; } -void apply_all_output_configs(void) { +bool apply_output_configs(struct output_config **ocs, size_t ocs_len, + bool test_only, bool degrade_to_off) { size_t configs_len = wl_list_length(&root->all_outputs); struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); if (!configs) { - return; + return false; } int config_idx = 0; @@ -999,16 +1016,22 @@ void apply_all_output_configs(void) { struct matched_output_config *config = &configs[config_idx++]; config->output = sway_output; - config->config = find_output_config(sway_output); + config->config = find_output_config_from_list(ocs, ocs_len, sway_output); } sort_output_configs_by_priority(configs, configs_len); - apply_output_configs(configs, configs_len, false, true); + bool ok = apply_resolved_output_configs(configs, configs_len, test_only, degrade_to_off); for (size_t idx = 0; idx < configs_len; idx++) { struct matched_output_config *cfg = &configs[idx]; free_output_config(cfg->config); } free(configs); + return ok; +} + +void apply_all_output_configs(void) { + apply_output_configs((struct output_config **)config->output_configs->items, + config->output_configs->length, false, true); } void free_output_config(struct output_config *oc) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 67ea6c29..1fd2f693 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -594,9 +594,8 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { } static struct output_config *output_config_for_config_head( - struct wlr_output_configuration_head_v1 *config_head, - struct sway_output *output) { - struct output_config *oc = new_output_config(output->wlr_output->name); + struct wlr_output_configuration_head_v1 *config_head) { + struct output_config *oc = new_output_config(config_head->state.output->name); oc->enabled = config_head->state.enabled; if (!oc->enabled) { return oc; @@ -622,67 +621,48 @@ static struct output_config *output_config_for_config_head( } static void output_manager_apply(struct sway_server *server, - struct wlr_output_configuration_v1 *config, bool test_only) { - size_t configs_len = wl_list_length(&root->all_outputs); - struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); + struct wlr_output_configuration_v1 *cfg, bool test_only) { + bool ok = false; + size_t configs_len = config->output_configs->length + wl_list_length(&cfg->heads); + struct output_config **configs = calloc(configs_len, sizeof(*configs)); if (!configs) { - return; + goto done; + } + size_t start_new_configs = config->output_configs->length; + for (size_t idx = 0; idx < start_new_configs; idx++) { + configs[idx] = config->output_configs->items[idx]; } - int config_idx = 0; - struct sway_output *sway_output; - wl_list_for_each(sway_output, &root->all_outputs, link) { - if (sway_output == root->fallback_output) { - configs_len--; - continue; - } - - struct matched_output_config *cfg = &configs[config_idx++]; - cfg->output = sway_output; - - struct wlr_output_configuration_head_v1 *config_head; - wl_list_for_each(config_head, &config->heads, link) { - if (config_head->state.output == sway_output->wlr_output) { - cfg->config = output_config_for_config_head(config_head, sway_output); - break; - } - } - if (!cfg->config) { - cfg->config = find_output_config(sway_output); - } + size_t config_idx = start_new_configs; + struct wlr_output_configuration_head_v1 *config_head; + wl_list_for_each(config_head, &cfg->heads, link) { + // Generate the configuration and store it as a temporary + // config. We keep a record of it so we can remove it later. + struct output_config *oc = output_config_for_config_head(config_head); + configs[config_idx++] = oc; } - sort_output_configs_by_priority(configs, configs_len); - bool ok = apply_output_configs(configs, configs_len, test_only, false); - for (size_t idx = 0; idx < configs_len; idx++) { - struct matched_output_config *cfg = &configs[idx]; - - // Only store new configs for successful non-test commits. Old configs, - // test-only and failed commits just get freed. - bool store_config = false; + // Try to commit without degrade to off enabled. Note that this will fail + // if any output configured for enablement fails to be enabled, even if it + // was not part of the config heads we were asked to configure. + ok = apply_output_configs(configs, configs_len, test_only, false); + for (size_t idx = start_new_configs; idx < configs_len; idx++) { + struct output_config *cfg = configs[idx]; if (!test_only && ok) { - struct wlr_output_configuration_head_v1 *config_head; - wl_list_for_each(config_head, &config->heads, link) { - if (config_head->state.output == cfg->output->wlr_output) { - store_config = true; - break; - } - } - } - if (store_config) { - store_output_config(cfg->config); + store_output_config(cfg); } else { - free_output_config(cfg->config); + free_output_config(cfg); } } free(configs); +done: if (ok) { - wlr_output_configuration_v1_send_succeeded(config); + wlr_output_configuration_v1_send_succeeded(cfg); } else { - wlr_output_configuration_v1_send_failed(config); + wlr_output_configuration_v1_send_failed(cfg); } - wlr_output_configuration_v1_destroy(config); + wlr_output_configuration_v1_destroy(cfg); } void handle_output_manager_apply(struct wl_listener *listener, void *data) {