parent
							
								
									83b4c0648d
								
							
						
					
					
						commit
						90f7f1a0e6
					
				| @ -0,0 +1,405 @@ | ||||
| #ifndef _SWAY_CONFIG_H | ||||
| #define _SWAY_CONFIG_H | ||||
| 
 | ||||
| #define PID_WORKSPACE_TIMEOUT 60 | ||||
| 
 | ||||
| #include <libinput.h> | ||||
| #include <stdint.h> | ||||
| #include <wlc/geometry.h> | ||||
| #include <wlc/wlc.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <time.h> | ||||
| #include "list.h" | ||||
| #include "layout.h" | ||||
| #include "container.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * Describes a variable created via the `set` command. | ||||
|  */ | ||||
| struct sway_variable { | ||||
| 	char *name; | ||||
| 	char *value; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * A key binding and an associated command. | ||||
|  */ | ||||
| struct sway_binding { | ||||
| 	int order; | ||||
| 	bool release; | ||||
| 	bool bindcode; | ||||
| 	list_t *keys; | ||||
| 	uint32_t modifiers; | ||||
| 	char *command; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * A mouse binding and an associated command. | ||||
|  */ | ||||
| struct sway_mouse_binding { | ||||
| 	uint32_t button; | ||||
| 	char *command; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * A "mode" of keybindings created via the `mode` command. | ||||
|  */ | ||||
| struct sway_mode { | ||||
| 	char *name; | ||||
| 	list_t *bindings; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * libinput options for input devices | ||||
|  */ | ||||
| struct input_config { | ||||
| 	char *identifier; | ||||
| 
 | ||||
| 	int accel_profile; | ||||
| 	int click_method; | ||||
| 	int drag_lock; | ||||
| 	int dwt; | ||||
| 	int left_handed; | ||||
| 	int middle_emulation; | ||||
| 	int natural_scroll; | ||||
| 	float pointer_accel; | ||||
| 	int scroll_method; | ||||
| 	int send_events; | ||||
| 	int tap; | ||||
| 
 | ||||
| 	bool capturable; | ||||
| 	struct wlc_geometry region; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Size and position configuration for a particular output. | ||||
|  * | ||||
|  * This is set via the `output` command. | ||||
|  */ | ||||
| struct output_config { | ||||
| 	char *name; | ||||
| 	int enabled; | ||||
| 	int width, height; | ||||
| 	int x, y; | ||||
| 	int scale; | ||||
| 	char *background; | ||||
| 	char *background_option; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * Maps a workspace name to an output name. | ||||
|  * | ||||
|  * Set via `workspace <x> output <y>` | ||||
|  */ | ||||
| struct workspace_output { | ||||
| 	char *output; | ||||
| 	char *workspace; | ||||
| }; | ||||
| 
 | ||||
| struct pid_workspace { | ||||
| 	pid_t *pid; | ||||
| 	char *workspace; | ||||
| 	time_t *time_added; | ||||
| }; | ||||
| 
 | ||||
| struct bar_config { | ||||
| 	/**
 | ||||
| 	 * One of "dock", "hide", "invisible" | ||||
| 	 * | ||||
| 	 * Always visible in dock mode. Visible only when modifier key is held in hide mode. | ||||
| 	 * Never visible in invisible mode. | ||||
| 	 */ | ||||
| 	char *mode; | ||||
| 	/**
 | ||||
| 	 * One of "show" or "hide". | ||||
| 	 * | ||||
| 	 * In "show" mode, it will always be shown on top of the active workspace. | ||||
| 	 */ | ||||
| 	char *hidden_state; | ||||
| 	/**
 | ||||
| 	 * Id name used to identify the bar through IPC. | ||||
| 	 * | ||||
| 	 * Defaults to bar-x, where x corresponds to the position of the | ||||
| 	 * embedding bar block in the config file (bar-0, bar-1, ...). | ||||
| 	 */ | ||||
| 	char *id; | ||||
| 	uint32_t modifier; | ||||
| 	list_t *outputs; | ||||
| 	//enum desktop_shell_panel_position position; // TODO
 | ||||
| 	list_t *bindings; | ||||
| 	char *status_command; | ||||
| 	bool pango_markup; | ||||
| 	char *swaybar_command; | ||||
| 	char *font; | ||||
| 	int height; // -1 not defined
 | ||||
| 
 | ||||
| #ifdef ENABLE_TRAY | ||||
| 	// Tray
 | ||||
| 	char *tray_output; | ||||
| 	char *icon_theme; | ||||
| 	uint32_t tray_padding; | ||||
| 	uint32_t activate_button; | ||||
| 	uint32_t context_button; | ||||
| 	uint32_t secondary_button; | ||||
| #endif | ||||
| 
 | ||||
| 	bool workspace_buttons; | ||||
| 	bool wrap_scroll; | ||||
| 	char *separator_symbol; | ||||
| 	bool strip_workspace_numbers; | ||||
| 	bool binding_mode_indicator; | ||||
| 	bool verbose; | ||||
| 	pid_t pid; | ||||
| 	struct { | ||||
| 		char *background; | ||||
| 		char *statusline; | ||||
| 		char *separator; | ||||
| 		char *focused_background; | ||||
| 		char *focused_statusline; | ||||
| 		char *focused_separator; | ||||
| 		char *focused_workspace_border; | ||||
| 		char *focused_workspace_bg; | ||||
| 		char *focused_workspace_text; | ||||
| 		char *active_workspace_border; | ||||
| 		char *active_workspace_bg; | ||||
| 		char *active_workspace_text; | ||||
| 		char *inactive_workspace_border; | ||||
| 		char *inactive_workspace_bg; | ||||
| 		char *inactive_workspace_text; | ||||
| 		char *urgent_workspace_border; | ||||
| 		char *urgent_workspace_bg; | ||||
| 		char *urgent_workspace_text; | ||||
| 		char *binding_mode_border; | ||||
| 		char *binding_mode_bg; | ||||
| 		char *binding_mode_text; | ||||
| 	} colors; | ||||
| }; | ||||
| 
 | ||||
| struct border_colors { | ||||
| 	uint32_t border; | ||||
| 	uint32_t background; | ||||
| 	uint32_t text; | ||||
| 	uint32_t indicator; | ||||
| 	uint32_t child_border; | ||||
| }; | ||||
| 
 | ||||
| enum edge_border_types { | ||||
| 	E_NONE,         /**< Don't hide edge borders */ | ||||
| 	E_VERTICAL,     /**< hide vertical edge borders */ | ||||
| 	E_HORIZONTAL,   /**< hide horizontal edge borders */ | ||||
| 	E_BOTH,		/**< hide vertical and horizontal edge borders */ | ||||
| 	E_SMART		/**< hide both if precisely one window is present in workspace */ | ||||
| }; | ||||
| 
 | ||||
| enum command_context { | ||||
| 	CONTEXT_CONFIG = 1, | ||||
| 	CONTEXT_BINDING = 2, | ||||
| 	CONTEXT_IPC = 4, | ||||
| 	CONTEXT_CRITERIA = 8, | ||||
| 	CONTEXT_ALL = 0xFFFFFFFF, | ||||
| }; | ||||
| 
 | ||||
| struct command_policy { | ||||
| 	char *command; | ||||
| 	uint32_t context; | ||||
| }; | ||||
| 
 | ||||
| enum secure_feature { | ||||
| 	FEATURE_LOCK = 1, | ||||
| 	FEATURE_PANEL = 2, | ||||
| 	FEATURE_BACKGROUND = 4, | ||||
| 	FEATURE_SCREENSHOT = 8, | ||||
| 	FEATURE_FULLSCREEN = 16, | ||||
| 	FEATURE_KEYBOARD = 32, | ||||
| 	FEATURE_MOUSE = 64, | ||||
| }; | ||||
| 
 | ||||
| struct feature_policy { | ||||
| 	char *program; | ||||
| 	uint32_t features; | ||||
| }; | ||||
| 
 | ||||
| enum ipc_feature { | ||||
| 	IPC_FEATURE_COMMAND = 1, | ||||
| 	IPC_FEATURE_GET_WORKSPACES = 2, | ||||
| 	IPC_FEATURE_GET_OUTPUTS = 4, | ||||
| 	IPC_FEATURE_GET_TREE = 8, | ||||
| 	IPC_FEATURE_GET_MARKS = 16, | ||||
| 	IPC_FEATURE_GET_BAR_CONFIG = 32, | ||||
| 	IPC_FEATURE_GET_VERSION = 64, | ||||
| 	IPC_FEATURE_GET_INPUTS = 128, | ||||
| 	IPC_FEATURE_EVENT_WORKSPACE = 256, | ||||
| 	IPC_FEATURE_EVENT_OUTPUT = 512, | ||||
| 	IPC_FEATURE_EVENT_MODE = 1024, | ||||
| 	IPC_FEATURE_EVENT_WINDOW = 2048, | ||||
| 	IPC_FEATURE_EVENT_BINDING = 4096, | ||||
| 	IPC_FEATURE_EVENT_INPUT = 8192, | ||||
| 	IPC_FEATURE_GET_CLIPBOARD = 16384, | ||||
| 
 | ||||
| 	IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, | ||||
| 	IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, | ||||
| 
 | ||||
| 	IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, | ||||
| }; | ||||
| 
 | ||||
| struct ipc_policy { | ||||
| 	char *program; | ||||
| 	uint32_t features; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * The configuration struct. The result of loading a config file. | ||||
|  */ | ||||
| struct sway_config { | ||||
| 	list_t *symbols; | ||||
| 	list_t *modes; | ||||
| 	list_t *bars; | ||||
| 	list_t *cmd_queue; | ||||
| 	list_t *workspace_outputs; | ||||
| 	list_t *pid_workspaces; | ||||
| 	list_t *output_configs; | ||||
| 	list_t *input_configs; | ||||
| 	list_t *criteria; | ||||
| 	list_t *no_focus; | ||||
| 	list_t *active_bar_modifiers; | ||||
| 	struct sway_mode *current_mode; | ||||
| 	struct bar_config *current_bar; | ||||
| 	uint32_t floating_mod; | ||||
| 	uint32_t dragging_key; | ||||
| 	uint32_t resizing_key; | ||||
| 	char *floating_scroll_up_cmd; | ||||
| 	char *floating_scroll_down_cmd; | ||||
| 	char *floating_scroll_left_cmd; | ||||
| 	char *floating_scroll_right_cmd; | ||||
| 	enum swayc_layouts default_orientation; | ||||
| 	enum swayc_layouts default_layout; | ||||
| 	char *font; | ||||
| 	int font_height; | ||||
| 
 | ||||
| 	// Flags
 | ||||
| 	bool focus_follows_mouse; | ||||
| 	bool mouse_warping; | ||||
| 	bool force_focus_wrapping; | ||||
| 	bool active; | ||||
| 	bool failed; | ||||
| 	bool reloading; | ||||
| 	bool reading; | ||||
| 	bool auto_back_and_forth; | ||||
| 	bool seamless_mouse; | ||||
| 	bool show_marks; | ||||
| 
 | ||||
| 	bool edge_gaps; | ||||
| 	bool smart_gaps; | ||||
| 	int gaps_inner; | ||||
| 	int gaps_outer; | ||||
| 
 | ||||
| 	list_t *config_chain; | ||||
| 	const char *current_config; | ||||
| 
 | ||||
| 	enum swayc_border_types border; | ||||
| 	enum swayc_border_types floating_border; | ||||
| 	int border_thickness; | ||||
| 	int floating_border_thickness; | ||||
| 	enum edge_border_types hide_edge_borders; | ||||
| 
 | ||||
| 	// border colors
 | ||||
| 	struct { | ||||
| 		struct border_colors focused; | ||||
| 		struct border_colors focused_inactive; | ||||
| 		struct border_colors unfocused; | ||||
| 		struct border_colors urgent; | ||||
| 		struct border_colors placeholder; | ||||
| 		uint32_t background; | ||||
| 	} border_colors; | ||||
| 
 | ||||
| 	// floating view
 | ||||
| 	int32_t floating_maximum_width; | ||||
| 	int32_t floating_maximum_height; | ||||
| 	int32_t floating_minimum_width; | ||||
| 	int32_t floating_minimum_height; | ||||
| 
 | ||||
| 	// Security
 | ||||
| 	list_t *command_policies; | ||||
| 	list_t *feature_policies; | ||||
| 	list_t *ipc_policies; | ||||
| }; | ||||
| 
 | ||||
| void pid_workspace_add(struct pid_workspace *pw); | ||||
| void free_pid_workspace(struct pid_workspace *pw); | ||||
| 
 | ||||
| /**
 | ||||
|  * Loads the main config from the given path. is_active should be true when | ||||
|  * reloading the config. | ||||
|  */ | ||||
| bool load_main_config(const char *path, bool is_active); | ||||
| 
 | ||||
| /**
 | ||||
|  * Loads an included config. Can only be used after load_main_config. | ||||
|  */ | ||||
| bool load_include_configs(const char *path, struct sway_config *config); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reads the config from the given FILE. | ||||
|  */ | ||||
| bool read_config(FILE *file, struct sway_config *config); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free config struct | ||||
|  */ | ||||
| void free_config(struct sway_config *config); | ||||
| /**
 | ||||
|  * Does variable replacement for a string based on the config's currently loaded variables. | ||||
|  */ | ||||
| char *do_var_replacement(char *str); | ||||
| 
 | ||||
| struct cmd_results *check_security_config(); | ||||
| 
 | ||||
| int input_identifier_cmp(const void *item, const void *data); | ||||
| void merge_input_config(struct input_config *dst, struct input_config *src); | ||||
| void apply_input_config(struct input_config *ic, struct libinput_device *dev); | ||||
| void free_input_config(struct input_config *ic); | ||||
| 
 | ||||
| int output_name_cmp(const void *item, const void *data); | ||||
| void merge_output_config(struct output_config *dst, struct output_config *src); | ||||
| /** Sets up a WLC output handle based on a given output_config.
 | ||||
|  */ | ||||
| void apply_output_config(struct output_config *oc, swayc_t *output); | ||||
| void free_output_config(struct output_config *oc); | ||||
| 
 | ||||
| /**
 | ||||
|  * Updates the list of active bar modifiers | ||||
|  */ | ||||
| void update_active_bar_modifiers(void); | ||||
| 
 | ||||
| int workspace_output_cmp_workspace(const void *a, const void *b); | ||||
| 
 | ||||
| int sway_binding_cmp(const void *a, const void *b); | ||||
| int sway_binding_cmp_qsort(const void *a, const void *b); | ||||
| int sway_binding_cmp_keys(const void *a, const void *b); | ||||
| void free_sway_binding(struct sway_binding *sb); | ||||
| struct sway_binding *sway_binding_dup(struct sway_binding *sb); | ||||
| 
 | ||||
| int sway_mouse_binding_cmp(const void *a, const void *b); | ||||
| int sway_mouse_binding_cmp_qsort(const void *a, const void *b); | ||||
| int sway_mouse_binding_cmp_buttons(const void *a, const void *b); | ||||
| void free_sway_mouse_binding(struct sway_mouse_binding *smb); | ||||
| 
 | ||||
| void load_swaybars(); | ||||
| void terminate_swaybg(pid_t pid); | ||||
| 
 | ||||
| /**
 | ||||
|  * Allocate and initialize default bar configuration. | ||||
|  */ | ||||
| struct bar_config *default_bar_config(void); | ||||
| 
 | ||||
| /**
 | ||||
|  * Global config singleton. | ||||
|  */ | ||||
| extern struct sway_config *config; | ||||
| 
 | ||||
| /**
 | ||||
|  * Config file currently being read. | ||||
|  */ | ||||
| extern const char *current_config_path; | ||||
| 
 | ||||
| #endif | ||||
| @ -1,16 +1,16 @@ | ||||
| #include <string.h> | ||||
| #include "sway/commands.h" | ||||
| #include "sway/config.h" | ||||
| #include "log.h" | ||||
| #include "stringop.h" | ||||
| 
 | ||||
| struct cmd_results *cmd_exec(int argc, char **argv) { | ||||
| 	// TODO: config
 | ||||
| 	/*if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL);
 | ||||
| 	if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); | ||||
| 	if (config->reloading) { | ||||
| 		char *args = join_args(argv, argc); | ||||
| 		sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); | ||||
| 		free(args); | ||||
| 		return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||||
| 	}*/ | ||||
| 	} | ||||
| 	return cmd_exec_always(argc, argv); | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,504 @@ | ||||
| #define _POSIX_C_SOURCE 200809L | ||||
| #define _XOPEN_SOURCE 700 | ||||
| #include <stdio.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <libgen.h> | ||||
| #include <wordexp.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/stat.h> | ||||
| #include <signal.h> | ||||
| #include <libinput.h> | ||||
| #include <limits.h> | ||||
| #include <float.h> | ||||
| #include <dirent.h> | ||||
| #include <strings.h> | ||||
| #ifdef __linux__ | ||||
| #include <linux/input-event-codes.h> | ||||
| #elif __FreeBSD__ | ||||
| #include <dev/evdev/input-event-codes.h> | ||||
| #endif | ||||
| #include <wlr/types/wlr_output.h> | ||||
| #include "sway/commands.h" | ||||
| #include "sway/config.h" | ||||
| #include "sway/layout.h" | ||||
| #include "readline.h" | ||||
| #include "stringop.h" | ||||
| #include "list.h" | ||||
| #include "log.h" | ||||
| 
 | ||||
| struct sway_config *config = NULL; | ||||
| 
 | ||||
| void free_config(struct sway_config *config) { | ||||
| 	// TODO
 | ||||
| } | ||||
| 
 | ||||
| static void config_defaults(struct sway_config *config) { | ||||
| 	if (!(config->symbols = create_list())) goto cleanup; | ||||
| 	if (!(config->modes = create_list())) goto cleanup; | ||||
| 	if (!(config->bars = create_list())) goto cleanup; | ||||
| 	if (!(config->workspace_outputs = create_list())) goto cleanup; | ||||
| 	if (!(config->pid_workspaces = create_list())) goto cleanup; | ||||
| 	if (!(config->criteria = create_list())) goto cleanup; | ||||
| 	if (!(config->no_focus = create_list())) goto cleanup; | ||||
| 	if (!(config->input_configs = create_list())) goto cleanup; | ||||
| 	if (!(config->output_configs = create_list())) goto cleanup; | ||||
| 
 | ||||
| 	if (!(config->cmd_queue = create_list())) goto cleanup; | ||||
| 
 | ||||
| 	if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; | ||||
| 	if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; | ||||
| 	strcpy(config->current_mode->name, "default"); | ||||
| 	if (!(config->current_mode->bindings = create_list())) goto cleanup; | ||||
| 	list_add(config->modes, config->current_mode); | ||||
| 
 | ||||
| 	config->floating_mod = 0; | ||||
| 	config->dragging_key = BTN_LEFT; | ||||
| 	config->resizing_key = BTN_RIGHT; | ||||
| 	if (!(config->floating_scroll_up_cmd = strdup(""))) goto cleanup; | ||||
| 	if (!(config->floating_scroll_down_cmd = strdup(""))) goto cleanup; | ||||
| 	if (!(config->floating_scroll_left_cmd = strdup(""))) goto cleanup; | ||||
| 	if (!(config->floating_scroll_right_cmd = strdup(""))) goto cleanup; | ||||
| 	config->default_layout = L_NONE; | ||||
| 	config->default_orientation = L_NONE; | ||||
| 	if (!(config->font = strdup("monospace 10"))) goto cleanup; | ||||
| 	// TODO: border
 | ||||
| 	//config->font_height = get_font_text_height(config->font);
 | ||||
| 
 | ||||
| 	// floating view
 | ||||
| 	config->floating_maximum_width = 0; | ||||
| 	config->floating_maximum_height = 0; | ||||
| 	config->floating_minimum_width = 75; | ||||
| 	config->floating_minimum_height = 50; | ||||
| 
 | ||||
| 	// Flags
 | ||||
| 	config->focus_follows_mouse = true; | ||||
| 	config->mouse_warping = true; | ||||
| 	config->reloading = false; | ||||
| 	config->active = false; | ||||
| 	config->failed = false; | ||||
| 	config->auto_back_and_forth = false; | ||||
| 	config->seamless_mouse = true; | ||||
| 	config->reading = false; | ||||
| 	config->show_marks = true; | ||||
| 
 | ||||
| 	config->edge_gaps = true; | ||||
| 	config->smart_gaps = false; | ||||
| 	config->gaps_inner = 0; | ||||
| 	config->gaps_outer = 0; | ||||
| 
 | ||||
| 	if (!(config->active_bar_modifiers = create_list())) goto cleanup; | ||||
| 
 | ||||
| 	if (!(config->config_chain = create_list())) goto cleanup; | ||||
| 	config->current_config = NULL; | ||||
| 
 | ||||
| 	// borders
 | ||||
| 	config->border = B_NORMAL; | ||||
| 	config->floating_border = B_NORMAL; | ||||
| 	config->border_thickness = 2; | ||||
| 	config->floating_border_thickness = 2; | ||||
| 	config->hide_edge_borders = E_NONE; | ||||
| 
 | ||||
| 	// border colors
 | ||||
| 	config->border_colors.focused.border = 0x4C7899FF; | ||||
| 	config->border_colors.focused.background = 0x285577FF; | ||||
| 	config->border_colors.focused.text = 0xFFFFFFFF; | ||||
| 	config->border_colors.focused.indicator = 0x2E9EF4FF; | ||||
| 	config->border_colors.focused.child_border = 0x285577FF; | ||||
| 
 | ||||
| 	config->border_colors.focused_inactive.border = 0x333333FF; | ||||
| 	config->border_colors.focused_inactive.background = 0x5F676AFF; | ||||
| 	config->border_colors.focused_inactive.text = 0xFFFFFFFF; | ||||
| 	config->border_colors.focused_inactive.indicator = 0x484E50FF; | ||||
| 	config->border_colors.focused_inactive.child_border = 0x5F676AFF; | ||||
| 
 | ||||
| 	config->border_colors.unfocused.border = 0x333333FF; | ||||
| 	config->border_colors.unfocused.background = 0x222222FF; | ||||
| 	config->border_colors.unfocused.text = 0x888888FF; | ||||
| 	config->border_colors.unfocused.indicator = 0x292D2EFF; | ||||
| 	config->border_colors.unfocused.child_border = 0x222222FF; | ||||
| 
 | ||||
| 	config->border_colors.urgent.border = 0x2F343AFF; | ||||
| 	config->border_colors.urgent.background = 0x900000FF; | ||||
| 	config->border_colors.urgent.text = 0xFFFFFFFF; | ||||
| 	config->border_colors.urgent.indicator = 0x900000FF; | ||||
| 	config->border_colors.urgent.child_border = 0x900000FF; | ||||
| 
 | ||||
| 	config->border_colors.placeholder.border = 0x000000FF; | ||||
| 	config->border_colors.placeholder.background = 0x0C0C0CFF; | ||||
| 	config->border_colors.placeholder.text = 0xFFFFFFFF; | ||||
| 	config->border_colors.placeholder.indicator = 0x000000FF; | ||||
| 	config->border_colors.placeholder.child_border = 0x0C0C0CFF; | ||||
| 
 | ||||
| 	config->border_colors.background = 0xFFFFFFFF; | ||||
| 
 | ||||
| 	// Security
 | ||||
| 	if (!(config->command_policies = create_list())) goto cleanup; | ||||
| 	if (!(config->feature_policies = create_list())) goto cleanup; | ||||
| 	if (!(config->ipc_policies = create_list())) goto cleanup; | ||||
| 
 | ||||
| 	return; | ||||
| cleanup: | ||||
| 	sway_abort("Unable to allocate config structures"); | ||||
| } | ||||
| 
 | ||||
| static bool file_exists(const char *path) { | ||||
| 	return path && access(path, R_OK) != -1; | ||||
| } | ||||
| 
 | ||||
| static char *get_config_path(void) { | ||||
| 	static const char *config_paths[] = { | ||||
| 		"$HOME/.sway/config", | ||||
| 		"$XDG_CONFIG_HOME/sway/config", | ||||
| 		"$HOME/.i3/config", | ||||
| 		"$XDG_CONFIG_HOME/i3/config", | ||||
| 		SYSCONFDIR "/sway/config", | ||||
| 		SYSCONFDIR "/i3/config", | ||||
| 	}; | ||||
| 
 | ||||
| 	if (!getenv("XDG_CONFIG_HOME")) { | ||||
| 		char *home = getenv("HOME"); | ||||
| 		char *config_home = malloc(strlen(home) + strlen("/.config") + 1); | ||||
| 		if (!config_home) { | ||||
| 			sway_log(L_ERROR, "Unable to allocate $HOME/.config"); | ||||
| 		} else { | ||||
| 			strcpy(config_home, home); | ||||
| 			strcat(config_home, "/.config"); | ||||
| 			setenv("XDG_CONFIG_HOME", config_home, 1); | ||||
| 			sway_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); | ||||
| 			free(config_home); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	wordexp_t p; | ||||
| 	char *path; | ||||
| 
 | ||||
| 	int i; | ||||
| 	for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) { | ||||
| 		if (wordexp(config_paths[i], &p, 0) == 0) { | ||||
| 			path = strdup(p.we_wordv[0]); | ||||
| 			wordfree(&p); | ||||
| 			if (file_exists(path)) { | ||||
| 				return path; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; // Not reached
 | ||||
| } | ||||
| 
 | ||||
| const char *current_config_path; | ||||
| 
 | ||||
| static bool load_config(const char *path, struct sway_config *config) { | ||||
| 	sway_log(L_INFO, "Loading config from %s", path); | ||||
| 	current_config_path = path; | ||||
| 
 | ||||
| 	struct stat sb; | ||||
| 	if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (path == NULL) { | ||||
| 		sway_log(L_ERROR, "Unable to find a config file!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	FILE *f = fopen(path, "r"); | ||||
| 	if (!f) { | ||||
| 		sway_log(L_ERROR, "Unable to open %s for reading", path); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	bool config_load_success = read_config(f, config); | ||||
| 	fclose(f); | ||||
| 
 | ||||
| 	if (!config_load_success) { | ||||
| 		sway_log(L_ERROR, "Error(s) loading config!"); | ||||
| 	} | ||||
| 
 | ||||
| 	current_config_path = NULL; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static int qstrcmp(const void* a, const void* b) { | ||||
| 	return strcmp(*((char**) a), *((char**) b)); | ||||
| } | ||||
| 
 | ||||
| bool load_main_config(const char *file, bool is_active) { | ||||
| 	char *path; | ||||
| 	if (file != NULL) { | ||||
| 		path = strdup(file); | ||||
| 	} else { | ||||
| 		path = get_config_path(); | ||||
| 	} | ||||
| 
 | ||||
| 	struct sway_config *old_config = config; | ||||
| 	config = calloc(1, sizeof(struct sway_config)); | ||||
| 	if (!config) { | ||||
| 		sway_abort("Unable to allocate config"); | ||||
| 	} | ||||
| 
 | ||||
| 	config_defaults(config); | ||||
| 	if (is_active) { | ||||
| 		sway_log(L_DEBUG, "Performing configuration file reload"); | ||||
| 		config->reloading = true; | ||||
| 		config->active = true; | ||||
| 	} | ||||
| 
 | ||||
| 	config->current_config = path; | ||||
| 	list_add(config->config_chain, path); | ||||
| 
 | ||||
| 	config->reading = true; | ||||
| 
 | ||||
| 	// Read security configs
 | ||||
| 	bool success = true; | ||||
| 	DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); | ||||
| 	if (!dir) { | ||||
| 		sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" | ||||
| 				" and will probably be broken", SYSCONFDIR "/sway/security.d"); | ||||
| 	} else { | ||||
| 		list_t *secconfigs = create_list(); | ||||
| 		char *base = SYSCONFDIR "/sway/security.d/"; | ||||
| 		struct dirent *ent = readdir(dir); | ||||
| 		struct stat s; | ||||
| 		while (ent != NULL) { | ||||
| 			char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); | ||||
| 			strcpy(_path, base); | ||||
| 			strcat(_path, ent->d_name); | ||||
| 			lstat(_path, &s); | ||||
| 			if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { | ||||
| 				list_add(secconfigs, _path); | ||||
| 			} | ||||
| 			else { | ||||
| 				free(_path); | ||||
| 			} | ||||
| 			ent = readdir(dir); | ||||
| 		} | ||||
| 		closedir(dir); | ||||
| 
 | ||||
| 		list_qsort(secconfigs, qstrcmp); | ||||
| 		for (int i = 0; i < secconfigs->length; ++i) { | ||||
| 			char *_path = secconfigs->items[i]; | ||||
| 			if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { | ||||
| 				sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); | ||||
| 				success = false; | ||||
| 			} else { | ||||
| 				success = success && load_config(_path, config); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		free_flat_list(secconfigs); | ||||
| 	} | ||||
| 
 | ||||
| 	success = success && load_config(path, config); | ||||
| 
 | ||||
| 	if (is_active) { | ||||
| 		config->reloading = false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (old_config) { | ||||
| 		free_config(old_config); | ||||
| 	} | ||||
| 	config->reading = false; | ||||
| 
 | ||||
| 	if (success) { | ||||
| 		// TODO: bar
 | ||||
| 		//update_active_bar_modifiers();
 | ||||
| 	} | ||||
| 
 | ||||
| 	return success; | ||||
| } | ||||
| 
 | ||||
| bool read_config(FILE *file, struct sway_config *config) { | ||||
| 	bool success = true; | ||||
| 	enum cmd_status block = CMD_BLOCK_END; | ||||
| 
 | ||||
| 	int line_number = 0; | ||||
| 	char *line; | ||||
| 	while (!feof(file)) { | ||||
| 		line = read_line(file); | ||||
| 		if (!line) { | ||||
| 			continue; | ||||
| 		} | ||||
| 		line_number++; | ||||
| 		line = strip_whitespace(line); | ||||
| 		if (line[0] == '#') { | ||||
| 			free(line); | ||||
| 			continue; | ||||
| 		} | ||||
| 		struct cmd_results *res; | ||||
| 		if (block == CMD_BLOCK_COMMANDS) { | ||||
| 			// Special case
 | ||||
| 			res = config_commands_command(line); | ||||
| 		} else { | ||||
| 			res = config_command(line, block); | ||||
| 		} | ||||
| 		switch(res->status) { | ||||
| 		case CMD_FAILURE: | ||||
| 		case CMD_INVALID: | ||||
| 			sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, | ||||
| 				res->error, config->current_config); | ||||
| 			success = false; | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_DEFER: | ||||
| 			sway_log(L_DEBUG, "Defferring command `%s'", line); | ||||
| 			list_add(config->cmd_queue, strdup(line)); | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_MODE: | ||||
| 			if (block == CMD_BLOCK_END) { | ||||
| 				block = CMD_BLOCK_MODE; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_INPUT: | ||||
| 			if (block == CMD_BLOCK_END) { | ||||
| 				block = CMD_BLOCK_INPUT; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_BAR: | ||||
| 			if (block == CMD_BLOCK_END) { | ||||
| 				block = CMD_BLOCK_BAR; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_BAR_COLORS: | ||||
| 			if (block == CMD_BLOCK_BAR) { | ||||
| 				block = CMD_BLOCK_BAR_COLORS; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_COMMANDS: | ||||
| 			if (block == CMD_BLOCK_END) { | ||||
| 				block = CMD_BLOCK_COMMANDS; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_IPC: | ||||
| 			if (block == CMD_BLOCK_END) { | ||||
| 				block = CMD_BLOCK_IPC; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_IPC_EVENTS: | ||||
| 			if (block == CMD_BLOCK_IPC) { | ||||
| 				block = CMD_BLOCK_IPC_EVENTS; | ||||
| 			} else { | ||||
| 				sway_log(L_ERROR, "Invalid block '%s'", line); | ||||
| 			} | ||||
| 			break; | ||||
| 
 | ||||
| 		case CMD_BLOCK_END: | ||||
| 			switch(block) { | ||||
| 			case CMD_BLOCK_MODE: | ||||
| 				sway_log(L_DEBUG, "End of mode block"); | ||||
| 				config->current_mode = config->modes->items[0]; | ||||
| 				block = CMD_BLOCK_END; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_INPUT: | ||||
| 				sway_log(L_DEBUG, "End of input block"); | ||||
| 				// TODO: input
 | ||||
| 				//current_input_config = NULL;
 | ||||
| 				block = CMD_BLOCK_END; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_BAR: | ||||
| 				sway_log(L_DEBUG, "End of bar block"); | ||||
| 				config->current_bar = NULL; | ||||
| 				block = CMD_BLOCK_END; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_BAR_COLORS: | ||||
| 				sway_log(L_DEBUG, "End of bar colors block"); | ||||
| 				block = CMD_BLOCK_BAR; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_COMMANDS: | ||||
| 				sway_log(L_DEBUG, "End of commands block"); | ||||
| 				block = CMD_BLOCK_END; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_IPC: | ||||
| 				sway_log(L_DEBUG, "End of IPC block"); | ||||
| 				block = CMD_BLOCK_END; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_IPC_EVENTS: | ||||
| 				sway_log(L_DEBUG, "End of IPC events block"); | ||||
| 				block = CMD_BLOCK_IPC; | ||||
| 				break; | ||||
| 
 | ||||
| 			case CMD_BLOCK_END: | ||||
| 				sway_log(L_ERROR, "Unmatched }"); | ||||
| 				break; | ||||
| 
 | ||||
| 			default:; | ||||
| 			} | ||||
| 		default:; | ||||
| 		} | ||||
| 		free(line); | ||||
| 		free_cmd_results(res); | ||||
| 	} | ||||
| 
 | ||||
| 	return success; | ||||
| } | ||||
| 
 | ||||
| char *do_var_replacement(char *str) { | ||||
| 	int i; | ||||
| 	char *find = str; | ||||
| 	while ((find = strchr(find, '$'))) { | ||||
| 		// Skip if escaped.
 | ||||
| 		if (find > str && find[-1] == '\\') { | ||||
| 			if (find == str + 1 || !(find > str + 1 && find[-2] == '\\')) { | ||||
| 				++find; | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| 		// Find matching variable
 | ||||
| 		for (i = 0; i < config->symbols->length; ++i) { | ||||
| 			struct sway_variable *var = config->symbols->items[i]; | ||||
| 			int vnlen = strlen(var->name); | ||||
| 			if (strncmp(find, var->name, vnlen) == 0) { | ||||
| 				int vvlen = strlen(var->value); | ||||
| 				char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); | ||||
| 				if (!newstr) { | ||||
| 					sway_log(L_ERROR, | ||||
| 							"Unable to allocate replacement during variable expansion"); | ||||
| 					break; | ||||
| 				} | ||||
| 				char *newptr = newstr; | ||||
| 				int offset = find - str; | ||||
| 				strncpy(newptr, str, offset); | ||||
| 				newptr += offset; | ||||
| 				strncpy(newptr, var->value, vvlen); | ||||
| 				newptr += vvlen; | ||||
| 				strcpy(newptr, find + vnlen); | ||||
| 				free(str); | ||||
| 				str = newstr; | ||||
| 				find = str + offset + vvlen; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (i == config->symbols->length) { | ||||
| 			++find; | ||||
| 		} | ||||
| 	} | ||||
| 	return str; | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| #define _XOPEN_SOURCE 700 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "sway/security.h" | ||||
| 
 | ||||
| struct command_policy *alloc_command_policy(const char *command) { | ||||
| 	struct command_policy *policy = malloc(sizeof(struct command_policy)); | ||||
| 	if (!policy) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	policy->command = strdup(command); | ||||
| 	if (!policy->command) { | ||||
| 		free(policy); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	policy->context = 0; | ||||
| 	return policy; | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue