diff options
-rw-r--r-- | include/sway/config.h | 9 | ||||
-rw-r--r-- | sway/config/output.c | 296 |
2 files changed, 143 insertions, 162 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index 40710199..0be1cd22 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -693,7 +693,14 @@ bool apply_output_configs(struct matched_output_config *configs, | |||
693 | 693 | ||
694 | void apply_all_output_configs(void); | 694 | void apply_all_output_configs(void); |
695 | 695 | ||
696 | struct output_config *store_output_config(struct output_config *oc); | 696 | /** |
697 | * store_output_config stores a new output config. An output may be matched by | ||
698 | * three different config types, in order of precedence: Identifier, name and | ||
699 | * wildcard. When storing a config type of lower precedence, assume that the | ||
700 | * user wants the config to take immediate effect by superseding (clearing) the | ||
701 | * same values from higher presedence configuration. | ||
702 | */ | ||
703 | void store_output_config(struct output_config *oc); | ||
697 | 704 | ||
698 | struct output_config *find_output_config(struct sway_output *output); | 705 | struct output_config *find_output_config(struct sway_output *output); |
699 | 706 | ||
diff --git a/sway/config/output.c b/sway/config/output.c index 3f1c3126..e5ff240a 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -79,6 +79,71 @@ struct output_config *new_output_config(const char *name) { | |||
79 | return oc; | 79 | return oc; |
80 | } | 80 | } |
81 | 81 | ||
82 | // supersede_output_config clears all fields in dst that were set in src | ||
83 | static void supersede_output_config(struct output_config *dst, struct output_config *src) { | ||
84 | if (src->enabled != -1) { | ||
85 | dst->enabled = -1; | ||
86 | } | ||
87 | if (src->width != -1) { | ||
88 | dst->width = -1; | ||
89 | } | ||
90 | if (src->height != -1) { | ||
91 | dst->height = -1; | ||
92 | } | ||
93 | if (src->x != -1) { | ||
94 | dst->x = -1; | ||
95 | } | ||
96 | if (src->y != -1) { | ||
97 | dst->y = -1; | ||
98 | } | ||
99 | if (src->scale != -1) { | ||
100 | dst->scale = -1; | ||
101 | } | ||
102 | if (src->scale_filter != SCALE_FILTER_DEFAULT) { | ||
103 | dst->scale_filter = SCALE_FILTER_DEFAULT; | ||
104 | } | ||
105 | if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) { | ||
106 | dst->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; | ||
107 | } | ||
108 | if (src->refresh_rate != -1) { | ||
109 | dst->refresh_rate = -1; | ||
110 | } | ||
111 | if (src->custom_mode != -1) { | ||
112 | dst->custom_mode = -1; | ||
113 | } | ||
114 | if (src->drm_mode.type != (uint32_t) -1) { | ||
115 | dst->drm_mode.type = -1; | ||
116 | } | ||
117 | if (src->transform != -1) { | ||
118 | dst->transform = -1; | ||
119 | } | ||
120 | if (src->max_render_time != -1) { | ||
121 | dst->max_render_time = -1; | ||
122 | } | ||
123 | if (src->adaptive_sync != -1) { | ||
124 | dst->adaptive_sync = -1; | ||
125 | } | ||
126 | if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { | ||
127 | dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; | ||
128 | } | ||
129 | if (src->background) { | ||
130 | free(dst->background); | ||
131 | dst->background = NULL; | ||
132 | } | ||
133 | if (src->background_option) { | ||
134 | free(dst->background_option); | ||
135 | dst->background_option = NULL; | ||
136 | } | ||
137 | if (src->background_fallback) { | ||
138 | free(dst->background_fallback); | ||
139 | dst->background_fallback = NULL; | ||
140 | } | ||
141 | if (src->power != -1) { | ||
142 | dst->power = -1; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // merge_output_config sets all fields in dst that were set in src | ||
82 | static void merge_output_config(struct output_config *dst, struct output_config *src) { | 147 | static void merge_output_config(struct output_config *dst, struct output_config *src) { |
83 | if (src->enabled != -1) { | 148 | if (src->enabled != -1) { |
84 | dst->enabled = src->enabled; | 149 | dst->enabled = src->enabled; |
@@ -142,96 +207,46 @@ static void merge_output_config(struct output_config *dst, struct output_config | |||
142 | } | 207 | } |
143 | } | 208 | } |
144 | 209 | ||
145 | static void merge_wildcard_on_all(struct output_config *wildcard) { | 210 | void store_output_config(struct output_config *oc) { |
146 | for (int i = 0; i < config->output_configs->length; i++) { | 211 | bool merged = false; |
147 | struct output_config *oc = config->output_configs->items[i]; | 212 | bool wildcard = strcmp(oc->name, "*") == 0; |
148 | if (strcmp(wildcard->name, oc->name) != 0) { | 213 | struct sway_output *output = wildcard ? NULL : output_by_name_or_id(oc->name); |
149 | sway_log(SWAY_DEBUG, "Merging output * config on %s", oc->name); | 214 | if (!output && !wildcard) { |
150 | merge_output_config(oc, wildcard); | 215 | // There is no config by this name, just add it in |
151 | } | 216 | goto done; |
152 | } | ||
153 | } | ||
154 | |||
155 | static void merge_id_on_name(struct output_config *oc) { | ||
156 | struct sway_output *output = all_output_by_name_or_id(oc->name); | ||
157 | if (output == NULL) { | ||
158 | return; | ||
159 | } | 217 | } |
160 | 218 | ||
161 | const char *name = output->wlr_output->name; | ||
162 | char id[128]; | 219 | char id[128]; |
163 | output_get_identifier(id, sizeof(id), output); | 220 | output_get_identifier(id, sizeof(id), output); |
164 | 221 | for (int i = 0; i < config->output_configs->length; i++) { | |
165 | char *id_on_name = format_str("%s on %s", id, name); | 222 | struct output_config *old = config->output_configs->items[i]; |
166 | if (!id_on_name) { | 223 | |
167 | return; | 224 | // If the old config matches the new config's name, regardless of |
168 | } | 225 | // whether it was name or identifier, merge on top of the existing |
169 | 226 | // config. If the new config is a wildcard, this also merges on top of | |
170 | int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); | 227 | // old wildcard configs. |
171 | if (i >= 0) { | 228 | if (strcmp(old->name, oc->name) == 0) { |
172 | sway_log(SWAY_DEBUG, "Merging on top of existing id on name config"); | 229 | merge_output_config(old, oc); |
173 | merge_output_config(config->output_configs->items[i], oc); | 230 | merged = true; |
174 | } else { | 231 | continue; |
175 | // If both a name and identifier config, exist generate an id on name | ||
176 | int ni = list_seq_find(config->output_configs, output_name_cmp, name); | ||
177 | int ii = list_seq_find(config->output_configs, output_name_cmp, id); | ||
178 | if ((ni >= 0 && ii >= 0) || (ni >= 0 && strcmp(oc->name, id) == 0) | ||
179 | || (ii >= 0 && strcmp(oc->name, name) == 0)) { | ||
180 | struct output_config *ion_oc = new_output_config(id_on_name); | ||
181 | if (ni >= 0) { | ||
182 | merge_output_config(ion_oc, config->output_configs->items[ni]); | ||
183 | } | ||
184 | if (ii >= 0) { | ||
185 | merge_output_config(ion_oc, config->output_configs->items[ii]); | ||
186 | } | ||
187 | merge_output_config(ion_oc, oc); | ||
188 | list_add(config->output_configs, ion_oc); | ||
189 | sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\"" | ||
190 | " (enabled: %d) (%dx%d@%fHz position %d,%d scale %f " | ||
191 | "transform %d) (bg %s %s) (power %d) (max render time: %d)", | ||
192 | ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height, | ||
193 | ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale, | ||
194 | ion_oc->transform, ion_oc->background, | ||
195 | ion_oc->background_option, ion_oc->power, | ||
196 | ion_oc->max_render_time); | ||
197 | } | 232 | } |
198 | } | ||
199 | free(id_on_name); | ||
200 | } | ||
201 | 233 | ||
202 | struct output_config *store_output_config(struct output_config *oc) { | 234 | // If the new config is a wildcard config we supersede all non-wildcard |
203 | bool wildcard = strcmp(oc->name, "*") == 0; | 235 | // configs. Old wildcard configs have already been handled above. |
204 | if (wildcard) { | 236 | if (wildcard) { |
205 | merge_wildcard_on_all(oc); | 237 | supersede_output_config(old, oc); |
206 | } else { | 238 | continue; |
207 | merge_id_on_name(oc); | 239 | } |
208 | } | ||
209 | 240 | ||
210 | int i = list_seq_find(config->output_configs, output_name_cmp, oc->name); | 241 | // If the new config matches an output's name, and the old config |
211 | if (i >= 0) { | 242 | // matches on that output's identifier, supersede it. |
212 | sway_log(SWAY_DEBUG, "Merging on top of existing output config"); | 243 | if (strcmp(old->name, id) == 0 && |
213 | struct output_config *current = config->output_configs->items[i]; | 244 | strcmp(oc->name, output->wlr_output->name) == 0) { |
214 | merge_output_config(current, oc); | 245 | supersede_output_config(old, oc); |
215 | free_output_config(oc); | ||
216 | oc = current; | ||
217 | } else if (!wildcard) { | ||
218 | sway_log(SWAY_DEBUG, "Adding non-wildcard output config"); | ||
219 | i = list_seq_find(config->output_configs, output_name_cmp, "*"); | ||
220 | if (i >= 0) { | ||
221 | sway_log(SWAY_DEBUG, "Merging on top of output * config"); | ||
222 | struct output_config *current = new_output_config(oc->name); | ||
223 | merge_output_config(current, config->output_configs->items[i]); | ||
224 | merge_output_config(current, oc); | ||
225 | free_output_config(oc); | ||
226 | oc = current; | ||
227 | } | 246 | } |
228 | list_add(config->output_configs, oc); | ||
229 | } else { | ||
230 | // New wildcard config. Just add it | ||
231 | sway_log(SWAY_DEBUG, "Adding output * config"); | ||
232 | list_add(config->output_configs, oc); | ||
233 | } | 247 | } |
234 | 248 | ||
249 | done: | ||
235 | sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " | 250 | sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " |
236 | "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) " | 251 | "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) " |
237 | "(max render time: %d)", | 252 | "(max render time: %d)", |
@@ -240,7 +255,13 @@ struct output_config *store_output_config(struct output_config *oc) { | |||
240 | oc->transform, oc->background, oc->background_option, oc->power, | 255 | oc->transform, oc->background, oc->background_option, oc->power, |
241 | oc->max_render_time); | 256 | oc->max_render_time); |
242 | 257 | ||
243 | return oc; | 258 | // If the configuration was not merged into an existing configuration, add |
259 | // it to the list. Otherwise we're done with it and can free it. | ||
260 | if (!merged) { | ||
261 | list_add(config->output_configs, oc); | ||
262 | } else { | ||
263 | free_output_config(oc); | ||
264 | } | ||
244 | } | 265 | } |
245 | 266 | ||
246 | static void set_mode(struct wlr_output *output, struct wlr_output_state *pending, | 267 | static void set_mode(struct wlr_output *output, struct wlr_output_state *pending, |
@@ -587,96 +608,49 @@ static void default_output_config(struct output_config *oc, | |||
587 | oc->max_render_time = 0; | 608 | oc->max_render_time = 0; |
588 | } | 609 | } |
589 | 610 | ||
590 | static struct output_config *get_output_config(char *identifier, | 611 | // find_output_config returns a merged output_config containing all stored |
591 | struct sway_output *sway_output) { | 612 | // configuration that applies to the specified output. |
613 | struct output_config *find_output_config(struct sway_output *sway_output) { | ||
592 | const char *name = sway_output->wlr_output->name; | 614 | const char *name = sway_output->wlr_output->name; |
615 | struct output_config *oc = NULL; | ||
593 | 616 | ||
594 | struct output_config *oc_id_on_name = NULL; | 617 | struct output_config *result = new_output_config(name); |
595 | struct output_config *oc_name = NULL; | ||
596 | struct output_config *oc_id = NULL; | ||
597 | |||
598 | char *id_on_name = format_str("%s on %s", identifier, name); | ||
599 | int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); | ||
600 | if (i >= 0) { | ||
601 | oc_id_on_name = config->output_configs->items[i]; | ||
602 | } else { | ||
603 | i = list_seq_find(config->output_configs, output_name_cmp, name); | ||
604 | if (i >= 0) { | ||
605 | oc_name = config->output_configs->items[i]; | ||
606 | } | ||
607 | |||
608 | i = list_seq_find(config->output_configs, output_name_cmp, identifier); | ||
609 | if (i >= 0) { | ||
610 | oc_id = config->output_configs->items[i]; | ||
611 | } | ||
612 | } | ||
613 | |||
614 | struct output_config *result = new_output_config("temp"); | ||
615 | if (config->reloading) { | 618 | if (config->reloading) { |
616 | default_output_config(result, sway_output->wlr_output); | 619 | default_output_config(result, sway_output->wlr_output); |
617 | } | 620 | } |
618 | if (oc_id_on_name) { | 621 | |
619 | // Already have an identifier on name config, use that | 622 | char id[128]; |
620 | free(result->name); | 623 | output_get_identifier(id, sizeof(id), sway_output); |
621 | result->name = strdup(id_on_name); | 624 | |
622 | merge_output_config(result, oc_id_on_name); | 625 | int i; |
623 | } else if (oc_name && oc_id) { | 626 | bool match = false; |
624 | // Generate a config named `<identifier> on <name>` which contains a | 627 | if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) { |
625 | // merged copy of the identifier on name. This will make sure that both | 628 | match = true; |
626 | // identifier and name configs are respected, with identifier getting | 629 | oc = config->output_configs->items[i]; |
627 | // priority | 630 | merge_output_config(result, oc); |
628 | struct output_config *temp = new_output_config(id_on_name); | 631 | } |
629 | merge_output_config(temp, oc_name); | 632 | if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) { |
630 | merge_output_config(temp, oc_id); | 633 | match = true; |
631 | list_add(config->output_configs, temp); | 634 | oc = config->output_configs->items[i]; |
632 | 635 | merge_output_config(result, oc); | |
633 | free(result->name); | 636 | } |
634 | result->name = strdup(id_on_name); | 637 | if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) { |
635 | merge_output_config(result, temp); | 638 | match = true; |
636 | 639 | oc = config->output_configs->items[i]; | |
637 | sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)" | 640 | merge_output_config(result, oc); |
638 | " (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)" | 641 | } |
639 | " (power %d) (max render time: %d)", result->name, result->enabled, | 642 | |
640 | result->width, result->height, result->refresh_rate, | 643 | if (!match && !config->reloading) { |
641 | result->x, result->y, result->scale, result->transform, | 644 | // No name, identifier, or wildcard config. Since we are not |
642 | result->background, result->background_option, result->power, | 645 | // reloading with defaults, the output config will be empty, so |
643 | result->max_render_time); | 646 | // just return NULL |
644 | } else if (oc_name) { | 647 | free_output_config(result); |
645 | // No identifier config, just return a copy of the name config | 648 | return NULL; |
646 | free(result->name); | ||
647 | result->name = strdup(name); | ||
648 | merge_output_config(result, oc_name); | ||
649 | } else if (oc_id) { | ||
650 | // No name config, just return a copy of the identifier config | ||
651 | free(result->name); | ||
652 | result->name = strdup(identifier); | ||
653 | merge_output_config(result, oc_id); | ||
654 | } else { | ||
655 | i = list_seq_find(config->output_configs, output_name_cmp, "*"); | ||
656 | if (i >= 0) { | ||
657 | // No name or identifier config, but there is a wildcard config | ||
658 | free(result->name); | ||
659 | result->name = strdup("*"); | ||
660 | merge_output_config(result, config->output_configs->items[i]); | ||
661 | } else if (!config->reloading) { | ||
662 | // No name, identifier, or wildcard config. Since we are not | ||
663 | // reloading with defaults, the output config will be empty, so | ||
664 | // just return NULL | ||
665 | free_output_config(result); | ||
666 | result = NULL; | ||
667 | } | ||
668 | } | 649 | } |
669 | 650 | ||
670 | free(id_on_name); | ||
671 | return result; | 651 | return result; |
672 | } | 652 | } |
673 | 653 | ||
674 | struct output_config *find_output_config(struct sway_output *output) { | ||
675 | char id[128]; | ||
676 | output_get_identifier(id, sizeof(id), output); | ||
677 | return get_output_config(id, output); | ||
678 | } | ||
679 | |||
680 | bool apply_output_configs(struct matched_output_config *configs, | 654 | bool apply_output_configs(struct matched_output_config *configs, |
681 | size_t configs_len, bool test_only) { | 655 | size_t configs_len, bool test_only) { |
682 | struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); | 656 | struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); |