Skip to content

Commit 725783a

Browse files
committed
config/output: Store output configs sequentially
The current output configuration system merges configurations such that only one configuration per match is stored. This is a simplification of a previous design and has the benefit that a minimal number of output configurations are retained, but to correctly merge and supersede configurations it is required that an identifier can be resolved from a connector, which leads to differences in how output configurations are interpreted based on whether a display is currently connected or not. Instead, append all new output configurations to the list. To mitigate unbounded growth, supersede old configurations that are an exact match by clearing the fiels that can no longer take effect. Once a particular output configuration no longer contains any set fields, remove it from the list. Based on work by Pedro Côrte-Real <pedro@pedrocr.net> in #5629 which targeted an older iteration of the output configuration system.
1 parent a950429 commit 725783a

File tree

1 file changed

+55
-52
lines changed

1 file changed

+55
-52
lines changed

sway/config/output.c

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,30 @@ struct output_config *new_output_config(const char *name) {
8282
return oc;
8383
}
8484

85+
static bool empty_output_config(struct output_config *oc) {
86+
return oc->enabled == -1 &&
87+
oc->width == -1 &&
88+
oc->height == -1 &&
89+
oc->x == INT_MAX &&
90+
oc->y == INT_MAX &&
91+
oc->scale == -1 &&
92+
oc->scale_filter == SCALE_FILTER_DEFAULT &&
93+
oc->subpixel == WL_OUTPUT_SUBPIXEL_UNKNOWN &&
94+
oc->refresh_rate == -1 &&
95+
oc->custom_mode == -1 &&
96+
oc->drm_mode.type == (uint32_t)-1 &&
97+
oc->transform == -1 &&
98+
oc->max_render_time == -1 &&
99+
oc->adaptive_sync == -1 &&
100+
oc->render_bit_depth == RENDER_BIT_DEPTH_DEFAULT &&
101+
oc->set_color_transform == false &&
102+
oc->background == NULL &&
103+
oc->background_option == NULL &&
104+
oc->background_fallback == NULL &&
105+
oc->power == -1 &&
106+
oc->allow_tearing == -1;
107+
}
108+
85109
// supersede_output_config clears all fields in dst that were set in src
86110
static void supersede_output_config(struct output_config *dst, struct output_config *src) {
87111
if (src->enabled != -1) {
@@ -232,57 +256,37 @@ static void merge_output_config(struct output_config *dst, struct output_config
232256
}
233257

234258
void store_output_config(struct output_config *oc) {
235-
bool merged = false;
236259
bool wildcard = strcmp(oc->name, "*") == 0;
237-
struct sway_output *output = wildcard ? NULL : all_output_by_name_or_id(oc->name);
238-
239-
char id[128];
240-
if (output) {
241-
output_get_identifier(id, sizeof(id), output);
242-
}
243-
244-
for (int i = 0; i < config->output_configs->length; i++) {
245-
struct output_config *old = config->output_configs->items[i];
246-
247-
// If the old config matches the new config's name, regardless of
248-
// whether it was name or identifier, merge on top of the existing
249-
// config. If the new config is a wildcard, this also merges on top of
250-
// old wildcard configs.
251-
if (strcmp(old->name, oc->name) == 0) {
252-
merge_output_config(old, oc);
253-
merged = true;
254-
continue;
255-
}
256-
257-
// If the new config is a wildcard config we supersede all non-wildcard
258-
// configs. Old wildcard configs have already been handled above.
259-
if (wildcard) {
260-
supersede_output_config(old, oc);
261-
continue;
262-
}
263260

264-
// If the new config matches an output's name, and the old config
265-
// matches on that output's identifier, supersede it.
266-
if (output && strcmp(old->name, id) == 0 &&
267-
strcmp(oc->name, output->wlr_output->name) == 0) {
261+
// Supersede any existing configurations that match by clearing settings
262+
// that can no longer be reached anyway, which allows us to later garbage
263+
// collect configurations that no longer have any value
264+
struct output_config *old;
265+
for (int idx = 0; idx < config->output_configs->length; idx++) {
266+
old = config->output_configs->items[idx];
267+
if (wildcard || strcmp(old->name, oc->name) == 0) {
268268
supersede_output_config(old, oc);
269269
}
270270
}
271271

272-
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
273-
"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
274-
"(max render time: %d) (allow tearing: %d)",
275-
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
276-
oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
277-
oc->transform, oc->background, oc->background_option, oc->power,
278-
oc->max_render_time, oc->allow_tearing);
279-
280-
// If the configuration was not merged into an existing configuration, add
281-
// it to the list. Otherwise we're done with it and can free it.
282-
if (!merged) {
283-
list_add(config->output_configs, oc);
284-
} else {
272+
// As a very minor optimization, if the last config is for the same name,
273+
// we can merge with that instead of adding a new config, reducing the
274+
// number of configs when sequentially changing different settings
275+
if (old != NULL && strcmp(old->name, oc->name) == 0) {
276+
merge_output_config(old, oc);
285277
free_output_config(oc);
278+
} else {
279+
list_add(config->output_configs, oc);
280+
}
281+
282+
// Remove any configurations that have had all their settings removed
283+
for (int idx = 0; idx < config->output_configs->length; idx++) {
284+
old = config->output_configs->items[idx];
285+
if (empty_output_config(old)) {
286+
list_del(config->output_configs, idx);
287+
free_output_config(old);
288+
idx--;
289+
}
286290
}
287291
}
288292

@@ -588,14 +592,13 @@ static struct output_config *find_output_config_from_list(
588592
char id[128];
589593
output_get_identifier(id, sizeof(id), sway_output);
590594

591-
// We take a new config and merge on top, in order, the wildcard config,
592-
// output config by name, and output config by identifier to form the final
593-
// config. If there are multiple matches, they are merged in order.
594-
struct output_config *oc = NULL;
595-
const char *names[] = {"*", name, id, NULL};
596-
for (const char **name = &names[0]; *name; name++) {
597-
for (size_t idx = 0; idx < configs_len; idx++) {
598-
oc = configs[idx];
595+
// To create the output config for this output, we merge all configurations
596+
// that match the output in the order they were stored, such that later
597+
// configurations override earlier ones
598+
for (size_t idx = 0; idx < configs_len; idx++) {
599+
struct output_config *oc = configs[idx];
600+
const char *names[] = {"*", name, id, NULL};
601+
for (const char **name = &names[0]; *name; name++) {
599602
if (strcmp(oc->name, *name) == 0) {
600603
merge_output_config(result, oc);
601604
}

0 commit comments

Comments
 (0)