desktop/output: Use temporary configs for output_manager

The current logic created a new output_config for each output according
to config_head posted by an output managing client. These configurations
would then be attempted applied, and if successful, be stored as active
configuration.

However, some of the state tested depend on fields not set by the output
manager. If 'output * power off' is in effect, and an output manager
enables a config_head, then the expected result is that power off is
respected and outputs remain off, but becuase only the config_head
configuration is considered, the output is powered on. The configuration
when stored is then no longer consistent with the current state.

Instead of trying to handle merging configurations and appropriate
precedence within the output manager, simply store the configuration
temporarily and apply all output configurations. If the result is
successful, we remove the temporary configuration and add it
permanently.
This commit is contained in:
Kenny Levinsen 2024-09-05 18:24:01 +02:00
parent fe1cbfaf08
commit 9092e0f755

View file

@ -544,9 +544,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
} }
static struct output_config *output_config_for_config_head( static struct output_config *output_config_for_config_head(
struct wlr_output_configuration_head_v1 *config_head, struct wlr_output_configuration_head_v1 *config_head) {
struct sway_output *output) { struct output_config *oc = new_output_config(config_head->state.output->name);
struct output_config *oc = new_output_config(output->wlr_output->name);
oc->enabled = config_head->state.enabled; oc->enabled = config_head->state.enabled;
if (!oc->enabled) { if (!oc->enabled) {
return oc; return oc;
@ -573,56 +572,31 @@ static struct output_config *output_config_for_config_head(
static void output_manager_apply(struct sway_server *server, static void output_manager_apply(struct sway_server *server,
struct wlr_output_configuration_v1 *config, bool test_only) { struct wlr_output_configuration_v1 *config, bool test_only) {
size_t configs_len = wl_list_length(&root->all_outputs); size_t configs_len = wl_list_length(&config->heads);
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs)); struct output_config **configs = calloc(configs_len, sizeof(*configs));
if (!configs) { if (!configs) {
return; return;
} }
int config_idx = 0; int config_idx = 0;
struct sway_output *sway_output; struct wlr_output_configuration_head_v1 *config_head;
wl_list_for_each(sway_output, &root->all_outputs, link) { wl_list_for_each(config_head, &config->heads, link) {
if (sway_output == root->fallback_output) { // Generate the configuration and store it as a temporary
configs_len--; // config. We keep a record of it so we can remove it later.
continue; struct output_config *oc = output_config_for_config_head(config_head);
} store_temp_output_config(oc);
configs[config_idx++] = oc;
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);
}
} }
configs_len = config_idx;
sort_output_configs_by_priority(configs, configs_len); bool ok = apply_all_output_configs(test_only, false);
bool ok = apply_output_configs(configs, configs_len, test_only, false);
for (size_t idx = 0; idx < configs_len; idx++) { for (size_t idx = 0; idx < configs_len; idx++) {
struct matched_output_config *cfg = &configs[idx]; struct output_config *cfg = configs[idx];
remove_temp_output_config(cfg);
// Only store new configs for successful non-test commits. Old configs,
// test-only and failed commits just get freed.
bool store_config = false;
if (!test_only && ok) { if (!test_only && ok) {
struct wlr_output_configuration_head_v1 *config_head; store_output_config(cfg);
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);
} else { } else {
free_output_config(cfg->config); free_output_config(cfg);
} }
} }
free(configs); free(configs);