aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/config.h9
-rw-r--r--sway/config/output.c296
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
694void apply_all_output_configs(void); 694void apply_all_output_configs(void);
695 695
696struct 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 */
703void store_output_config(struct output_config *oc);
697 704
698struct output_config *find_output_config(struct sway_output *output); 705struct 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
83static 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
82static void merge_output_config(struct output_config *dst, struct output_config *src) { 147static 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
145static void merge_wildcard_on_all(struct output_config *wildcard) { 210void 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
155static 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
202struct 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
249done:
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
246static void set_mode(struct wlr_output *output, struct wlr_output_state *pending, 267static 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
590static 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.
613struct 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
674struct 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
680bool apply_output_configs(struct matched_output_config *configs, 654bool 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));