diff options
Diffstat (limited to 'sway/config.c')
-rw-r--r-- | sway/config.c | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/sway/config.c b/sway/config.c index 89b7d349..c620e4c7 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "sway/input/seat.h" | 24 | #include "sway/input/seat.h" |
25 | #include "sway/commands.h" | 25 | #include "sway/commands.h" |
26 | #include "sway/config.h" | 26 | #include "sway/config.h" |
27 | #include "sway/criteria.h" | ||
27 | #include "sway/tree/arrange.h" | 28 | #include "sway/tree/arrange.h" |
28 | #include "sway/tree/layout.h" | 29 | #include "sway/tree/layout.h" |
29 | #include "sway/tree/workspace.h" | 30 | #include "sway/tree/workspace.h" |
@@ -105,7 +106,12 @@ void free_config(struct sway_config *config) { | |||
105 | } | 106 | } |
106 | list_free(config->seat_configs); | 107 | list_free(config->seat_configs); |
107 | } | 108 | } |
108 | list_free(config->criteria); | 109 | if (config->criteria) { |
110 | for (int i = 0; i < config->criteria->length; ++i) { | ||
111 | criteria_destroy(config->criteria->items[i]); | ||
112 | } | ||
113 | list_free(config->criteria); | ||
114 | } | ||
109 | list_free(config->no_focus); | 115 | list_free(config->no_focus); |
110 | list_free(config->active_bar_modifiers); | 116 | list_free(config->active_bar_modifiers); |
111 | list_free(config->config_chain); | 117 | list_free(config->config_chain); |
@@ -117,6 +123,7 @@ void free_config(struct sway_config *config) { | |||
117 | free(config->floating_scroll_left_cmd); | 123 | free(config->floating_scroll_left_cmd); |
118 | free(config->floating_scroll_right_cmd); | 124 | free(config->floating_scroll_right_cmd); |
119 | free(config->font); | 125 | free(config->font); |
126 | free((char *)config->current_config_path); | ||
120 | free((char *)config->current_config); | 127 | free((char *)config->current_config); |
121 | free(config); | 128 | free(config); |
122 | } | 129 | } |
@@ -205,6 +212,7 @@ static void config_defaults(struct sway_config *config) { | |||
205 | if (!(config->active_bar_modifiers = create_list())) goto cleanup; | 212 | if (!(config->active_bar_modifiers = create_list())) goto cleanup; |
206 | 213 | ||
207 | if (!(config->config_chain = create_list())) goto cleanup; | 214 | if (!(config->config_chain = create_list())) goto cleanup; |
215 | config->current_config_path = NULL; | ||
208 | config->current_config = NULL; | 216 | config->current_config = NULL; |
209 | 217 | ||
210 | // borders | 218 | // borders |
@@ -276,12 +284,12 @@ static char *get_config_path(void) { | |||
276 | char *home = getenv("HOME"); | 284 | char *home = getenv("HOME"); |
277 | char *config_home = malloc(strlen(home) + strlen("/.config") + 1); | 285 | char *config_home = malloc(strlen(home) + strlen("/.config") + 1); |
278 | if (!config_home) { | 286 | if (!config_home) { |
279 | wlr_log(L_ERROR, "Unable to allocate $HOME/.config"); | 287 | wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config"); |
280 | } else { | 288 | } else { |
281 | strcpy(config_home, home); | 289 | strcpy(config_home, home); |
282 | strcat(config_home, "/.config"); | 290 | strcat(config_home, "/.config"); |
283 | setenv("XDG_CONFIG_HOME", config_home, 1); | 291 | setenv("XDG_CONFIG_HOME", config_home, 1); |
284 | wlr_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); | 292 | wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); |
285 | free(config_home); | 293 | free(config_home); |
286 | } | 294 | } |
287 | } | 295 | } |
@@ -304,16 +312,13 @@ static char *get_config_path(void) { | |||
304 | return NULL; // Not reached | 312 | return NULL; // Not reached |
305 | } | 313 | } |
306 | 314 | ||
307 | const char *current_config_path; | ||
308 | |||
309 | static bool load_config(const char *path, struct sway_config *config) { | 315 | static bool load_config(const char *path, struct sway_config *config) { |
310 | if (path == NULL) { | 316 | if (path == NULL) { |
311 | wlr_log(L_ERROR, "Unable to find a config file!"); | 317 | wlr_log(WLR_ERROR, "Unable to find a config file!"); |
312 | return false; | 318 | return false; |
313 | } | 319 | } |
314 | 320 | ||
315 | wlr_log(L_INFO, "Loading config from %s", path); | 321 | wlr_log(WLR_INFO, "Loading config from %s", path); |
316 | current_config_path = path; | ||
317 | 322 | ||
318 | struct stat sb; | 323 | struct stat sb; |
319 | if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { | 324 | if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { |
@@ -322,7 +327,7 @@ static bool load_config(const char *path, struct sway_config *config) { | |||
322 | 327 | ||
323 | FILE *f = fopen(path, "r"); | 328 | FILE *f = fopen(path, "r"); |
324 | if (!f) { | 329 | if (!f) { |
325 | wlr_log(L_ERROR, "Unable to open %s for reading", path); | 330 | wlr_log(WLR_ERROR, "Unable to open %s for reading", path); |
326 | return false; | 331 | return false; |
327 | } | 332 | } |
328 | 333 | ||
@@ -330,10 +335,9 @@ static bool load_config(const char *path, struct sway_config *config) { | |||
330 | fclose(f); | 335 | fclose(f); |
331 | 336 | ||
332 | if (!config_load_success) { | 337 | if (!config_load_success) { |
333 | wlr_log(L_ERROR, "Error(s) loading config!"); | 338 | wlr_log(WLR_ERROR, "Error(s) loading config!"); |
334 | } | 339 | } |
335 | 340 | ||
336 | current_config_path = NULL; | ||
337 | return true; | 341 | return true; |
338 | } | 342 | } |
339 | 343 | ||
@@ -353,12 +357,12 @@ bool load_main_config(const char *file, bool is_active) { | |||
353 | 357 | ||
354 | config_defaults(config); | 358 | config_defaults(config); |
355 | if (is_active) { | 359 | if (is_active) { |
356 | wlr_log(L_DEBUG, "Performing configuration file reload"); | 360 | wlr_log(WLR_DEBUG, "Performing configuration file reload"); |
357 | config->reloading = true; | 361 | config->reloading = true; |
358 | config->active = true; | 362 | config->active = true; |
359 | } | 363 | } |
360 | 364 | ||
361 | config->current_config = path; | 365 | config->current_config_path = path; |
362 | list_add(config->config_chain, path); | 366 | list_add(config->config_chain, path); |
363 | 367 | ||
364 | config->reading = true; | 368 | config->reading = true; |
@@ -369,7 +373,7 @@ bool load_main_config(const char *file, bool is_active) { | |||
369 | /* | 373 | /* |
370 | DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); | 374 | DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); |
371 | if (!dir) { | 375 | if (!dir) { |
372 | wlr_log(L_ERROR, | 376 | wlr_log(WLR_ERROR, |
373 | "%s does not exist, sway will have no security configuration" | 377 | "%s does not exist, sway will have no security configuration" |
374 | " and will probably be broken", SYSCONFDIR "/sway/security.d"); | 378 | " and will probably be broken", SYSCONFDIR "/sway/security.d"); |
375 | } else { | 379 | } else { |
@@ -398,7 +402,7 @@ bool load_main_config(const char *file, bool is_active) { | |||
398 | if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || | 402 | if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || |
399 | (((s.st_mode & 0777) != 0644) && | 403 | (((s.st_mode & 0777) != 0644) && |
400 | (s.st_mode & 0777) != 0444)) { | 404 | (s.st_mode & 0777) != 0444)) { |
401 | wlr_log(L_ERROR, | 405 | wlr_log(WLR_ERROR, |
402 | "Refusing to load %s - it must be owned by root " | 406 | "Refusing to load %s - it must be owned by root " |
403 | "and mode 644 or 444", _path); | 407 | "and mode 644 or 444", _path); |
404 | success = false; | 408 | success = false; |
@@ -428,7 +432,7 @@ bool load_main_config(const char *file, bool is_active) { | |||
428 | static bool load_include_config(const char *path, const char *parent_dir, | 432 | static bool load_include_config(const char *path, const char *parent_dir, |
429 | struct sway_config *config) { | 433 | struct sway_config *config) { |
430 | // save parent config | 434 | // save parent config |
431 | const char *parent_config = config->current_config; | 435 | const char *parent_config = config->current_config_path; |
432 | 436 | ||
433 | char *full_path; | 437 | char *full_path; |
434 | int len = strlen(path); | 438 | int len = strlen(path); |
@@ -436,7 +440,7 @@ static bool load_include_config(const char *path, const char *parent_dir, | |||
436 | len = len + strlen(parent_dir) + 2; | 440 | len = len + strlen(parent_dir) + 2; |
437 | full_path = malloc(len * sizeof(char)); | 441 | full_path = malloc(len * sizeof(char)); |
438 | if (!full_path) { | 442 | if (!full_path) { |
439 | wlr_log(L_ERROR, | 443 | wlr_log(WLR_ERROR, |
440 | "Unable to allocate full path to included config"); | 444 | "Unable to allocate full path to included config"); |
441 | return false; | 445 | return false; |
442 | } | 446 | } |
@@ -449,7 +453,7 @@ static bool load_include_config(const char *path, const char *parent_dir, | |||
449 | free(full_path); | 453 | free(full_path); |
450 | 454 | ||
451 | if (real_path == NULL) { | 455 | if (real_path == NULL) { |
452 | wlr_log(L_DEBUG, "%s not found.", path); | 456 | wlr_log(WLR_DEBUG, "%s not found.", path); |
453 | return false; | 457 | return false; |
454 | } | 458 | } |
455 | 459 | ||
@@ -458,7 +462,7 @@ static bool load_include_config(const char *path, const char *parent_dir, | |||
458 | for (j = 0; j < config->config_chain->length; ++j) { | 462 | for (j = 0; j < config->config_chain->length; ++j) { |
459 | char *old_path = config->config_chain->items[j]; | 463 | char *old_path = config->config_chain->items[j]; |
460 | if (strcmp(real_path, old_path) == 0) { | 464 | if (strcmp(real_path, old_path) == 0) { |
461 | wlr_log(L_DEBUG, | 465 | wlr_log(WLR_DEBUG, |
462 | "%s already included once, won't be included again.", | 466 | "%s already included once, won't be included again.", |
463 | real_path); | 467 | real_path); |
464 | free(real_path); | 468 | free(real_path); |
@@ -466,25 +470,25 @@ static bool load_include_config(const char *path, const char *parent_dir, | |||
466 | } | 470 | } |
467 | } | 471 | } |
468 | 472 | ||
469 | config->current_config = real_path; | 473 | config->current_config_path = real_path; |
470 | list_add(config->config_chain, real_path); | 474 | list_add(config->config_chain, real_path); |
471 | int index = config->config_chain->length - 1; | 475 | int index = config->config_chain->length - 1; |
472 | 476 | ||
473 | if (!load_config(real_path, config)) { | 477 | if (!load_config(real_path, config)) { |
474 | free(real_path); | 478 | free(real_path); |
475 | config->current_config = parent_config; | 479 | config->current_config_path = parent_config; |
476 | list_del(config->config_chain, index); | 480 | list_del(config->config_chain, index); |
477 | return false; | 481 | return false; |
478 | } | 482 | } |
479 | 483 | ||
480 | // restore current_config | 484 | // restore current_config_path |
481 | config->current_config = parent_config; | 485 | config->current_config_path = parent_config; |
482 | return true; | 486 | return true; |
483 | } | 487 | } |
484 | 488 | ||
485 | bool load_include_configs(const char *path, struct sway_config *config) { | 489 | bool load_include_configs(const char *path, struct sway_config *config) { |
486 | char *wd = getcwd(NULL, 0); | 490 | char *wd = getcwd(NULL, 0); |
487 | char *parent_path = strdup(config->current_config); | 491 | char *parent_path = strdup(config->current_config_path); |
488 | const char *parent_dir = dirname(parent_path); | 492 | const char *parent_dir = dirname(parent_path); |
489 | 493 | ||
490 | if (chdir(parent_dir) < 0) { | 494 | if (chdir(parent_dir) < 0) { |
@@ -512,7 +516,7 @@ bool load_include_configs(const char *path, struct sway_config *config) { | |||
512 | // restore wd | 516 | // restore wd |
513 | if (chdir(wd) < 0) { | 517 | if (chdir(wd) < 0) { |
514 | free(wd); | 518 | free(wd); |
515 | wlr_log(L_ERROR, "failed to restore working directory"); | 519 | wlr_log(WLR_ERROR, "failed to restore working directory"); |
516 | return false; | 520 | return false; |
517 | } | 521 | } |
518 | 522 | ||
@@ -527,13 +531,13 @@ static int detect_brace_on_following_line(FILE *file, char *line, | |||
527 | char *peeked = NULL; | 531 | char *peeked = NULL; |
528 | long position = 0; | 532 | long position = 0; |
529 | do { | 533 | do { |
530 | wlr_log(L_DEBUG, "Peeking line %d", line_number + lines + 1); | 534 | wlr_log(WLR_DEBUG, "Peeking line %d", line_number + lines + 1); |
531 | free(peeked); | 535 | free(peeked); |
532 | peeked = peek_line(file, lines, &position); | 536 | peeked = peek_line(file, lines, &position); |
533 | if (peeked) { | 537 | if (peeked) { |
534 | peeked = strip_whitespace(peeked); | 538 | peeked = strip_whitespace(peeked); |
535 | } | 539 | } |
536 | wlr_log(L_DEBUG, "Peeked line: `%s`", peeked); | 540 | wlr_log(WLR_DEBUG, "Peeked line: `%s`", peeked); |
537 | lines++; | 541 | lines++; |
538 | } while (peeked && strlen(peeked) == 0); | 542 | } while (peeked && strlen(peeked) == 0); |
539 | 543 | ||
@@ -552,7 +556,7 @@ static char *expand_line(const char *block, const char *line, bool add_brace) { | |||
552 | + (add_brace ? 2 : 0) + 1; | 556 | + (add_brace ? 2 : 0) + 1; |
553 | char *expanded = calloc(1, size); | 557 | char *expanded = calloc(1, size); |
554 | if (!expanded) { | 558 | if (!expanded) { |
555 | wlr_log(L_ERROR, "Cannot allocate expanded line buffer"); | 559 | wlr_log(WLR_ERROR, "Cannot allocate expanded line buffer"); |
556 | return NULL; | 560 | return NULL; |
557 | } | 561 | } |
558 | snprintf(expanded, size, "%s%s%s%s", block ? block : "", | 562 | snprintf(expanded, size, "%s%s%s%s", block ? block : "", |
@@ -561,10 +565,33 @@ static char *expand_line(const char *block, const char *line, bool add_brace) { | |||
561 | } | 565 | } |
562 | 566 | ||
563 | bool read_config(FILE *file, struct sway_config *config) { | 567 | bool read_config(FILE *file, struct sway_config *config) { |
568 | bool reading_main_config = false; | ||
569 | char *this_config = NULL; | ||
570 | size_t config_size = 0; | ||
571 | if (config->current_config == NULL) { | ||
572 | reading_main_config = true; | ||
573 | |||
574 | int ret_seek = fseek(file, 0, SEEK_END); | ||
575 | long ret_tell = ftell(file); | ||
576 | if (ret_seek == -1 || ret_tell == -1) { | ||
577 | wlr_log(WLR_ERROR, "Unable to get size of config file"); | ||
578 | return false; | ||
579 | } | ||
580 | config_size = ret_tell; | ||
581 | rewind(file); | ||
582 | |||
583 | config->current_config = this_config = calloc(1, config_size + 1); | ||
584 | if (this_config == NULL) { | ||
585 | wlr_log(WLR_ERROR, "Unable to allocate buffer for config contents"); | ||
586 | return false; | ||
587 | } | ||
588 | } | ||
589 | |||
564 | bool success = true; | 590 | bool success = true; |
565 | int line_number = 0; | 591 | int line_number = 0; |
566 | char *line; | 592 | char *line; |
567 | list_t *stack = create_list(); | 593 | list_t *stack = create_list(); |
594 | size_t read = 0; | ||
568 | while (!feof(file)) { | 595 | while (!feof(file)) { |
569 | char *block = stack->length ? stack->items[0] : NULL; | 596 | char *block = stack->length ? stack->items[0] : NULL; |
570 | line = read_line(file); | 597 | line = read_line(file); |
@@ -572,7 +599,26 @@ bool read_config(FILE *file, struct sway_config *config) { | |||
572 | continue; | 599 | continue; |
573 | } | 600 | } |
574 | line_number++; | 601 | line_number++; |
575 | wlr_log(L_DEBUG, "Read line %d: %s", line_number, line); | 602 | wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line); |
603 | |||
604 | if (reading_main_config) { | ||
605 | size_t length = strlen(line); | ||
606 | |||
607 | if (read + length > config_size) { | ||
608 | wlr_log(WLR_ERROR, "Config file changed during reading"); | ||
609 | list_foreach(stack, free); | ||
610 | list_free(stack); | ||
611 | free(line); | ||
612 | return false; | ||
613 | } | ||
614 | |||
615 | strcpy(this_config + read, line); | ||
616 | if (line_number != 1) { | ||
617 | this_config[read - 1] = '\n'; | ||
618 | } | ||
619 | read += length + 1; | ||
620 | } | ||
621 | |||
576 | line = strip_whitespace(line); | 622 | line = strip_whitespace(line); |
577 | if (line[0] == '#') { | 623 | if (line[0] == '#') { |
578 | free(line); | 624 | free(line); |
@@ -586,15 +632,16 @@ bool read_config(FILE *file, struct sway_config *config) { | |||
586 | line_number); | 632 | line_number); |
587 | if (brace_detected > 0) { | 633 | if (brace_detected > 0) { |
588 | line_number += brace_detected; | 634 | line_number += brace_detected; |
589 | wlr_log(L_DEBUG, "Detected open brace on line %d", line_number); | 635 | wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number); |
590 | } | 636 | } |
591 | char *expanded = expand_line(block, line, brace_detected > 0); | 637 | char *expanded = expand_line(block, line, brace_detected > 0); |
592 | if (!expanded) { | 638 | if (!expanded) { |
593 | list_foreach(stack, free); | 639 | list_foreach(stack, free); |
594 | list_free(stack); | 640 | list_free(stack); |
641 | free(line); | ||
595 | return false; | 642 | return false; |
596 | } | 643 | } |
597 | wlr_log(L_DEBUG, "Expanded line: %s", expanded); | 644 | wlr_log(WLR_DEBUG, "Expanded line: %s", expanded); |
598 | struct cmd_results *res; | 645 | struct cmd_results *res; |
599 | if (block && strcmp(block, "<commands>") == 0) { | 646 | if (block && strcmp(block, "<commands>") == 0) { |
600 | // Special case | 647 | // Special case |
@@ -606,23 +653,23 @@ bool read_config(FILE *file, struct sway_config *config) { | |||
606 | switch(res->status) { | 653 | switch(res->status) { |
607 | case CMD_FAILURE: | 654 | case CMD_FAILURE: |
608 | case CMD_INVALID: | 655 | case CMD_INVALID: |
609 | wlr_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, | 656 | wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number, |
610 | line, res->error, config->current_config); | 657 | line, res->error, config->current_config_path); |
611 | success = false; | 658 | success = false; |
612 | break; | 659 | break; |
613 | 660 | ||
614 | case CMD_DEFER: | 661 | case CMD_DEFER: |
615 | wlr_log(L_DEBUG, "Deferring command `%s'", line); | 662 | wlr_log(WLR_DEBUG, "Deferring command `%s'", line); |
616 | list_add(config->cmd_queue, strdup(line)); | 663 | list_add(config->cmd_queue, strdup(line)); |
617 | break; | 664 | break; |
618 | 665 | ||
619 | case CMD_BLOCK_COMMANDS: | 666 | case CMD_BLOCK_COMMANDS: |
620 | wlr_log(L_DEBUG, "Entering commands block"); | 667 | wlr_log(WLR_DEBUG, "Entering commands block"); |
621 | list_insert(stack, 0, "<commands>"); | 668 | list_insert(stack, 0, "<commands>"); |
622 | break; | 669 | break; |
623 | 670 | ||
624 | case CMD_BLOCK: | 671 | case CMD_BLOCK: |
625 | wlr_log(L_DEBUG, "Entering block '%s'", res->input); | 672 | wlr_log(WLR_DEBUG, "Entering block '%s'", res->input); |
626 | list_insert(stack, 0, strdup(res->input)); | 673 | list_insert(stack, 0, strdup(res->input)); |
627 | if (strcmp(res->input, "bar") == 0) { | 674 | if (strcmp(res->input, "bar") == 0) { |
628 | config->current_bar = NULL; | 675 | config->current_bar = NULL; |
@@ -631,7 +678,7 @@ bool read_config(FILE *file, struct sway_config *config) { | |||
631 | 678 | ||
632 | case CMD_BLOCK_END: | 679 | case CMD_BLOCK_END: |
633 | if (!block) { | 680 | if (!block) { |
634 | wlr_log(L_DEBUG, "Unmatched '}' on line %i", line_number); | 681 | wlr_log(WLR_DEBUG, "Unmatched '}' on line %i", line_number); |
635 | success = false; | 682 | success = false; |
636 | break; | 683 | break; |
637 | } | 684 | } |
@@ -639,7 +686,7 @@ bool read_config(FILE *file, struct sway_config *config) { | |||
639 | config->current_bar = NULL; | 686 | config->current_bar = NULL; |
640 | } | 687 | } |
641 | 688 | ||
642 | wlr_log(L_DEBUG, "Exiting block '%s'", block); | 689 | wlr_log(WLR_DEBUG, "Exiting block '%s'", block); |
643 | list_del(stack, 0); | 690 | list_del(stack, 0); |
644 | free(block); | 691 | free(block); |
645 | memset(&config->handler_context, 0, | 692 | memset(&config->handler_context, 0, |
@@ -682,7 +729,7 @@ char *do_var_replacement(char *str) { | |||
682 | int vvlen = strlen(var->value); | 729 | int vvlen = strlen(var->value); |
683 | char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); | 730 | char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); |
684 | if (!newstr) { | 731 | if (!newstr) { |
685 | wlr_log(L_ERROR, | 732 | wlr_log(WLR_ERROR, |
686 | "Unable to allocate replacement " | 733 | "Unable to allocate replacement " |
687 | "during variable expansion"); | 734 | "during variable expansion"); |
688 | break; | 735 | break; |
@@ -744,6 +791,6 @@ void config_update_font_height(bool recalculate) { | |||
744 | } | 791 | } |
745 | 792 | ||
746 | if (config->font_height != prev_max_height) { | 793 | if (config->font_height != prev_max_height) { |
747 | arrange_and_commit(&root_container); | 794 | arrange_windows(&root_container); |
748 | } | 795 | } |
749 | } | 796 | } |