aboutsummaryrefslogtreecommitdiffstats
path: root/sway/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/config.c')
-rw-r--r--sway/config.c223
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 @@
39struct sway_config *config = NULL; 33struct sway_config *config = NULL;
40 34
41static void free_mode(struct sway_mode *mode) { 35static 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
348static bool load_config(const char *path, struct sway_config *config, 335static 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
584static int detect_brace_on_following_line(FILE *file, char *line, 576// get line, with backslash continuation
585 int line_number) { 577static 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] == '{') { 605static 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
609static char *expand_line(const char *block, const char *line, bool add_brace) { 628static 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
778void 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
765char *do_var_replacement(char *str) { 802char *do_var_replacement(char *str) {
766 int i; 803 int i;
767 char *find = str; 804 char *find = str;