diff options
| -rw-r--r-- | include/sway/commands.h | 1 | ||||
| -rw-r--r-- | include/sway/criteria.h | 5 | ||||
| -rw-r--r-- | include/sway/tree/container.h | 2 | ||||
| -rw-r--r-- | include/sway/tree/view.h | 9 | ||||
| -rw-r--r-- | include/sway/tree/workspace.h | 4 | ||||
| -rw-r--r-- | sway/commands.c | 3 | ||||
| -rw-r--r-- | sway/commands/default_floating_border.c | 29 | ||||
| -rw-r--r-- | sway/commands/no_focus.c | 26 | ||||
| -rw-r--r-- | sway/commands/urgent.c | 36 | ||||
| -rw-r--r-- | sway/config.c | 9 | ||||
| -rw-r--r-- | sway/criteria.c | 46 | ||||
| -rw-r--r-- | sway/desktop/idle_inhibit_v1.c | 1 | ||||
| -rw-r--r-- | sway/desktop/layer_shell.c | 12 | ||||
| -rw-r--r-- | sway/desktop/render.c | 64 | ||||
| -rw-r--r-- | sway/desktop/xwayland.c | 4 | ||||
| -rw-r--r-- | sway/input/seat.c | 17 | ||||
| -rw-r--r-- | sway/ipc-json.c | 7 | ||||
| -rw-r--r-- | sway/meson.build | 3 | ||||
| -rw-r--r-- | sway/sway.5.scd | 5 | ||||
| -rw-r--r-- | sway/tree/container.c | 45 | ||||
| -rw-r--r-- | sway/tree/layout.c | 11 | ||||
| -rw-r--r-- | sway/tree/view.c | 96 | ||||
| -rw-r--r-- | sway/tree/workspace.c | 11 | ||||
| -rw-r--r-- | swaybar/ipc.c | 12 | ||||
| -rw-r--r-- | swayidle/main.c | 15 | ||||
| -rw-r--r-- | swaylock/main.c | 244 | ||||
| -rw-r--r-- | swaylock/swaylock.1.scd | 9 | 
27 files changed, 602 insertions, 124 deletions
| diff --git a/include/sway/commands.h b/include/sway/commands.h index 3ebd0002..1e93e2a3 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -152,6 +152,7 @@ sway_cmd cmd_swaybg_command;  sway_cmd cmd_swap;  sway_cmd cmd_title_format;  sway_cmd cmd_unmark; +sway_cmd cmd_urgent;  sway_cmd cmd_workspace;  sway_cmd cmd_ws_auto_back_and_forth;  sway_cmd cmd_workspace_layout; diff --git a/include/sway/criteria.h b/include/sway/criteria.h index bd3ca0ac..6a8337c5 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -6,9 +6,10 @@  #include "tree/view.h"  enum criteria_type { -	CT_COMMAND = 1 << 0, -	CT_ASSIGN_OUTPUT = 1 << 1, +	CT_COMMAND          = 1 << 0, +	CT_ASSIGN_OUTPUT    = 1 << 1,  	CT_ASSIGN_WORKSPACE = 1 << 2, +	CT_NO_FOCUS         = 1 << 3,  };  struct criteria { diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 04e50fc6..ca7a3288 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -316,4 +316,6 @@ void container_floating_move_to(struct sway_container *con,   */  void container_set_dirty(struct sway_container *container); +bool container_has_urgent_child(struct sway_container *container); +  #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 21d6403e..e270f851 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -69,6 +69,11 @@ struct sway_view {  	bool border_bottom;  	bool border_left;  	bool border_right; +	bool using_csd; + +	struct timespec urgent; +	bool allow_request_urgent; +	struct wl_event_source *urgent_timer;  	bool destroying; @@ -305,4 +310,8 @@ void view_update_marks_textures(struct sway_view *view);   */  bool view_is_visible(struct sway_view *view); +void view_set_urgent(struct sway_view *view, bool enable); + +bool view_is_urgent(struct sway_view *view); +  #endif diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index c72a4ac0..bc95317a 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -10,6 +10,7 @@ struct sway_workspace {  	struct sway_view *fullscreen;  	struct sway_container *floating;  	list_t *output_priority; +	bool urgent;  };  extern char *prev_workspace_name; @@ -42,4 +43,7 @@ void workspace_output_add_priority(struct sway_container *workspace,  struct sway_container *workspace_output_get_highest_available(  		struct sway_container *ws, struct sway_container *exclude); + +void workspace_detect_urgent(struct sway_container *workspace); +  #endif diff --git a/sway/commands.c b/sway/commands.c index addd64a6..a3e6a500 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -98,6 +98,7 @@ static struct cmd_handler handlers[] = {  	{ "client.unfocused", cmd_client_unfocused },  	{ "client.urgent", cmd_client_urgent },  	{ "default_border", cmd_default_border }, +	{ "default_floating_border", cmd_default_floating_border },  	{ "exec", cmd_exec },  	{ "exec_always", cmd_exec_always },  	{ "floating_maximum_size", cmd_floating_maximum_size }, @@ -114,6 +115,7 @@ static struct cmd_handler handlers[] = {  	{ "input", cmd_input },  	{ "mode", cmd_mode },  	{ "mouse_warping", cmd_mouse_warping }, +	{ "no_focus", cmd_no_focus },  	{ "output", cmd_output },  	{ "seat", cmd_seat },  	{ "set", cmd_set }, @@ -153,6 +155,7 @@ static struct cmd_handler command_handlers[] = {  	{ "swap", cmd_swap },  	{ "title_format", cmd_title_format },  	{ "unmark", cmd_unmark }, +	{ "urgent", cmd_urgent },  };  static int handler_compare(const void *_a, const void *_b) { diff --git a/sway/commands/default_floating_border.c b/sway/commands/default_floating_border.c new file mode 100644 index 00000000..1bfc24af --- /dev/null +++ b/sway/commands/default_floating_border.c @@ -0,0 +1,29 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/container.h" + +struct cmd_results *cmd_default_floating_border(int argc, char **argv) { +	struct cmd_results *error = NULL; +	if ((error = checkarg(argc, "default_floating_border", +					EXPECTED_AT_LEAST, 1))) { +		return error; +	} + +	if (strcmp(argv[0], "none") == 0) { +		config->floating_border = B_NONE; +	} else if (strcmp(argv[0], "normal") == 0) { +		config->floating_border = B_NORMAL; +	} else if (strcmp(argv[0], "pixel") == 0) { +		config->floating_border = B_PIXEL; +	} else { +		return cmd_results_new(CMD_INVALID, "default_floating_border", +				"Expected 'default_floating_border <none|normal|pixel>' " +				"or 'default_floating_border <normal|pixel> <px>'"); +	} +	if (argc == 2) { +		config->floating_border_thickness = atoi(argv[1]); +	} + +	return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/no_focus.c b/sway/commands/no_focus.c new file mode 100644 index 00000000..61a8de7e --- /dev/null +++ b/sway/commands/no_focus.c @@ -0,0 +1,26 @@ +#define _XOPEN_SOURCE 500 +#include <string.h> +#include "sway/commands.h" +#include "sway/criteria.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_no_focus(int argc, char **argv) { +	struct cmd_results *error = NULL; +	if ((error = checkarg(argc, "no_focus", EXPECTED_AT_LEAST, 1))) { +		return error; +	} + +	char *err_str = NULL; +	struct criteria *criteria = criteria_parse(argv[0], &err_str); +	if (!criteria) { +		error = cmd_results_new(CMD_INVALID, "no_focus", err_str); +		free(err_str); +		return error; +	} + +	criteria->type = CT_NO_FOCUS; +	list_add(config->criteria, criteria); + +	return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c new file mode 100644 index 00000000..d199858a --- /dev/null +++ b/sway/commands/urgent.c @@ -0,0 +1,36 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" +#include "sway/tree/layout.h" + +struct cmd_results *cmd_urgent(int argc, char **argv) { +	struct cmd_results *error = NULL; +	if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { +		return error; +	} +	struct sway_container *container = +		config->handler_context.current_container; +	if (container->type != C_VIEW) { +		return cmd_results_new(CMD_INVALID, "urgent", +				"Only views can be urgent"); +	} +	struct sway_view *view = container->sway_view; + +	if (strcmp(argv[0], "enable") == 0) { +		view_set_urgent(view, true); +	} else if (strcmp(argv[0], "disable") == 0) { +		view_set_urgent(view, false); +	} else if (strcmp(argv[0], "allow") == 0) { +		view->allow_request_urgent = true; +	} else if (strcmp(argv[0], "deny") == 0) { +		view->allow_request_urgent = false; +	} else { +		return cmd_results_new(CMD_INVALID, "urgent", +				"Expected 'urgent <enable|disable|allow|deny>'"); +	} + +	return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/config.c b/sway/config.c index f63835bf..c620e4c7 100644 --- a/sway/config.c +++ b/sway/config.c @@ -24,6 +24,7 @@  #include "sway/input/seat.h"  #include "sway/commands.h"  #include "sway/config.h" +#include "sway/criteria.h"  #include "sway/tree/arrange.h"  #include "sway/tree/layout.h"  #include "sway/tree/workspace.h" @@ -105,7 +106,12 @@ void free_config(struct sway_config *config) {  		}  		list_free(config->seat_configs);  	} -	list_free(config->criteria); +	if (config->criteria) { +		for (int i = 0; i < config->criteria->length; ++i) { +			criteria_destroy(config->criteria->items[i]); +		} +		list_free(config->criteria); +	}  	list_free(config->no_focus);  	list_free(config->active_bar_modifiers);  	list_free(config->config_chain); @@ -474,7 +480,6 @@ static bool load_include_config(const char *path, const char *parent_dir,  		list_del(config->config_chain, index);  		return false;  	} -	free(real_path);  	// restore current_config_path  	config->current_config_path = parent_config; diff --git a/sway/criteria.c b/sway/criteria.c index 29a3668b..e2b248de 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -37,7 +37,7 @@ void criteria_destroy(struct criteria *criteria) {  	pcre_free(criteria->con_mark);  	pcre_free(criteria->window_role);  	free(criteria->workspace); - +	free(criteria->cmdlist);  	free(criteria->raw);  	free(criteria);  } @@ -46,6 +46,31 @@ static int regex_cmp(const char *item, const pcre *regex) {  	return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);  } +static int cmp_urgent(const void *_a, const void *_b) { +	struct sway_view *a = *(void **)_a; +	struct sway_view *b = *(void **)_b; + +	if (a->urgent.tv_sec < b->urgent.tv_sec) { +		return -1; +	} else if (a->urgent.tv_sec > b->urgent.tv_sec) { +		return 1; +	} +	if (a->urgent.tv_nsec < b->urgent.tv_nsec) { +		return -1; +	} else if (a->urgent.tv_nsec > b->urgent.tv_nsec) { +		return 1; +	} +	return 0; +} + +static void find_urgent_iterator(struct sway_container *swayc, void *data) { +	if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) { +		return; +	} +	list_t *urgent_views = data; +	list_add(urgent_views, swayc->sway_view); +} +  static bool criteria_matches_view(struct criteria *criteria,  		struct sway_view *view) {  	if (criteria->title) { @@ -133,8 +158,23 @@ static bool criteria_matches_view(struct criteria *criteria,  	}  	if (criteria->urgent) { -		// TODO -		return false; +		if (!view_is_urgent(view)) { +			return false; +		} +		list_t *urgent_views = create_list(); +		container_for_each_descendant_dfs(&root_container, +				find_urgent_iterator, urgent_views); +		list_stable_sort(urgent_views, cmp_urgent); +		struct sway_view *target; +		if (criteria->urgent == 'o') { // oldest +			target = urgent_views->items[0]; +		} else { // latest +			target = urgent_views->items[urgent_views->length - 1]; +		} +		list_free(urgent_views); +		if (view != target) { +			return false; +		}  	}  	if (criteria->workspace) { diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 108a8417..da17d0f2 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -67,6 +67,7 @@ struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(  	manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display);  	if (!manager->wlr_manager) { +		free(manager);  		return NULL;  	}  	manager->idle = idle; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 91baa6f8..a7d96717 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -325,12 +325,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {  		layer_surface->client_pending.margin.bottom,  		layer_surface->client_pending.margin.left); -	struct sway_layer_surface *sway_layer = -		calloc(1, sizeof(struct sway_layer_surface)); -	if (!sway_layer) { -		return; -	} -  	if (!layer_surface->output) {  		// Assign last active output  		struct sway_container *output = NULL; @@ -352,6 +346,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {  		layer_surface->output = output->sway_output->wlr_output;  	} +	struct sway_layer_surface *sway_layer = +		calloc(1, sizeof(struct sway_layer_surface)); +	if (!sway_layer) { +		return; +	} +  	sway_layer->surface_commit.notify = handle_surface_commit;  	wl_signal_add(&layer_surface->surface->events.commit,  		&sway_layer->surface_commit); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 17fe823a..4c85e516 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -256,6 +256,10 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage,  		render_view_surfaces(view, output, damage, view->swayc->alpha);  	} +	if (view->using_csd) { +		return; +	} +  	struct wlr_box box;  	float output_scale = output->wlr_output->scale;  	float color[4]; @@ -553,7 +557,11 @@ static void render_container_simple(struct sway_output *output,  			struct wlr_texture *marks_texture;  			struct sway_container_state *state = &child->current; -			if (state->focused || parent_focused) { +			if (view_is_urgent(view)) { +				colors = &config->border_colors.urgent; +				title_texture = child->title_urgent; +				marks_texture = view->marks_urgent; +			} else if (state->focused || parent_focused) {  				colors = &config->border_colors.focused;  				title_texture = child->title_focused;  				marks_texture = view->marks_focused; @@ -567,12 +575,14 @@ static void render_container_simple(struct sway_output *output,  				marks_texture = view->marks_unfocused;  			} -			if (state->border == B_NORMAL) { -				render_titlebar(output, damage, child, state->swayc_x, -						state->swayc_y, state->swayc_width, colors, -						title_texture, marks_texture); -			} else { -				render_top_border(output, damage, child, colors); +			if (!view->using_csd) { +				if (state->border == B_NORMAL) { +					render_titlebar(output, damage, child, state->swayc_x, +							state->swayc_y, state->swayc_width, colors, +							title_texture, marks_texture); +				} else { +					render_top_border(output, damage, child, colors); +				}  			}  			render_view(output, damage, child, colors);  		} else { @@ -607,8 +617,14 @@ static void render_container_tabbed(struct sway_output *output,  		struct border_colors *colors;  		struct wlr_texture *title_texture;  		struct wlr_texture *marks_texture; - -		if (cstate->focused || parent_focused) { +		bool urgent = view ? +			view_is_urgent(view) : container_has_urgent_child(child); + +		if (urgent) { +			colors = &config->border_colors.urgent; +			title_texture = child->title_urgent; +			marks_texture = view ? view->marks_urgent : NULL; +		} else if (cstate->focused || parent_focused) {  			colors = &config->border_colors.focused;  			title_texture = child->title_focused;  			marks_texture = view ? view->marks_focused : NULL; @@ -670,8 +686,14 @@ static void render_container_stacked(struct sway_output *output,  		struct border_colors *colors;  		struct wlr_texture *title_texture;  		struct wlr_texture *marks_texture; - -		if (cstate->focused || parent_focused) { +		bool urgent = view ? +			view_is_urgent(view) : container_has_urgent_child(child); + +		if (urgent) { +			colors = &config->border_colors.urgent; +			title_texture = child->title_urgent; +			marks_texture = view ? view->marks_urgent : NULL; +		} else if (cstate->focused || parent_focused) {  			colors = &config->border_colors.focused;  			title_texture = child->title_focused;  			marks_texture = view ? view->marks_focused : NULL; @@ -731,7 +753,11 @@ static void render_floating_container(struct sway_output *soutput,  		struct wlr_texture *title_texture;  		struct wlr_texture *marks_texture; -		if (con->current.focused) { +		if (view_is_urgent(view)) { +			colors = &config->border_colors.urgent; +			title_texture = con->title_urgent; +			marks_texture = view->marks_urgent; +		} else if (con->current.focused) {  			colors = &config->border_colors.focused;  			title_texture = con->title_focused;  			marks_texture = view->marks_focused; @@ -741,12 +767,14 @@ static void render_floating_container(struct sway_output *soutput,  			marks_texture = view->marks_unfocused;  		} -		if (con->current.border == B_NORMAL) { -			render_titlebar(soutput, damage, con, con->current.swayc_x, -					con->current.swayc_y, con->current.swayc_width, colors, -					title_texture, marks_texture); -		} else if (con->current.border != B_NONE) { -			render_top_border(soutput, damage, con, colors); +		if (!view->using_csd) { +			if (con->current.border == B_NORMAL) { +				render_titlebar(soutput, damage, con, con->current.swayc_x, +						con->current.swayc_y, con->current.swayc_width, colors, +						title_texture, marks_texture); +			} else if (con->current.border != B_NONE) { +				render_top_border(soutput, damage, con, colors); +			}  		}  		render_view(soutput, damage, con, colors);  	} else { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 11516673..9df7977d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -297,6 +297,10 @@ static void handle_commit(struct wl_listener *listener, void *data) {  	}  	view_damage_from(view); + +	if (view->allow_request_urgent) { +		view_set_urgent(view, (bool)xsurface->hints_urgency); +	}  }  static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/input/seat.c b/sway/input/seat.c index 74f1375e..12b1fab5 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -594,6 +594,12 @@ static void seat_send_unfocus(struct sway_container *container,  	}  } +static int handle_urgent_timeout(void *data) { +	struct sway_view *view = data; +	view_set_urgent(view, false); +	return 0; +} +  void seat_set_focus_warp(struct sway_seat *seat,  		struct sway_container *container, bool warp) {  	if (seat->focused_layer) { @@ -649,6 +655,7 @@ void seat_set_focus_warp(struct sway_seat *seat,  		while (parent) {  			wl_list_remove(&parent->link);  			wl_list_insert(&seat->focus_stack, &parent->link); +			container_set_dirty(parent->container);  			parent =  				seat_container_from_container(seat, @@ -670,6 +677,16 @@ void seat_set_focus_warp(struct sway_seat *seat,  		}  	} +	// If urgent, start a timer to unset it +	if (container && container->type == C_VIEW && +			view_is_urgent(container->sway_view) && +			!container->sway_view->urgent_timer) { +		struct sway_view *view = container->sway_view; +		view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, +				handle_urgent_timeout, view); +		wl_event_source_timer_update(view->urgent_timer, 1000); +	} +  	// If we've focused a floating container, bring it to the front.  	// We do this by putting it at the end of the floating list.  	// This must happen for both the pending and current children lists. diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 3d0e88f0..c49ea47e 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -170,7 +170,8 @@ static void ipc_json_describe_workspace(struct sway_container *workspace,  	json_object_object_add(object, "output", workspace->parent ?  			json_object_new_string(workspace->parent->name) : NULL);  	json_object_object_add(object, "type", json_object_new_string("workspace")); -	json_object_object_add(object, "urgent", json_object_new_boolean(false)); +	json_object_object_add(object, "urgent", +			json_object_new_boolean(workspace->sway_workspace->urgent));  	json_object_object_add(object, "representation", workspace->formatted_title ?  			json_object_new_string(workspace->formatted_title) : NULL); @@ -196,6 +197,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object  		json_object_object_add(object, "layout",  			json_object_new_string(ipc_json_layout_description(c->layout)));  	} + +	bool urgent = c->type == C_VIEW ? +		view_is_urgent(c->sway_view) : container_has_urgent_child(c); +	json_object_object_add(object, "urgent", json_object_new_boolean(urgent));  }  static void focus_inactive_children_iterator(struct sway_container *c, void *data) { diff --git a/sway/meson.build b/sway/meson.build index f878450d..c58d3470 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -35,6 +35,7 @@ sway_sources = files(  	'commands/border.c',  	'commands/client.c',  	'commands/default_border.c', +	'commands/default_floating_border.c',  	'commands/default_orientation.c',  	'commands/exit.c',  	'commands/exec.c', @@ -59,6 +60,7 @@ sway_sources = files(  	'commands/mode.c',  	'commands/mouse_warping.c',  	'commands/move.c', +	'commands/no_focus.c',  	'commands/output.c',  	'commands/reload.c',  	'commands/rename.c', @@ -76,6 +78,7 @@ sway_sources = files(  	'commands/swap.c',  	'commands/title_format.c',  	'commands/unmark.c', +	'commands/urgent.c',  	'commands/workspace.c',  	'commands/workspace_layout.c',  	'commands/ws_auto_back_and_forth.c', diff --git a/sway/sway.5.scd b/sway/sway.5.scd index c6eb5e6d..d369d7b6 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -499,6 +499,11 @@ config after the others, or it will be matched instead of the others.  	*unmark* will remove _identifier_ from the list of current marks on a  	window. If _identifier_ is omitted, all marks are removed. +*urgent* enable|disable|allow|deny +	Using _enable_ or _disable_ manually sets or unsets the window's urgent +	state. Using _allow_ or _deny_ controls the window's ability to set itself +	as urgent. By default, windows are allowed to set their own urgency. +  *workspace* [number] <name>  	Switches to the specified workspace. The string "number" is optional and is  	used to sort workspaces. diff --git a/sway/tree/container.c b/sway/tree/container.c index 35f67cce..3f9d701a 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -674,16 +674,23 @@ struct sway_container *floating_container_at(double lx, double ly,  void container_for_each_descendant_dfs(struct sway_container *container,  		void (*f)(struct sway_container *container, void *data),  		void *data) { -	if (container) { -		if (container->children)  { -			for (int i = 0; i < container->children->length; ++i) { -				struct sway_container *child = -					container->children->items[i]; -				container_for_each_descendant_dfs(child, f, data); -			} +	if (!container) { +		return; +	} +	if (container->children)  { +		for (int i = 0; i < container->children->length; ++i) { +			struct sway_container *child = container->children->items[i]; +			container_for_each_descendant_dfs(child, f, data);  		} -		f(container, data);  	} +	if (container->type == C_WORKSPACE)  { +		struct sway_container *floating = container->sway_workspace->floating; +		for (int i = 0; i < floating->children->length; ++i) { +			struct sway_container *child = floating->children->items[i]; +			container_for_each_descendant_dfs(child, f, data); +		} +	} +	f(container, data);  }  void container_for_each_descendant_bfs(struct sway_container *con, @@ -960,9 +967,14 @@ void container_set_geometry_from_floating_view(struct sway_container *con) {  		return;  	}  	struct sway_view *view = con->sway_view; -	size_t border_width = view->border_thickness * (view->border != B_NONE); -	size_t top = -		view->border == B_NORMAL ? container_titlebar_height() : border_width; +	size_t border_width = 0; +	size_t top = 0; + +	if (!view->using_csd) { +		border_width = view->border_thickness * (view->border != B_NONE); +		top = view->border == B_NORMAL ? +			container_titlebar_height() : border_width; +	}  	con->x = view->x - border_width;  	con->y = view->y - top; @@ -1063,6 +1075,8 @@ void container_floating_move_to(struct sway_container *con,  		container_add_child(new_workspace->sway_workspace->floating, con);  		arrange_windows(old_workspace);  		arrange_windows(new_workspace); +		workspace_detect_urgent(old_workspace); +		workspace_detect_urgent(new_workspace);  	}  } @@ -1073,3 +1087,12 @@ void container_set_dirty(struct sway_container *container) {  	container->dirty = true;  	list_add(server.dirty_containers, container);  } + +static bool find_urgent_iterator(struct sway_container *con, +		void *data) { +	return con->type == C_VIEW && view_is_urgent(con->sway_view); +} + +bool container_has_urgent_child(struct sway_container *container) { +	return container_find(container, find_urgent_iterator, NULL); +} diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 54ddb3f9..197a2fc8 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -225,6 +225,15 @@ void container_move_to(struct sway_container *container,  			}  		}  	} +	// Update workspace urgent state +	struct sway_container *old_workspace = old_parent; +	if (old_workspace->type != C_WORKSPACE) { +		old_workspace = container_parent(old_workspace, C_WORKSPACE); +	} +	if (new_workspace != old_workspace) { +		workspace_detect_urgent(new_workspace); +		workspace_detect_urgent(old_workspace); +	}  }  static bool sway_dir_to_wlr(enum movement_direction dir, @@ -548,6 +557,8 @@ void container_move(struct sway_container *container,  	}  	if (last_ws && next_ws && last_ws != next_ws) {  		ipc_event_workspace(last_ws, container, "focus"); +		workspace_detect_urgent(last_ws); +		workspace_detect_urgent(next_ws);  	}  } diff --git a/sway/tree/view.c b/sway/tree/view.c index bf380d98..fc31699c 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -25,6 +25,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,  	view->impl = impl;  	view->executed_criteria = create_list();  	view->marks = create_list(); +	view->allow_request_urgent = true;  	wl_signal_init(&view->events.unmap);  } @@ -315,11 +316,15 @@ void view_set_activated(struct sway_view *view, bool activated) {  }  void view_set_tiled(struct sway_view *view, bool tiled) { -	bool csd = true; -	if (view->impl->has_client_side_decorations) { -		csd = view->impl->has_client_side_decorations(view); +	if (!tiled) { +		view->using_csd = true; +		if (view->impl->has_client_side_decorations) { +			view->using_csd = view->impl->has_client_side_decorations(view); +		} +	} else { +		view->using_csd = false;  	} -	view->border = tiled || !csd ? config->border : B_NONE; +  	if (view->impl->set_tiled) {  		view->impl->set_tiled(view, tiled);  	} @@ -504,20 +509,38 @@ void view_execute_criteria(struct sway_view *view) {  		}  		wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",  				criteria->raw, view, criteria->cmdlist); +		seat_set_focus(seat, view->swayc);  		list_add(view->executed_criteria, criteria);  		struct cmd_results *res = execute_command(criteria->cmdlist, NULL);  		if (res->status != CMD_SUCCESS) {  			wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);  		}  		free_cmd_results(res); -		// view must be focused for commands to affect it, -		// so always refocus in-between command lists -		seat_set_focus(seat, view->swayc);  	}  	list_free(criterias);  	seat_set_focus(seat, prior_focus);  } +static bool should_focus(struct sway_view *view) { +	// If the view is the only one in the focused workspace, it'll get focus +	// regardless of any no_focus criteria. +	struct sway_container *parent = view->swayc->parent; +	struct sway_seat *seat = input_manager_current_seat(input_manager); +	if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) { +		size_t num_children = parent->children->length + +			parent->sway_workspace->floating->children->length; +		if (num_children == 1) { +			return true; +		} +	} + +	// Check no_focus criteria +	list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); +	size_t len = criterias->length; +	list_free(criterias); +	return len == 0; +} +  void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  	if (!sway_assert(view->surface == NULL, "cannot map mapped view")) {  		return; @@ -554,8 +577,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  	view->surface = wlr_surface;  	view->swayc = cont; -	view->border = config->border; -	view->border_thickness = config->border_thickness;  	view_init_subsurfaces(view, wlr_surface);  	wl_signal_add(&wlr_surface->events.new_subsurface, @@ -566,14 +587,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {  	view->container_reparent.notify = view_handle_container_reparent;  	if (view->impl->wants_floating && view->impl->wants_floating(view)) { +		view->border = config->floating_border; +		view->border_thickness = config->floating_border_thickness;  		container_set_floating(view->swayc, true);  	} else { +		view->border = config->border; +		view->border_thickness = config->border_thickness;  		view_set_tiled(view, true);  	} -	input_manager_set_focus(input_manager, cont); -	if (workspace) { -		workspace_switch(workspace); +	if (should_focus(view)) { +		input_manager_set_focus(input_manager, cont); +		if (workspace) { +			workspace_switch(workspace); +		}  	}  	view_update_title(view, false); @@ -589,16 +616,26 @@ void view_unmap(struct sway_view *view) {  	wl_list_remove(&view->surface_new_subsurface.link);  	wl_list_remove(&view->container_reparent.link); +	if (view->urgent_timer) { +		wl_event_source_remove(view->urgent_timer); +		view->urgent_timer = NULL; +	} + +	struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + +	struct sway_container *parent;  	if (view->is_fullscreen) { -		struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE);  		ws->sway_workspace->fullscreen = NULL; -		container_destroy(view->swayc); +		parent = container_destroy(view->swayc);  		arrange_windows(ws->parent);  	} else { -		struct sway_container *parent = container_destroy(view->swayc); +		parent = container_destroy(view->swayc);  		arrange_windows(parent);  	} +	if (parent->type >= C_WORKSPACE) { // if the workspace still exists +		workspace_detect_urgent(ws); +	}  	transaction_commit_dirty();  	view->surface = NULL;  } @@ -1047,3 +1084,32 @@ bool view_is_visible(struct sway_view *view) {  	}  	return true;  } + +void view_set_urgent(struct sway_view *view, bool enable) { +	if (view_is_urgent(view) == enable) { +		return; +	} +	if (enable) { +		struct sway_seat *seat = input_manager_current_seat(input_manager); +		if (seat_get_focus(seat) == view->swayc) { +			return; +		} +		clock_gettime(CLOCK_MONOTONIC, &view->urgent); +	} else { +		view->urgent = (struct timespec){ 0 }; +		if (view->urgent_timer) { +			wl_event_source_remove(view->urgent_timer); +			view->urgent_timer = NULL; +		} +	} +	container_damage_whole(view->swayc); + +	ipc_event_window(view->swayc, "urgent"); + +	struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); +	workspace_detect_urgent(ws); +} + +bool view_is_urgent(struct sway_view *view) { +	return view->urgent.tv_sec || view->urgent.tv_nsec; +} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 2a2d834a..622f01ec 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -11,6 +11,7 @@  #include "sway/ipc-server.h"  #include "sway/tree/arrange.h"  #include "sway/tree/container.h" +#include "sway/tree/view.h"  #include "sway/tree/workspace.h"  #include "list.h"  #include "log.h" @@ -518,3 +519,13 @@ struct sway_container *workspace_output_get_highest_available(  	return NULL;  } + +void workspace_detect_urgent(struct sway_container *workspace) { +	bool new_urgent = container_has_urgent_child(workspace); + +	if (workspace->sway_workspace->urgent != new_urgent) { +		workspace->sway_workspace->urgent = new_urgent; +		ipc_event_workspace(NULL, workspace, "urgent"); +		container_damage_whole(workspace); +	} +} diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 08531f2a..c2d05920 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -115,6 +115,18 @@ static void ipc_parse_colors(  		config->colors.inactive_workspace.text = parse_color(  				json_object_get_string(inactive_workspace_text));  	} +	if (urgent_workspace_border) { +		config->colors.urgent_workspace.border = parse_color( +				json_object_get_string(urgent_workspace_border)); +	} +	if (urgent_workspace_bg) { +		config->colors.urgent_workspace.background = parse_color( +				json_object_get_string(urgent_workspace_bg)); +	} +	if (urgent_workspace_text) { +		config->colors.urgent_workspace.text = parse_color( +				json_object_get_string(urgent_workspace_text)); +	}  	if (binding_mode_border) {  		config->colors.binding_mode.border = parse_color(  				json_object_get_string(binding_mode_border)); diff --git a/swayidle/main.c b/swayidle/main.c index 64e45036..678d622f 100644 --- a/swayidle/main.c +++ b/swayidle/main.c @@ -1,22 +1,21 @@  #define _XOPEN_SOURCE 500 +#include <errno.h>  #include <getopt.h> -#include <signal.h>  #include <pthread.h> +#include <signal.h>  #include <stdio.h>  #include <stdlib.h> -#include <errno.h>  #include <string.h>  #include <sys/wait.h>  #include <unistd.h>  #include <wayland-client-protocol.h>  #include <wayland-client.h> +#include <wayland-server.h>  #include <wayland-util.h>  #include <wlr/config.h>  #include <wlr/util/log.h> -#include <wlr/types/wlr_output_layout.h> -#include <wlr/types/wlr_output.h> -#include "idle-client-protocol.h"  #include "config.h" +#include "idle-client-protocol.h"  #include "list.h"  #ifdef SWAY_IDLE_HAS_SYSTEMD  #include <systemd/sd-bus.h> @@ -36,7 +35,6 @@ struct swayidle_state {  	struct wl_display *display;  	struct org_kde_kwin_idle_timeout *idle_timer;  	struct org_kde_kwin_idle_timeout *lock_timer; -	struct wlr_output_layout *layout;  	struct wl_event_loop *event_loop;  	list_t *timeout_cmds;  } state; @@ -165,7 +163,7 @@ static int dbus_event(int fd, uint32_t mask, void *data) {  void setup_sleep_listener() {  	struct sd_bus *bus; -	 +  	int ret = sd_bus_default_system(&bus);  	if (ret < 0) {  		wlr_log(WLR_ERROR, "Failed to open D-Bus connection: %s", @@ -360,7 +358,7 @@ static int display_event(int fd, uint32_t mask, void *data) {  	if (wl_display_dispatch(state.display) < 0) {  		wlr_log_errno(WLR_ERROR, "wl_display_dispatch failed, exiting");  		sway_terminate(0); -	}; +	}  	return 0;  } @@ -397,7 +395,6 @@ int main(int argc, char *argv[]) {  	struct wl_registry *registry = wl_display_get_registry(state.display);  	wl_registry_add_listener(registry, ®istry_listener, NULL);  	wl_display_roundtrip(state.display); -	state.layout = wlr_output_layout_create();  	state.event_loop = wl_event_loop_create();  	if (idle_manager == NULL) { diff --git a/swaylock/main.c b/swaylock/main.c index faebc757..ae5b86b9 100644 --- a/swaylock/main.c +++ b/swaylock/main.c @@ -21,6 +21,7 @@  #include "pool-buffer.h"  #include "cairo.h"  #include "log.h" +#include "readline.h"  #include "stringop.h"  #include "util.h"  #include "wlr-input-inhibitor-unstable-v1-client-protocol.h" @@ -412,15 +413,14 @@ static void set_default_colors(struct swaylock_colors *colors) {  	};  } -static struct swaylock_state state; - -int main(int argc, char **argv) { -	enum line_mode { -		LM_LINE, -		LM_INSIDE, -		LM_RING, -	}; +enum line_mode { +	LM_LINE, +	LM_INSIDE, +	LM_RING, +}; +static int parse_options(int argc, char **argv, struct swaylock_state *state, +		enum line_mode *line_mode) {  	enum long_option_codes {  		LO_BS_HL_COLOR = 256,  		LO_FONT, @@ -447,6 +447,7 @@ int main(int argc, char **argv) {  	};  	static struct option long_options[] = { +		{"config", required_argument, NULL, 'C'},  		{"color", required_argument, NULL, 'c'},  		{"ignore-empty-password", no_argument, NULL, 'e'},  		{"daemonize", no_argument, NULL, 'f'}, @@ -487,6 +488,8 @@ int main(int argc, char **argv) {  	const char usage[] =  		"Usage: swaylock [options...]\n"  		"\n" +		"  -C, --config <config_file>     " +			"Path to the config file.\n"  		"  -c, --color <color>            "  			"Turn the screen into the given color instead of white.\n"  		"  -e, --ignore-empty-password    " @@ -559,58 +562,48 @@ int main(int argc, char **argv) {  		"\n"  		"All <color> options are of the form <rrggbb[aa]>.\n"; -	enum line_mode line_mode = LM_LINE; -	state.args = (struct swaylock_args){ -		.mode = BACKGROUND_MODE_SOLID_COLOR, -		.font = strdup("sans-serif"), -		.radius = 50, -		.thickness = 10, -		.ignore_empty = false, -		.show_indicator = true, -	}; -	wl_list_init(&state.images); -	set_default_colors(&state.args.colors); - -	wlr_log_init(WLR_DEBUG, NULL); -  	int c; +	optind = 1;  	while (1) {  		int opt_idx = 0; -		c = getopt_long(argc, argv, "c:efhi:nrs:tuv", long_options, &opt_idx); +		c = getopt_long(argc, argv, "c:efhi:nrs:tuvC:", long_options, &opt_idx);  		if (c == -1) {  			break;  		}  		switch (c) { +		case 'C': +			// Config file. This will have already been handled so just ignore. +			break;  		case 'c': -			state.args.colors.background = parse_color(optarg); -			state.args.mode = BACKGROUND_MODE_SOLID_COLOR; +			state->args.colors.background = parse_color(optarg); +			state->args.mode = BACKGROUND_MODE_SOLID_COLOR;  			break;  		case 'e': -			state.args.ignore_empty = true; +			state->args.ignore_empty = true;  			break;  		case 'f': -			state.args.daemonize = true; +			state->args.daemonize = true;  			break;  		case 'i': -			load_image(optarg, &state); +			load_image(optarg, state);  			break;  		case 'n': -			line_mode = LM_INSIDE; +			*line_mode = LM_INSIDE;  			break;  		case 'r': -			line_mode = LM_RING; +			*line_mode = LM_RING;  			break;  		case 's': -			state.args.mode = parse_background_mode(optarg); -			if (state.args.mode == BACKGROUND_MODE_INVALID) { +			state->args.mode = parse_background_mode(optarg); +			if (state->args.mode == BACKGROUND_MODE_INVALID) {  				return 1;  			}  			break;  		case 't': -			state.args.mode = BACKGROUND_MODE_TILE; +			state->args.mode = BACKGROUND_MODE_TILE;  			break;  		case 'u': -			state.args.show_indicator = false; +			state->args.show_indicator = false;  			break;  		case 'v':  #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE @@ -621,71 +614,71 @@ int main(int argc, char **argv) {  #endif  			return 0;  		case LO_BS_HL_COLOR: -			state.args.colors.bs_highlight = parse_color(optarg); +			state->args.colors.bs_highlight = parse_color(optarg);  			break;  		case LO_FONT: -			free(state.args.font); -			state.args.font = strdup(optarg); +			free(state->args.font); +			state->args.font = strdup(optarg);  			break;  		case LO_IND_RADIUS: -			state.args.radius = strtol(optarg, NULL, 0); +			state->args.radius = strtol(optarg, NULL, 0);  			break;  		case LO_IND_THICKNESS: -			state.args.thickness = strtol(optarg, NULL, 0); +			state->args.thickness = strtol(optarg, NULL, 0);  			break;  		case LO_INSIDE_COLOR: -			state.args.colors.inside.input = parse_color(optarg); +			state->args.colors.inside.input = parse_color(optarg);  			break;  		case LO_INSIDE_CLEAR_COLOR: -			state.args.colors.inside.cleared = parse_color(optarg); +			state->args.colors.inside.cleared = parse_color(optarg);  			break;  		case LO_INSIDE_VER_COLOR: -			state.args.colors.inside.verifying = parse_color(optarg); +			state->args.colors.inside.verifying = parse_color(optarg);  			break;  		case LO_INSIDE_WRONG_COLOR: -			state.args.colors.inside.wrong = parse_color(optarg); +			state->args.colors.inside.wrong = parse_color(optarg);  			break;  		case LO_KEY_HL_COLOR: -			state.args.colors.key_highlight = parse_color(optarg); +			state->args.colors.key_highlight = parse_color(optarg);  			break;  		case LO_LINE_COLOR: -			state.args.colors.line.input = parse_color(optarg); +			state->args.colors.line.input = parse_color(optarg);  			break;  		case LO_LINE_CLEAR_COLOR: -			state.args.colors.line.cleared = parse_color(optarg); +			state->args.colors.line.cleared = parse_color(optarg);  			break;  		case LO_LINE_VER_COLOR: -			state.args.colors.line.verifying = parse_color(optarg); +			state->args.colors.line.verifying = parse_color(optarg);  			break;  		case LO_LINE_WRONG_COLOR: -			state.args.colors.line.wrong = parse_color(optarg); +			state->args.colors.line.wrong = parse_color(optarg);  			break;  		case LO_RING_COLOR: -			state.args.colors.ring.input = parse_color(optarg); +			state->args.colors.ring.input = parse_color(optarg);  			break;  		case LO_RING_CLEAR_COLOR: -			state.args.colors.ring.cleared = parse_color(optarg); +			state->args.colors.ring.cleared = parse_color(optarg);  			break;  		case LO_RING_VER_COLOR: -			state.args.colors.ring.verifying = parse_color(optarg); +			state->args.colors.ring.verifying = parse_color(optarg);  			break;  		case LO_RING_WRONG_COLOR: -			state.args.colors.ring.wrong = parse_color(optarg); +			state->args.colors.ring.wrong = parse_color(optarg);  			break;  		case LO_SEP_COLOR: -			state.args.colors.separator = parse_color(optarg); +			state->args.colors.separator = parse_color(optarg);  			break;  		case LO_TEXT_COLOR: -			state.args.colors.text.input = parse_color(optarg); +			state->args.colors.text.input = parse_color(optarg);  			break;  		case LO_TEXT_CLEAR_COLOR: -			state.args.colors.text.cleared = parse_color(optarg); +			state->args.colors.text.cleared = parse_color(optarg);  			break;  		case LO_TEXT_VER_COLOR: -			state.args.colors.text.verifying = parse_color(optarg); +			state->args.colors.text.verifying = parse_color(optarg);  			break;  		case LO_TEXT_WRONG_COLOR: -			state.args.colors.text.wrong = parse_color(optarg); +			state->args.colors.text.wrong = parse_color(optarg);  			break;  		default:  			fprintf(stderr, "%s", usage); @@ -693,6 +686,143 @@ int main(int argc, char **argv) {  		}  	} +	return 0; +} + +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/.swaylock/config", +		"$XDG_CONFIG_HOME/swaylock/config", +		SYSCONFDIR "/swaylock/config", +	}; + +	if (!getenv("XDG_CONFIG_HOME")) { +		char *home = getenv("HOME"); +		char *config_home = malloc(strlen(home) + strlen("/.config") + 1); +		if (!config_home) { +			wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config"); +		} else { +			strcpy(config_home, home); +			strcat(config_home, "/.config"); +			setenv("XDG_CONFIG_HOME", config_home, 1); +			wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); +			free(config_home); +		} +	} + +	wordexp_t p; +	char *path; +	for (size_t i = 0; i < 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; +			} +			free(path); +		} +	} + +	return NULL; +} + +static int load_config(char *path, struct swaylock_state *state, +		enum line_mode *line_mode) { +	FILE *config = fopen(path, "r"); +	if (!config) { +		wlr_log(WLR_ERROR, "Failed to read config. Running without it."); +		return 0; +	} +	char *line; +	int line_number = 0; +	while (!feof(config)) { +		line = read_line(config); +		if (!line) { +			continue; +		} + +		line_number++; +		if (line[0] == '#') { +			free(line); +			continue; +		} +		if (strlen(line) == 0) { +			free(line); +			continue; +		} + +		wlr_log(WLR_DEBUG, "Config Line #%d: %s", line_number, line); +		char flag[strlen(line) + 3]; +		sprintf(flag, "--%s", line); +		char *argv[] = {"swaylock", flag}; +		int result = parse_options(2, argv, state, line_mode); +		if (result != 0) { +			free(line); +			fclose(config); +			return result; +		} +		free(line); +	} +	fclose(config); +	return 0; +} + +static struct swaylock_state state; + +int main(int argc, char **argv) { +	enum line_mode line_mode = LM_LINE; +	state.args = (struct swaylock_args){ +		.mode = BACKGROUND_MODE_SOLID_COLOR, +		.font = strdup("sans-serif"), +		.radius = 50, +		.thickness = 10, +		.ignore_empty = false, +		.show_indicator = true, +	}; +	wl_list_init(&state.images); +	set_default_colors(&state.args.colors); + +	wlr_log_init(WLR_DEBUG, NULL); + +	char *config_path = NULL; +	static struct option long_options[] = { +		{"config", required_argument, NULL, 'C'}, +		{0, 0, 0, 0}, +	}; +	while (1) { +		int c = getopt_long(argc, argv, "C:", long_options, NULL); +		if (c == -1) { +			break; +		} else if (c == 'C') { +			config_path = strdup(optarg); +			break; +		} +	} +	if (!config_path) { +		config_path = get_config_path(); +	} + +	if (config_path) { +		wlr_log(WLR_DEBUG, "Found config at %s", config_path); +		int config_status = load_config(config_path, &state, &line_mode); +		free(config_path); +		if (config_status != 0) { +			return config_status; +		} +	} + +	if (argc > 1) { +		wlr_log(WLR_DEBUG, "Parsing CLI Args"); +		int result = parse_options(argc, argv, &state, &line_mode); +		if (result != 0) { +			return result; +		} +	} +  	if (line_mode == LM_INSIDE) {  		state.args.colors.line = state.args.colors.inside;  	} else if (line_mode == LM_RING) { diff --git a/swaylock/swaylock.1.scd b/swaylock/swaylock.1.scd index eea62c2a..3107124f 100644 --- a/swaylock/swaylock.1.scd +++ b/swaylock/swaylock.1.scd @@ -12,6 +12,15 @@ Locks your Wayland session.  # OPTIONS +*-C, --config* <path> +	The config file to use. By default, the following paths are checked: +	_$HOME/.swaylock/config_, _$XDG\_CONFIG\_HOME/swaylock/config_, and +	_SYSCONFDIR/swaylock/config_. All flags aside from this one are valid +	options in the configuration file using the format _long-option=value_. +	For options such as _ignore-empty-password_, just supply the _long-option_. +	All leading dashes should be omitted and the equals sign is required for +	flags that take an argument. +  *-c, --color* <rrggbb[aa]>  	Turn the screen into the given color. If -i is used, this sets the  	background of the image to the given color. Defaults to white (FFFFFF), or | 
