diff options
-rw-r--r-- | include/config.h | 20 | ||||
-rw-r--r-- | sway/commands.c | 17 | ||||
-rw-r--r-- | sway/config.c | 151 | ||||
-rw-r--r-- | sway/main.c | 4 |
4 files changed, 155 insertions, 37 deletions
diff --git a/include/config.h b/include/config.h index 9356140d..4bcf55e8 100644 --- a/include/config.h +++ b/include/config.h | |||
@@ -184,15 +184,27 @@ struct sway_config { | |||
184 | bool smart_gaps; | 184 | bool smart_gaps; |
185 | int gaps_inner; | 185 | int gaps_inner; |
186 | int gaps_outer; | 186 | int gaps_outer; |
187 | |||
188 | list_t *config_chain; | ||
189 | const char *current_config; | ||
187 | }; | 190 | }; |
188 | 191 | ||
189 | /** | 192 | /** |
190 | * Loads the config from the given path. | 193 | * Loads the main config from the given path. is_active should be true when |
194 | * reloading the config. | ||
191 | */ | 195 | */ |
192 | bool load_config(const char *file); | 196 | bool load_main_config(const char *path, bool is_active); |
193 | /** Reads the config from the given FILE. | 197 | |
198 | /** | ||
199 | * Loads an included config. Can only be used after load_main_config. | ||
194 | */ | 200 | */ |
195 | bool read_config(FILE *file, bool is_active); | 201 | bool load_include_configs(const char *path, struct sway_config *config); |
202 | |||
203 | /** | ||
204 | * Reads the config from the given FILE. | ||
205 | */ | ||
206 | bool read_config(FILE *file, struct sway_config *config); | ||
207 | |||
196 | /** | 208 | /** |
197 | * Free config struct | 209 | * Free config struct |
198 | */ | 210 | */ |
diff --git a/sway/commands.c b/sway/commands.c index 26fa771e..bc8c42eb 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -55,6 +55,7 @@ static sway_cmd cmd_font; | |||
55 | static sway_cmd cmd_for_window; | 55 | static sway_cmd cmd_for_window; |
56 | static sway_cmd cmd_fullscreen; | 56 | static sway_cmd cmd_fullscreen; |
57 | static sway_cmd cmd_gaps; | 57 | static sway_cmd cmd_gaps; |
58 | static sway_cmd cmd_include; | ||
58 | static sway_cmd cmd_input; | 59 | static sway_cmd cmd_input; |
59 | static sway_cmd cmd_kill; | 60 | static sway_cmd cmd_kill; |
60 | static sway_cmd cmd_layout; | 61 | static sway_cmd cmd_layout; |
@@ -1141,6 +1142,19 @@ static struct cmd_results *input_cmd_tap(int argc, char **argv) { | |||
1141 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 1142 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
1142 | } | 1143 | } |
1143 | 1144 | ||
1145 | static struct cmd_results *cmd_include(int argc, char **argv) { | ||
1146 | struct cmd_results *error = NULL; | ||
1147 | if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) { | ||
1148 | return error; | ||
1149 | } | ||
1150 | |||
1151 | if (!load_include_configs(argv[0], config)) { | ||
1152 | return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]); | ||
1153 | } | ||
1154 | |||
1155 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1156 | } | ||
1157 | |||
1144 | static struct cmd_results *cmd_input(int argc, char **argv) { | 1158 | static struct cmd_results *cmd_input(int argc, char **argv) { |
1145 | struct cmd_results *error = NULL; | 1159 | struct cmd_results *error = NULL; |
1146 | if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { | 1160 | if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { |
@@ -1541,7 +1555,7 @@ static struct cmd_results *cmd_reload(int argc, char **argv) { | |||
1541 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { | 1555 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { |
1542 | return error; | 1556 | return error; |
1543 | } | 1557 | } |
1544 | if (!load_config(NULL)) return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); | 1558 | if (!load_main_config(NULL, true)) return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); |
1545 | 1559 | ||
1546 | load_swaybars(); | 1560 | load_swaybars(); |
1547 | 1561 | ||
@@ -2053,6 +2067,7 @@ static struct cmd_handler handlers[] = { | |||
2053 | { "for_window", cmd_for_window }, | 2067 | { "for_window", cmd_for_window }, |
2054 | { "fullscreen", cmd_fullscreen }, | 2068 | { "fullscreen", cmd_fullscreen }, |
2055 | { "gaps", cmd_gaps }, | 2069 | { "gaps", cmd_gaps }, |
2070 | { "include", cmd_include }, | ||
2056 | { "input", cmd_input }, | 2071 | { "input", cmd_input }, |
2057 | { "kill", cmd_kill }, | 2072 | { "kill", cmd_kill }, |
2058 | { "layout", cmd_layout }, | 2073 | { "layout", cmd_layout }, |
diff --git a/sway/config.c b/sway/config.c index a5fdf850..d54ce213 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <stdbool.h> | 2 | #include <stdbool.h> |
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <unistd.h> | 4 | #include <unistd.h> |
5 | #include <libgen.h> | ||
5 | #include <wordexp.h> | 6 | #include <wordexp.h> |
6 | #include <sys/types.h> | 7 | #include <sys/types.h> |
7 | #include <sys/wait.h> | 8 | #include <sys/wait.h> |
@@ -126,6 +127,7 @@ void free_config(struct sway_config *config) { | |||
126 | list_free(config->output_configs); | 127 | list_free(config->output_configs); |
127 | 128 | ||
128 | list_free(config->active_bar_modifiers); | 129 | list_free(config->active_bar_modifiers); |
130 | free_flat_list(config->config_chain); | ||
129 | free(config->font); | 131 | free(config->font); |
130 | free(config); | 132 | free(config); |
131 | } | 133 | } |
@@ -175,6 +177,9 @@ static void config_defaults(struct sway_config *config) { | |||
175 | config->gaps_outer = 0; | 177 | config->gaps_outer = 0; |
176 | 178 | ||
177 | config->active_bar_modifiers = create_list(); | 179 | config->active_bar_modifiers = create_list(); |
180 | |||
181 | config->config_chain = create_list(); | ||
182 | config->current_config = NULL; | ||
178 | } | 183 | } |
179 | 184 | ||
180 | static int compare_modifiers(const void *left, const void *right) { | 185 | static int compare_modifiers(const void *left, const void *right) { |
@@ -237,16 +242,7 @@ static char *get_config_path(void) { | |||
237 | return NULL; // Not reached | 242 | return NULL; // Not reached |
238 | } | 243 | } |
239 | 244 | ||
240 | bool load_config(const char *file) { | 245 | static bool load_config(const char *path, struct sway_config *config) { |
241 | input_init(); | ||
242 | |||
243 | char *path; | ||
244 | if (file != NULL) { | ||
245 | path = strdup(file); | ||
246 | } else { | ||
247 | path = get_config_path(); | ||
248 | } | ||
249 | |||
250 | sway_log(L_INFO, "Loading config from %s", path); | 246 | sway_log(L_INFO, "Loading config from %s", path); |
251 | 247 | ||
252 | if (path == NULL) { | 248 | if (path == NULL) { |
@@ -257,20 +253,12 @@ bool load_config(const char *file) { | |||
257 | FILE *f = fopen(path, "r"); | 253 | FILE *f = fopen(path, "r"); |
258 | if (!f) { | 254 | if (!f) { |
259 | sway_log(L_ERROR, "Unable to open %s for reading", path); | 255 | sway_log(L_ERROR, "Unable to open %s for reading", path); |
260 | free(path); | ||
261 | return false; | 256 | return false; |
262 | } | 257 | } |
263 | free(path); | ||
264 | 258 | ||
265 | bool config_load_success; | 259 | bool config_load_success = read_config(f, config); |
266 | if (config) { | ||
267 | config_load_success = read_config(f, true); | ||
268 | } else { | ||
269 | config_load_success = read_config(f, false); | ||
270 | } | ||
271 | fclose(f); | 260 | fclose(f); |
272 | 261 | ||
273 | update_active_bar_modifiers(); | ||
274 | 262 | ||
275 | if (!config_load_success) { | 263 | if (!config_load_success) { |
276 | sway_log(L_ERROR, "Error(s) loading config!"); | 264 | sway_log(L_ERROR, "Error(s) loading config!"); |
@@ -279,17 +267,129 @@ bool load_config(const char *file) { | |||
279 | return true; | 267 | return true; |
280 | } | 268 | } |
281 | 269 | ||
282 | bool read_config(FILE *file, bool is_active) { | 270 | bool load_main_config(const char *file, bool is_active) { |
271 | input_init(); | ||
272 | |||
273 | char *path; | ||
274 | if (file != NULL) { | ||
275 | path = strdup(file); | ||
276 | } else { | ||
277 | path = get_config_path(); | ||
278 | } | ||
279 | |||
283 | struct sway_config *old_config = config; | 280 | struct sway_config *old_config = config; |
284 | config = calloc(1, sizeof(struct sway_config)); | 281 | config = calloc(1, sizeof(struct sway_config)); |
285 | 282 | ||
286 | config_defaults(config); | 283 | config_defaults(config); |
287 | config->reading = true; | ||
288 | if (is_active) { | 284 | if (is_active) { |
289 | sway_log(L_DEBUG, "Performing configuration file reload"); | 285 | sway_log(L_DEBUG, "Performing configuration file reload"); |
290 | config->reloading = true; | 286 | config->reloading = true; |
291 | config->active = true; | 287 | config->active = true; |
292 | } | 288 | } |
289 | |||
290 | config->current_config = path; | ||
291 | list_add(config->config_chain, path); | ||
292 | |||
293 | config->reading = true; | ||
294 | bool success = load_config(path, config); | ||
295 | |||
296 | if (is_active) { | ||
297 | config->reloading = false; | ||
298 | } | ||
299 | |||
300 | if (old_config) { | ||
301 | free_config(old_config); | ||
302 | } | ||
303 | config->reading = false; | ||
304 | |||
305 | if (success) { | ||
306 | update_active_bar_modifiers(); | ||
307 | } | ||
308 | |||
309 | return success; | ||
310 | } | ||
311 | |||
312 | static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { | ||
313 | // save parent config | ||
314 | const char *parent_config = config->current_config; | ||
315 | |||
316 | char *full_path = strdup(path); | ||
317 | int len = strlen(path); | ||
318 | if (len >= 1 && path[0] != '/') { | ||
319 | len = len + strlen(parent_dir) + 2; | ||
320 | full_path = malloc(len * sizeof(char)); | ||
321 | snprintf(full_path, len, "%s/%s", parent_dir, path); | ||
322 | } | ||
323 | |||
324 | char *real_path = realpath(full_path, NULL); | ||
325 | free(full_path); | ||
326 | |||
327 | // check if config has already been included | ||
328 | int j; | ||
329 | for (j = 0; j < config->config_chain->length; ++j) { | ||
330 | char *old_path = config->config_chain->items[j]; | ||
331 | if (strcmp(real_path, old_path) == 0) { | ||
332 | sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); | ||
333 | free(real_path); | ||
334 | return false; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | config->current_config = real_path; | ||
339 | list_add(config->config_chain, real_path); | ||
340 | int index = config->config_chain->length - 1; | ||
341 | |||
342 | if (!load_config(real_path, config)) { | ||
343 | free(real_path); | ||
344 | config->current_config = parent_config; | ||
345 | list_del(config->config_chain, index); | ||
346 | return false; | ||
347 | } | ||
348 | |||
349 | // restore current_config | ||
350 | config->current_config = parent_config; | ||
351 | return true; | ||
352 | } | ||
353 | |||
354 | bool load_include_configs(const char *path, struct sway_config *config) { | ||
355 | char *wd = getcwd(NULL, 0); | ||
356 | char *parent_path = strdup(config->current_config); | ||
357 | const char *parent_dir = dirname(parent_path); | ||
358 | |||
359 | if (chdir(parent_dir) < 0) { | ||
360 | free(parent_path); | ||
361 | free(wd); | ||
362 | return false; | ||
363 | } | ||
364 | |||
365 | wordexp_t p; | ||
366 | |||
367 | if (wordexp(path, &p, 0) < 0) { | ||
368 | free(parent_path); | ||
369 | free(wd); | ||
370 | return false; | ||
371 | } | ||
372 | |||
373 | char **w = p.we_wordv; | ||
374 | size_t i; | ||
375 | for (i = 0; i < p.we_wordc; ++i) { | ||
376 | load_include_config(w[i], parent_dir, config); | ||
377 | } | ||
378 | free(parent_path); | ||
379 | wordfree(&p); | ||
380 | |||
381 | // restore wd | ||
382 | if (chdir(wd) < 0) { | ||
383 | free(wd); | ||
384 | sway_log(L_ERROR, "failed to restore working directory"); | ||
385 | return false; | ||
386 | } | ||
387 | |||
388 | free(wd); | ||
389 | return true; | ||
390 | } | ||
391 | |||
392 | bool read_config(FILE *file, struct sway_config *config) { | ||
293 | bool success = true; | 393 | bool success = true; |
294 | enum cmd_status block = CMD_BLOCK_END; | 394 | enum cmd_status block = CMD_BLOCK_END; |
295 | 395 | ||
@@ -386,15 +486,6 @@ bool read_config(FILE *file, bool is_active) { | |||
386 | free(res); | 486 | free(res); |
387 | } | 487 | } |
388 | 488 | ||
389 | if (is_active) { | ||
390 | config->reloading = false; | ||
391 | arrange_windows(&root_container, -1, -1); | ||
392 | } | ||
393 | if (old_config) { | ||
394 | free_config(old_config); | ||
395 | } | ||
396 | |||
397 | config->reading = false; | ||
398 | return success; | 489 | return success; |
399 | } | 490 | } |
400 | 491 | ||
diff --git a/sway/main.c b/sway/main.c index c4a5d497..4aaac556 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -206,11 +206,11 @@ int main(int argc, char **argv) { | |||
206 | init_layout(); | 206 | init_layout(); |
207 | 207 | ||
208 | if (validate) { | 208 | if (validate) { |
209 | bool valid = load_config(config_path); | 209 | bool valid = load_main_config(config_path, false); |
210 | return valid ? 0 : 1; | 210 | return valid ? 0 : 1; |
211 | } | 211 | } |
212 | 212 | ||
213 | if (!load_config(config_path)) { | 213 | if (!load_main_config(config_path, false)) { |
214 | sway_terminate(EXIT_FAILURE); | 214 | sway_terminate(EXIT_FAILURE); |
215 | } | 215 | } |
216 | 216 | ||