diff options
Diffstat (limited to 'sway/config.c')
-rw-r--r-- | sway/config.c | 223 |
1 files changed, 130 insertions, 93 deletions
diff --git a/sway/config.c b/sway/config.c index 6f65d0c2..18fee404 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _XOPEN_SOURCE 700 // for realpath |
2 | #define _XOPEN_SOURCE 700 | ||
3 | #include <stdio.h> | 2 | #include <stdio.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
5 | #include <stdlib.h> | 4 | #include <stdlib.h> |
@@ -14,11 +13,7 @@ | |||
14 | #include <limits.h> | 13 | #include <limits.h> |
15 | #include <dirent.h> | 14 | #include <dirent.h> |
16 | #include <strings.h> | 15 | #include <strings.h> |
17 | #ifdef __linux__ | ||
18 | #include <linux/input-event-codes.h> | 16 | #include <linux/input-event-codes.h> |
19 | #elif __FreeBSD__ | ||
20 | #include <dev/evdev/input-event-codes.h> | ||
21 | #endif | ||
22 | #include <wlr/types/wlr_output.h> | 17 | #include <wlr/types/wlr_output.h> |
23 | #include "sway/input/input-manager.h" | 18 | #include "sway/input/input-manager.h" |
24 | #include "sway/input/seat.h" | 19 | #include "sway/input/seat.h" |
@@ -31,7 +26,6 @@ | |||
31 | #include "sway/tree/workspace.h" | 26 | #include "sway/tree/workspace.h" |
32 | #include "cairo.h" | 27 | #include "cairo.h" |
33 | #include "pango.h" | 28 | #include "pango.h" |
34 | #include "readline.h" | ||
35 | #include "stringop.h" | 29 | #include "stringop.h" |
36 | #include "list.h" | 30 | #include "list.h" |
37 | #include "log.h" | 31 | #include "log.h" |
@@ -39,26 +33,24 @@ | |||
39 | struct sway_config *config = NULL; | 33 | struct sway_config *config = NULL; |
40 | 34 | ||
41 | static void free_mode(struct sway_mode *mode) { | 35 | static void free_mode(struct sway_mode *mode) { |
42 | int i; | ||
43 | |||
44 | if (!mode) { | 36 | if (!mode) { |
45 | return; | 37 | return; |
46 | } | 38 | } |
47 | free(mode->name); | 39 | free(mode->name); |
48 | if (mode->keysym_bindings) { | 40 | if (mode->keysym_bindings) { |
49 | for (i = 0; i < mode->keysym_bindings->length; i++) { | 41 | for (int i = 0; i < mode->keysym_bindings->length; i++) { |
50 | free_sway_binding(mode->keysym_bindings->items[i]); | 42 | free_sway_binding(mode->keysym_bindings->items[i]); |
51 | } | 43 | } |
52 | list_free(mode->keysym_bindings); | 44 | list_free(mode->keysym_bindings); |
53 | } | 45 | } |
54 | if (mode->keycode_bindings) { | 46 | if (mode->keycode_bindings) { |
55 | for (i = 0; i < mode->keycode_bindings->length; i++) { | 47 | for (int i = 0; i < mode->keycode_bindings->length; i++) { |
56 | free_sway_binding(mode->keycode_bindings->items[i]); | 48 | free_sway_binding(mode->keycode_bindings->items[i]); |
57 | } | 49 | } |
58 | list_free(mode->keycode_bindings); | 50 | list_free(mode->keycode_bindings); |
59 | } | 51 | } |
60 | if (mode->mouse_bindings) { | 52 | if (mode->mouse_bindings) { |
61 | for (i = 0; i < mode->mouse_bindings->length; i++) { | 53 | for (int i = 0; i < mode->mouse_bindings->length; i++) { |
62 | free_sway_binding(mode->mouse_bindings->items[i]); | 54 | free_sway_binding(mode->mouse_bindings->items[i]); |
63 | } | 55 | } |
64 | list_free(mode->mouse_bindings); | 56 | list_free(mode->mouse_bindings); |
@@ -214,6 +206,10 @@ static void config_defaults(struct sway_config *config) { | |||
214 | config->popup_during_fullscreen = POPUP_SMART; | 206 | config->popup_during_fullscreen = POPUP_SMART; |
215 | config->xwayland = true; | 207 | config->xwayland = true; |
216 | 208 | ||
209 | config->titlebar_border_thickness = 1; | ||
210 | config->titlebar_h_padding = 5; | ||
211 | config->titlebar_v_padding = 4; | ||
212 | |||
217 | // floating view | 213 | // floating view |
218 | config->floating_maximum_width = 0; | 214 | config->floating_maximum_width = 0; |
219 | config->floating_maximum_height = 0; | 215 | config->floating_maximum_height = 0; |
@@ -231,7 +227,9 @@ static void config_defaults(struct sway_config *config) { | |||
231 | config->auto_back_and_forth = false; | 227 | config->auto_back_and_forth = false; |
232 | config->reading = false; | 228 | config->reading = false; |
233 | config->show_marks = true; | 229 | config->show_marks = true; |
230 | config->title_align = ALIGN_LEFT; | ||
234 | config->tiling_drag = true; | 231 | config->tiling_drag = true; |
232 | config->tiling_drag_threshold = 9; | ||
235 | 233 | ||
236 | config->smart_gaps = false; | 234 | config->smart_gaps = false; |
237 | config->gaps_inner = 0; | 235 | config->gaps_inner = 0; |
@@ -313,27 +311,16 @@ static char *get_config_path(void) { | |||
313 | SYSCONFDIR "/i3/config", | 311 | SYSCONFDIR "/i3/config", |
314 | }; | 312 | }; |
315 | 313 | ||
316 | if (!getenv("XDG_CONFIG_HOME")) { | 314 | char *config_home = getenv("XDG_CONFIG_HOME"); |
317 | char *home = getenv("HOME"); | 315 | if (!config_home || !*config_home) { |
318 | char *config_home = malloc(strlen(home) + strlen("/.config") + 1); | 316 | config_paths[1] = "$HOME/.config/sway/config"; |
319 | if (!config_home) { | 317 | config_paths[3] = "$HOME/.config/i3/config"; |
320 | wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config"); | ||
321 | } else { | ||
322 | strcpy(config_home, home); | ||
323 | strcat(config_home, "/.config"); | ||
324 | setenv("XDG_CONFIG_HOME", config_home, 1); | ||
325 | wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); | ||
326 | free(config_home); | ||
327 | } | ||
328 | } | 318 | } |
329 | 319 | ||
330 | wordexp_t p; | 320 | for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) { |
331 | char *path; | 321 | wordexp_t p; |
332 | 322 | if (wordexp(config_paths[i], &p, WRDE_UNDEF) == 0) { | |
333 | int i; | 323 | char *path = strdup(p.we_wordv[0]); |
334 | for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) { | ||
335 | if (wordexp(config_paths[i], &p, 0) == 0) { | ||
336 | path = strdup(p.we_wordv[0]); | ||
337 | wordfree(&p); | 324 | wordfree(&p); |
338 | if (file_exists(path)) { | 325 | if (file_exists(path)) { |
339 | return path; | 326 | return path; |
@@ -342,7 +329,7 @@ static char *get_config_path(void) { | |||
342 | } | 329 | } |
343 | } | 330 | } |
344 | 331 | ||
345 | return NULL; // Not reached | 332 | return NULL; |
346 | } | 333 | } |
347 | 334 | ||
348 | static bool load_config(const char *path, struct sway_config *config, | 335 | static bool load_config(const char *path, struct sway_config *config, |
@@ -402,7 +389,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
402 | &old_config->swaynag_config_errors, | 389 | &old_config->swaynag_config_errors, |
403 | sizeof(struct swaynag_instance)); | 390 | sizeof(struct swaynag_instance)); |
404 | 391 | ||
405 | create_default_output_configs(); | 392 | input_manager_reset_all_inputs(); |
406 | } | 393 | } |
407 | 394 | ||
408 | config->current_config_path = path; | 395 | config->current_config_path = path; |
@@ -454,7 +441,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
454 | } | 441 | } |
455 | } | 442 | } |
456 | 443 | ||
457 | free_flat_list(secconfigs); | 444 | list_free_items_and_destroy(secconfigs); |
458 | } | 445 | } |
459 | */ | 446 | */ |
460 | 447 | ||
@@ -475,6 +462,11 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
475 | if (config->swaynag_config_errors.pid > 0) { | 462 | if (config->swaynag_config_errors.pid > 0) { |
476 | swaynag_show(&config->swaynag_config_errors); | 463 | swaynag_show(&config->swaynag_config_errors); |
477 | } | 464 | } |
465 | |||
466 | input_manager_verify_fallback_seat(); | ||
467 | for (int i = 0; i < config->seat_configs->length; i++) { | ||
468 | input_manager_apply_seat_config(config->seat_configs->items[i]); | ||
469 | } | ||
478 | } | 470 | } |
479 | 471 | ||
480 | if (old_config) { | 472 | if (old_config) { |
@@ -581,29 +573,56 @@ bool load_include_configs(const char *path, struct sway_config *config, | |||
581 | return true; | 573 | return true; |
582 | } | 574 | } |
583 | 575 | ||
584 | static int detect_brace_on_following_line(FILE *file, char *line, | 576 | // get line, with backslash continuation |
585 | int line_number) { | 577 | static ssize_t getline_with_cont(char **lineptr, size_t *line_size, FILE *file, |
586 | int lines = 0; | 578 | int *nlines) { |
587 | if (line[strlen(line) - 1] != '{' && line[strlen(line) - 1] != '}') { | 579 | char *next_line = NULL; |
588 | char *peeked = NULL; | 580 | size_t next_line_size = 0; |
589 | long position = 0; | 581 | ssize_t nread = getline(lineptr, line_size, file); |
590 | do { | 582 | *nlines = nread == -1 ? 0 : 1; |
591 | free(peeked); | 583 | while (nread >= 2 && strcmp(&(*lineptr)[nread - 2], "\\\n") == 0) { |
592 | peeked = peek_line(file, lines, &position); | 584 | ssize_t next_nread = getline(&next_line, &next_line_size, file); |
593 | if (peeked) { | 585 | if (next_nread == -1) { |
594 | peeked = strip_whitespace(peeked); | 586 | break; |
587 | } | ||
588 | (*nlines)++; | ||
589 | |||
590 | nread += next_nread - 2; | ||
591 | if ((ssize_t) *line_size < nread + 1) { | ||
592 | *line_size = nread + 1; | ||
593 | *lineptr = realloc(*lineptr, *line_size); | ||
594 | if (!*lineptr) { | ||
595 | nread = -1; | ||
596 | break; | ||
595 | } | 597 | } |
596 | lines++; | 598 | } |
597 | } while (peeked && strlen(peeked) == 0); | 599 | strcpy(&(*lineptr)[nread - next_nread], next_line); |
600 | } | ||
601 | free(next_line); | ||
602 | return nread; | ||
603 | } | ||
598 | 604 | ||
599 | if (peeked && strlen(peeked) == 1 && peeked[0] == '{') { | 605 | static int detect_brace(FILE *file) { |
600 | fseek(file, position, SEEK_SET); | 606 | int ret = 0; |
601 | } else { | 607 | int lines = 0; |
602 | lines = 0; | 608 | long pos = ftell(file); |
609 | char *line = NULL; | ||
610 | size_t line_size = 0; | ||
611 | while ((getline(&line, &line_size, file)) != -1) { | ||
612 | lines++; | ||
613 | strip_whitespace(line); | ||
614 | if (*line) { | ||
615 | if (strcmp(line, "{") == 0) { | ||
616 | ret = lines; | ||
617 | } | ||
618 | break; | ||
603 | } | 619 | } |
604 | free(peeked); | ||
605 | } | 620 | } |
606 | return lines; | 621 | free(line); |
622 | if (ret == 0) { | ||
623 | fseek(file, pos, SEEK_SET); | ||
624 | } | ||
625 | return ret; | ||
607 | } | 626 | } |
608 | 627 | ||
609 | static char *expand_line(const char *block, const char *line, bool add_brace) { | 628 | static char *expand_line(const char *block, const char *line, bool add_brace) { |
@@ -645,58 +664,51 @@ bool read_config(FILE *file, struct sway_config *config, | |||
645 | 664 | ||
646 | bool success = true; | 665 | bool success = true; |
647 | int line_number = 0; | 666 | int line_number = 0; |
648 | char *line; | 667 | char *line = NULL; |
668 | size_t line_size = 0; | ||
669 | ssize_t nread; | ||
649 | list_t *stack = create_list(); | 670 | list_t *stack = create_list(); |
650 | size_t read = 0; | 671 | size_t read = 0; |
651 | while (!feof(file)) { | 672 | int nlines = 0; |
652 | char *block = stack->length ? stack->items[0] : NULL; | 673 | while ((nread = getline_with_cont(&line, &line_size, file, &nlines)) != -1) { |
653 | line = read_line(file); | ||
654 | if (!line) { | ||
655 | continue; | ||
656 | } | ||
657 | line_number++; | ||
658 | wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line); | ||
659 | |||
660 | if (reading_main_config) { | 674 | if (reading_main_config) { |
661 | size_t length = strlen(line); | 675 | if (read + nread > config_size) { |
662 | |||
663 | if (read + length > config_size) { | ||
664 | wlr_log(WLR_ERROR, "Config file changed during reading"); | 676 | wlr_log(WLR_ERROR, "Config file changed during reading"); |
665 | list_foreach(stack, free); | 677 | success = false; |
666 | list_free(stack); | 678 | break; |
667 | free(line); | ||
668 | return false; | ||
669 | } | 679 | } |
670 | 680 | ||
671 | strcpy(this_config + read, line); | 681 | strcpy(&this_config[read], line); |
672 | if (line_number != 1) { | 682 | read += nread; |
673 | this_config[read - 1] = '\n'; | ||
674 | } | ||
675 | read += length + 1; | ||
676 | } | 683 | } |
677 | 684 | ||
678 | line = strip_whitespace(line); | 685 | if (line[nread - 1] == '\n') { |
679 | if (line[0] == '#') { | 686 | line[nread - 1] = '\0'; |
680 | free(line); | ||
681 | continue; | ||
682 | } | 687 | } |
683 | if (strlen(line) == 0) { | 688 | |
684 | free(line); | 689 | line_number += nlines; |
690 | wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line); | ||
691 | |||
692 | strip_whitespace(line); | ||
693 | if (!*line || line[0] == '#') { | ||
685 | continue; | 694 | continue; |
686 | } | 695 | } |
687 | int brace_detected = detect_brace_on_following_line(file, line, | 696 | int brace_detected = 0; |
688 | line_number); | 697 | if (line[strlen(line) - 1] != '{' && line[strlen(line) - 1] != '}') { |
689 | if (brace_detected > 0) { | 698 | brace_detected = detect_brace(file); |
690 | line_number += brace_detected; | 699 | if (brace_detected > 0) { |
691 | wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number); | 700 | line_number += brace_detected; |
701 | wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number); | ||
702 | } | ||
692 | } | 703 | } |
704 | char *block = stack->length ? stack->items[0] : NULL; | ||
693 | char *expanded = expand_line(block, line, brace_detected > 0); | 705 | char *expanded = expand_line(block, line, brace_detected > 0); |
694 | if (!expanded) { | 706 | if (!expanded) { |
695 | list_foreach(stack, free); | 707 | success = false; |
696 | list_free(stack); | 708 | break; |
697 | free(line); | ||
698 | return false; | ||
699 | } | 709 | } |
710 | config->current_config_line_number = line_number; | ||
711 | config->current_config_line = line; | ||
700 | struct cmd_results *res; | 712 | struct cmd_results *res; |
701 | if (block && strcmp(block, "<commands>") == 0) { | 713 | if (block && strcmp(block, "<commands>") == 0) { |
702 | // Special case | 714 | // Special case |
@@ -753,15 +765,40 @@ bool read_config(FILE *file, struct sway_config *config, | |||
753 | default:; | 765 | default:; |
754 | } | 766 | } |
755 | free(expanded); | 767 | free(expanded); |
756 | free(line); | ||
757 | free_cmd_results(res); | 768 | free_cmd_results(res); |
758 | } | 769 | } |
759 | list_foreach(stack, free); | 770 | free(line); |
760 | list_free(stack); | 771 | list_free_items_and_destroy(stack); |
772 | config->current_config_line_number = 0; | ||
773 | config->current_config_line = NULL; | ||
761 | 774 | ||
762 | return success; | 775 | return success; |
763 | } | 776 | } |
764 | 777 | ||
778 | void config_add_swaynag_warning(char *fmt, ...) { | ||
779 | if (config->reading && !config->validating) { | ||
780 | va_list args; | ||
781 | va_start(args, fmt); | ||
782 | size_t length = vsnprintf(NULL, 0, fmt, args) + 1; | ||
783 | va_end(args); | ||
784 | |||
785 | char *temp = malloc(length + 1); | ||
786 | if (!temp) { | ||
787 | wlr_log(WLR_ERROR, "Failed to allocate buffer for warning."); | ||
788 | return; | ||
789 | } | ||
790 | |||
791 | va_start(args, fmt); | ||
792 | vsnprintf(temp, length, fmt, args); | ||
793 | va_end(args); | ||
794 | |||
795 | swaynag_log(config->swaynag_command, &config->swaynag_config_errors, | ||
796 | "Warning on line %i (%s) '%s': %s", | ||
797 | config->current_config_line_number, config->current_config_path, | ||
798 | config->current_config_line, temp); | ||
799 | } | ||
800 | } | ||
801 | |||
765 | char *do_var_replacement(char *str) { | 802 | char *do_var_replacement(char *str) { |
766 | int i; | 803 | int i; |
767 | char *find = str; | 804 | char *find = str; |