aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/config.h14
-rw-r--r--include/sway/tree/workspace.h4
-rw-r--r--sway/commands/gaps.c151
-rw-r--r--sway/commands/workspace.c124
-rw-r--r--sway/config.c5
-rw-r--r--sway/sway.5.scd18
-rw-r--r--sway/tree/view.c3
-rw-r--r--sway/tree/workspace.c65
8 files changed, 278 insertions, 106 deletions
diff --git a/include/sway/config.h b/include/sway/config.h
index 0912bc73..cd56c3dc 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -168,6 +168,16 @@ struct output_config {
168}; 168};
169 169
170/** 170/**
171 * Stores size of gaps for each side
172 */
173struct side_gaps {
174 int top;
175 int right;
176 int bottom;
177 int left;
178};
179
180/**
171 * Stores configuration for a workspace, regardless of whether the workspace 181 * Stores configuration for a workspace, regardless of whether the workspace
172 * exists. 182 * exists.
173 */ 183 */
@@ -175,7 +185,7 @@ struct workspace_config {
175 char *workspace; 185 char *workspace;
176 char *output; 186 char *output;
177 int gaps_inner; 187 int gaps_inner;
178 int gaps_outer; 188 struct side_gaps gaps_outer;
179}; 189};
180 190
181struct bar_config { 191struct bar_config {
@@ -398,7 +408,7 @@ struct sway_config {
398 408
399 bool smart_gaps; 409 bool smart_gaps;
400 int gaps_inner; 410 int gaps_inner;
401 int gaps_outer; 411 struct side_gaps gaps_outer;
402 412
403 list_t *config_chain; 413 list_t *config_chain;
404 const char *current_config_path; 414 const char *current_config_path;
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index b5ae92f3..7abfbff1 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -32,9 +32,9 @@ struct sway_workspace {
32 enum sway_container_layout layout; 32 enum sway_container_layout layout;
33 enum sway_container_layout prev_split_layout; 33 enum sway_container_layout prev_split_layout;
34 34
35 int current_gaps; 35 struct side_gaps current_gaps;
36 int gaps_inner; 36 int gaps_inner;
37 int gaps_outer; 37 struct side_gaps gaps_outer;
38 38
39 struct sway_output *output; // NULL if no outputs are connected 39 struct sway_output *output; // NULL if no outputs are connected
40 list_t *floating; // struct sway_container 40 list_t *floating; // struct sway_container
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c
index 3f0ef155..faaeab37 100644
--- a/sway/commands/gaps.c
+++ b/sway/commands/gaps.c
@@ -16,73 +16,128 @@ enum gaps_op {
16 16
17struct gaps_data { 17struct gaps_data {
18 bool inner; 18 bool inner;
19 struct {
20 bool top;
21 bool right;
22 bool bottom;
23 bool left;
24 } outer;
19 enum gaps_op operation; 25 enum gaps_op operation;
20 int amount; 26 int amount;
21}; 27};
22 28
23// gaps inner|outer <px> 29// Prevent negative outer gaps from moving windows out of the workspace.
30static void prevent_invalid_outer_gaps(void) {
31 if (config->gaps_outer.top < -config->gaps_inner) {
32 config->gaps_outer.top = -config->gaps_inner;
33 }
34 if (config->gaps_outer.right < -config->gaps_inner) {
35 config->gaps_outer.right = -config->gaps_inner;
36 }
37 if (config->gaps_outer.bottom < -config->gaps_inner) {
38 config->gaps_outer.bottom = -config->gaps_inner;
39 }
40 if (config->gaps_outer.left < -config->gaps_inner) {
41 config->gaps_outer.left = -config->gaps_inner;
42 }
43}
44
45// gaps inner|outer|horizontal|vertical|top|right|bottom|left <px>
46static const char *expected_defaults =
47 "'gaps inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
24static struct cmd_results *gaps_set_defaults(int argc, char **argv) { 48static struct cmd_results *gaps_set_defaults(int argc, char **argv) {
25 struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2); 49 struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
26 if (error) { 50 if (error) {
27 return error; 51 return error;
28 } 52 }
29 53
30 bool inner;
31 if (strcasecmp(argv[0], "inner") == 0) {
32 inner = true;
33 } else if (strcasecmp(argv[0], "outer") == 0) {
34 inner = false;
35 } else {
36 return cmd_results_new(CMD_INVALID, "gaps",
37 "Expected 'gaps inner|outer <px>'");
38 }
39
40 char *end; 54 char *end;
41 int amount = strtol(argv[1], &end, 10); 55 int amount = strtol(argv[1], &end, 10);
42 if (strlen(end) && strcasecmp(end, "px") != 0) { 56 if (strlen(end) && strcasecmp(end, "px") != 0) {
43 return cmd_results_new(CMD_INVALID, "gaps", 57 return cmd_results_new(CMD_INVALID, "gaps",
44 "Expected 'gaps inner|outer <px>'"); 58 "Expected %s", expected_defaults);
45 } 59 }
46 if (inner) { 60
61 bool valid = false;
62 if (!strcasecmp(argv[0], "inner")) {
63 valid = true;
47 config->gaps_inner = (amount >= 0) ? amount : 0; 64 config->gaps_inner = (amount >= 0) ? amount : 0;
48 } else { 65 } else {
49 config->gaps_outer = amount; 66 if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "vertical")
50 } 67 || !strcasecmp(argv[0], "top")) {
51 68 valid = true;
52 // Prevent negative outer gaps from moving windows out of the workspace. 69 config->gaps_outer.top = amount;
53 if (config->gaps_outer < -config->gaps_inner) { 70 }
54 config->gaps_outer = -config->gaps_inner; 71 if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "horizontal")
72 || !strcasecmp(argv[0], "right")) {
73 valid = true;
74 config->gaps_outer.right = amount;
75 }
76 if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "vertical")
77 || !strcasecmp(argv[0], "bottom")) {
78 valid = true;
79 config->gaps_outer.bottom = amount;
80 }
81 if (!strcasecmp(argv[0], "outer") || !strcasecmp(argv[0], "horizontal")
82 || !strcasecmp(argv[0], "left")) {
83 valid = true;
84 config->gaps_outer.left = amount;
85 }
86 }
87 if (!valid) {
88 return cmd_results_new(CMD_INVALID, "gaps",
89 "Expected %s", expected_defaults);
55 } 90 }
56 91
92 prevent_invalid_outer_gaps();
57 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 93 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
58} 94}
59 95
60static void configure_gaps(struct sway_workspace *ws, void *_data) { 96static void apply_gaps_op(int *prop, enum gaps_op op, int amount) {
61 struct gaps_data *data = _data; 97 switch (op) {
62 int *prop = data->inner ? &ws->gaps_inner : &ws->gaps_outer;
63
64 switch (data->operation) {
65 case GAPS_OP_SET: 98 case GAPS_OP_SET:
66 *prop = data->amount; 99 *prop = amount;
67 break; 100 break;
68 case GAPS_OP_ADD: 101 case GAPS_OP_ADD:
69 *prop += data->amount; 102 *prop += amount;
70 break; 103 break;
71 case GAPS_OP_SUBTRACT: 104 case GAPS_OP_SUBTRACT:
72 *prop -= data->amount; 105 *prop -= amount;
73 break; 106 break;
74 } 107 }
108}
109
110static void configure_gaps(struct sway_workspace *ws, void *_data) {
111 // Apply operation to gaps
112 struct gaps_data *data = _data;
113 if (data->inner) {
114 apply_gaps_op(&ws->gaps_inner, data->operation, data->amount);
115 }
116 if (data->outer.top) {
117 apply_gaps_op(&(ws->gaps_outer.top), data->operation, data->amount);
118 }
119 if (data->outer.right) {
120 apply_gaps_op(&(ws->gaps_outer.right), data->operation, data->amount);
121 }
122 if (data->outer.bottom) {
123 apply_gaps_op(&(ws->gaps_outer.bottom), data->operation, data->amount);
124 }
125 if (data->outer.left) {
126 apply_gaps_op(&(ws->gaps_outer.left), data->operation, data->amount);
127 }
128
75 // Prevent invalid gaps configurations. 129 // Prevent invalid gaps configurations.
76 if (ws->gaps_inner < 0) { 130 if (ws->gaps_inner < 0) {
77 ws->gaps_inner = 0; 131 ws->gaps_inner = 0;
78 } 132 }
79 if (ws->gaps_outer < -ws->gaps_inner) { 133 prevent_invalid_outer_gaps();
80 ws->gaps_outer = -ws->gaps_inner;
81 }
82 arrange_workspace(ws); 134 arrange_workspace(ws);
83} 135}
84 136
85// gaps inner|outer current|all set|plus|minus <px> 137// gaps inner|outer|horizontal|vertical|top|right|bottom|left current|all
138// set|plus|minus <px>
139static const char *expected_runtime = "'gaps inner|outer|horizontal|vertical|"
140 "top|right|bottom|left current|all set|plus|minus <px>'";
86static struct cmd_results *gaps_set_runtime(int argc, char **argv) { 141static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
87 struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4); 142 struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
88 if (error) { 143 if (error) {
@@ -93,15 +148,24 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
93 "Can't run this command while there's no outputs connected."); 148 "Can't run this command while there's no outputs connected.");
94 } 149 }
95 150
96 struct gaps_data data; 151 struct gaps_data data = {0};
97 152
98 if (strcasecmp(argv[0], "inner") == 0) { 153 if (strcasecmp(argv[0], "inner") == 0) {
99 data.inner = true; 154 data.inner = true;
100 } else if (strcasecmp(argv[0], "outer") == 0) {
101 data.inner = false;
102 } else { 155 } else {
156 data.outer.top = !strcasecmp(argv[0], "outer") ||
157 !strcasecmp(argv[0], "vertical") || !strcasecmp(argv[0], "top");
158 data.outer.right = !strcasecmp(argv[0], "outer") ||
159 !strcasecmp(argv[0], "horizontal") || !strcasecmp(argv[0], "right");
160 data.outer.bottom = !strcasecmp(argv[0], "outer") ||
161 !strcasecmp(argv[0], "vertical") || !strcasecmp(argv[0], "bottom");
162 data.outer.left = !strcasecmp(argv[0], "outer") ||
163 !strcasecmp(argv[0], "horizontal") || !strcasecmp(argv[0], "left");
164 }
165 if (!data.inner && !data.outer.top && !data.outer.right &&
166 !data.outer.bottom && !data.outer.left) {
103 return cmd_results_new(CMD_INVALID, "gaps", 167 return cmd_results_new(CMD_INVALID, "gaps",
104 "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); 168 "Expected %s", expected_runtime);
105 } 169 }
106 170
107 bool all; 171 bool all;
@@ -111,7 +175,7 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
111 all = true; 175 all = true;
112 } else { 176 } else {
113 return cmd_results_new(CMD_INVALID, "gaps", 177 return cmd_results_new(CMD_INVALID, "gaps",
114 "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); 178 "Expected %s", expected_runtime);
115 } 179 }
116 180
117 if (strcasecmp(argv[2], "set") == 0) { 181 if (strcasecmp(argv[2], "set") == 0) {
@@ -122,14 +186,14 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
122 data.operation = GAPS_OP_SUBTRACT; 186 data.operation = GAPS_OP_SUBTRACT;
123 } else { 187 } else {
124 return cmd_results_new(CMD_INVALID, "gaps", 188 return cmd_results_new(CMD_INVALID, "gaps",
125 "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); 189 "Expected %s", expected_runtime);
126 } 190 }
127 191
128 char *end; 192 char *end;
129 data.amount = strtol(argv[3], &end, 10); 193 data.amount = strtol(argv[3], &end, 10);
130 if (strlen(end) && strcasecmp(end, "px") != 0) { 194 if (strlen(end) && strcasecmp(end, "px") != 0) {
131 return cmd_results_new(CMD_INVALID, "gaps", 195 return cmd_results_new(CMD_INVALID, "gaps",
132 "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); 196 "Expected %s", expected_runtime);
133 } 197 }
134 198
135 if (all) { 199 if (all) {
@@ -141,8 +205,10 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
141 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 205 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
142} 206}
143 207
144// gaps inner|outer <px> - sets defaults for workspaces 208// gaps inner|outer|<dir>|<side> <px> - sets defaults for workspaces
145// gaps inner|outer current|all set|plus|minus <px> - runtime only 209// gaps inner|outer|<dir>|<side> current|all set|plus|minus <px> - runtime only
210// <dir> = horizontal|vertical
211// <side> = top|right|bottom|left
146struct cmd_results *cmd_gaps(int argc, char **argv) { 212struct cmd_results *cmd_gaps(int argc, char **argv) {
147 struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2); 213 struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2);
148 if (error) { 214 if (error) {
@@ -159,9 +225,8 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
159 } 225 }
160 if (config_loading) { 226 if (config_loading) {
161 return cmd_results_new(CMD_INVALID, "gaps", 227 return cmd_results_new(CMD_INVALID, "gaps",
162 "Expected 'gaps inner|outer <px>'"); 228 "Expected %s", expected_defaults);
163 } 229 }
164 return cmd_results_new(CMD_INVALID, "gaps", 230 return cmd_results_new(CMD_INVALID, "gaps",
165 "Expected 'gaps inner|outer <px>' or " 231 "Expected %s or %s", expected_runtime, expected_defaults);
166 "'gaps inner|outer current|all set|plus|minus <px>'");
167} 232}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index 5abbb676..168494d2 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -22,7 +22,10 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
22 } 22 }
23 wsc->workspace = strdup(ws_name); 23 wsc->workspace = strdup(ws_name);
24 wsc->gaps_inner = INT_MIN; 24 wsc->gaps_inner = INT_MIN;
25 wsc->gaps_outer = INT_MIN; 25 wsc->gaps_outer.top = INT_MIN;
26 wsc->gaps_outer.right = INT_MIN;
27 wsc->gaps_outer.bottom = INT_MIN;
28 wsc->gaps_outer.left = INT_MIN;
26 list_add(config->workspace_configs, wsc); 29 list_add(config->workspace_configs, wsc);
27 return wsc; 30 return wsc;
28} 31}
@@ -33,6 +36,89 @@ void free_workspace_config(struct workspace_config *wsc) {
33 free(wsc); 36 free(wsc);
34} 37}
35 38
39static void prevent_invalid_outer_gaps(struct workspace_config *wsc) {
40 if (wsc->gaps_outer.top != INT_MIN &&
41 wsc->gaps_outer.top < -wsc->gaps_inner) {
42 wsc->gaps_outer.top = -wsc->gaps_inner;
43 }
44 if (wsc->gaps_outer.right != INT_MIN &&
45 wsc->gaps_outer.right < -wsc->gaps_inner) {
46 wsc->gaps_outer.right = -wsc->gaps_inner;
47 }
48 if (wsc->gaps_outer.bottom != INT_MIN &&
49 wsc->gaps_outer.bottom < -wsc->gaps_inner) {
50 wsc->gaps_outer.bottom = -wsc->gaps_inner;
51 }
52 if (wsc->gaps_outer.left != INT_MIN &&
53 wsc->gaps_outer.left < -wsc->gaps_inner) {
54 wsc->gaps_outer.left = -wsc->gaps_inner;
55 }
56}
57
58static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
59 int gaps_location) {
60 const char *expected = "Expected 'workspace <name> gaps "
61 "inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
62 struct cmd_results *error = NULL;
63 if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO,
64 gaps_location + 3))) {
65 return error;
66 }
67 char *ws_name = join_args(argv, argc - 3);
68 struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
69 free(ws_name);
70 if (!wsc) {
71 return cmd_results_new(CMD_FAILURE, "workspace gaps",
72 "Unable to allocate workspace output");
73 }
74
75 char *end;
76 int amount = strtol(argv[gaps_location + 2], &end, 10);
77 if (strlen(end)) {
78 free(end);
79 return cmd_results_new(CMD_FAILURE, "workspace gaps", expected);
80 }
81
82 bool valid = false;
83 char *type = argv[gaps_location + 1];
84 if (!strcasecmp(type, "inner")) {
85 valid = true;
86 wsc->gaps_inner = (amount >= 0) ? amount : 0;
87 } else {
88 if (!strcasecmp(type, "outer") || !strcasecmp(type, "vertical")
89 || !strcasecmp(type, "top")) {
90 valid = true;
91 wsc->gaps_outer.top = amount;
92 }
93 if (!strcasecmp(type, "outer") || !strcasecmp(type, "horizontal")
94 || !strcasecmp(type, "right")) {
95 valid = true;
96 wsc->gaps_outer.right = amount;
97 }
98 if (!strcasecmp(type, "outer") || !strcasecmp(type, "vertical")
99 || !strcasecmp(type, "bottom")) {
100 valid = true;
101 wsc->gaps_outer.bottom = amount;
102 }
103 if (!strcasecmp(type, "outer") || !strcasecmp(type, "horizontal")
104 || !strcasecmp(type, "left")) {
105 valid = true;
106 wsc->gaps_outer.left = amount;
107 }
108 }
109 if (!valid) {
110 return cmd_results_new(CMD_INVALID, "workspace gaps", expected);
111 }
112
113 // Prevent invalid gaps configurations.
114 if (wsc->gaps_inner != INT_MIN && wsc->gaps_inner < 0) {
115 wsc->gaps_inner = 0;
116 }
117 prevent_invalid_outer_gaps(wsc);
118
119 return error;
120}
121
36struct cmd_results *cmd_workspace(int argc, char **argv) { 122struct cmd_results *cmd_workspace(int argc, char **argv) {
37 struct cmd_results *error = NULL; 123 struct cmd_results *error = NULL;
38 if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) { 124 if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) {
@@ -68,43 +154,9 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
68 free(wsc->output); 154 free(wsc->output);
69 wsc->output = strdup(argv[output_location + 1]); 155 wsc->output = strdup(argv[output_location + 1]);
70 } else if (gaps_location >= 0) { 156 } else if (gaps_location >= 0) {
71 if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, gaps_location + 3))) { 157 if ((error = cmd_workspace_gaps(argc, argv, gaps_location))) {
72 return error; 158 return error;
73 } 159 }
74 char *ws_name = join_args(argv, argc - 3);
75 struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
76 free(ws_name);
77 if (!wsc) {
78 return cmd_results_new(CMD_FAILURE, "workspace gaps",
79 "Unable to allocate workspace output");
80 }
81 int *prop = NULL;
82 if (strcasecmp(argv[gaps_location + 1], "inner") == 0) {
83 prop = &wsc->gaps_inner;
84 } else if (strcasecmp(argv[gaps_location + 1], "outer") == 0) {
85 prop = &wsc->gaps_outer;
86 } else {
87 return cmd_results_new(CMD_FAILURE, "workspace gaps",
88 "Expected 'workspace <ws> gaps inner|outer <px>'");
89 }
90 char *end;
91 int val = strtol(argv[gaps_location + 2], &end, 10);
92
93 if (strlen(end)) {
94 free(end);
95 return cmd_results_new(CMD_FAILURE, "workspace gaps",
96 "Expected 'workspace <ws> gaps inner|outer <px>'");
97 }
98 *prop = val;
99
100 // Prevent invalid gaps configurations.
101 if (wsc->gaps_inner < 0) {
102 wsc->gaps_inner = 0;
103 }
104 if (wsc->gaps_outer < -wsc->gaps_inner) {
105 wsc->gaps_outer = -wsc->gaps_inner;
106 }
107
108 } else { 160 } else {
109 if (config->reading || !config->active) { 161 if (config->reading || !config->active) {
110 return cmd_results_new(CMD_DEFER, "workspace", NULL); 162 return cmd_results_new(CMD_DEFER, "workspace", NULL);
diff --git a/sway/config.c b/sway/config.c
index 64653024..0fdd1723 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -234,7 +234,10 @@ static void config_defaults(struct sway_config *config) {
234 234
235 config->smart_gaps = false; 235 config->smart_gaps = false;
236 config->gaps_inner = 0; 236 config->gaps_inner = 0;
237 config->gaps_outer = 0; 237 config->gaps_outer.top = 0;
238 config->gaps_outer.right = 0;
239 config->gaps_outer.bottom = 0;
240 config->gaps_outer.left = 0;
238 241
239 if (!(config->active_bar_modifiers = create_list())) goto cleanup; 242 if (!(config->active_bar_modifiers = create_list())) goto cleanup;
240 243
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 4a645837..3bf6233d 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -133,9 +133,12 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
133*fullscreen* 133*fullscreen*
134 Toggles fullscreen for the focused view. 134 Toggles fullscreen for the focused view.
135 135
136*gaps* inner|outer all|current set|plus|minus <amount> 136*gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current
137set|plus|minus <amount>
137 Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the 138 Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the
138 _current_ workspace. 139 _current_ workspace. _outer_ gaps can be altered per side with _top_,
140 _right_, _bottom_, and _left_ or per direction with _horizontal_ and
141 _vertical_.
139 142
140*layout* default|splith|splitv|stacking|tabbed 143*layout* default|splith|splitv|stacking|tabbed
141 Sets the layout mode of the focused container. 144 Sets the layout mode of the focused container.
@@ -429,14 +432,16 @@ The default colors are:
429 _focus\_wrapping force_. This is only available for convenience. Please 432 _focus\_wrapping force_. This is only available for convenience. Please
430 use _focus\_wrapping_ instead when possible. 433 use _focus\_wrapping_ instead when possible.
431 434
432*gaps* inner|outer <amount> 435*gaps* inner|outer|horizontal|vertical|top|right|bottom|left <amount>
433 Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner 436 Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
434 affects spacing around each view and outer affects the spacing around each 437 affects spacing around each view and outer affects the spacing around each
435 workspace. Outer gaps are in addition to inner gaps. To reduce or remove 438 workspace. Outer gaps are in addition to inner gaps. To reduce or remove
436 outer gaps, outer gaps can be set to a negative value. 439 outer gaps, outer gaps can be set to a negative value. _outer_ gaps can
440 also be specified per side with _top_, _right_, _bottom_, and _left_ or
441 per direction with _horizontal_ and _vertical_.
437 442
438 This affects new workspaces only, and is used when the workspace doesn't 443 This affects new workspaces only, and is used when the workspace doesn't
439 have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>). 444 have its own gaps settings (see: workspace <ws> gaps ...).
440 445
441*hide\_edge\_borders* none|vertical|horizontal|both|smart|smart\_no\_gaps 446*hide\_edge\_borders* none|vertical|horizontal|both|smart|smart\_no\_gaps
442 Hides window borders adjacent to the screen edges. Default is _none_. 447 Hides window borders adjacent to the screen edges. Default is _none_.
@@ -549,7 +554,8 @@ The default colors are:
549*workspace* back\_and\_forth 554*workspace* back\_and\_forth
550 Switches to the previously focused workspace. 555 Switches to the previously focused workspace.
551 556
552*workspace* <name> gaps inner|outer <amount> 557*workspace* <name> gaps inner|outer|horizontal|vertical|top|right|bottom|left
558<amount>
553 Specifies that workspace _name_ should have the given gaps settings when it 559 Specifies that workspace _name_ should have the given gaps settings when it
554 is created. 560 is created.
555 561
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 1aa59e68..7ae8efaa 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -190,7 +190,8 @@ static bool gaps_to_edge(struct sway_view *view) {
190 } 190 }
191 con = con->parent; 191 con = con->parent;
192 } 192 }
193 return view->container->workspace->current_gaps > 0; 193 struct side_gaps gaps = view->container->workspace->current_gaps;
194 return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0;
194} 195}
195 196
196void view_autoconfigure(struct sway_view *view) { 197void view_autoconfigure(struct sway_view *view) {
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 05cda5c0..93ce50de 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -49,6 +49,21 @@ struct sway_output *workspace_get_initial_output(const char *name) {
49 return focus->output; 49 return focus->output;
50} 50}
51 51
52static void prevent_invalid_outer_gaps(struct sway_workspace *ws) {
53 if (ws->gaps_outer.top < -ws->gaps_inner) {
54 ws->gaps_outer.top = -ws->gaps_inner;
55 }
56 if (ws->gaps_outer.right < -ws->gaps_inner) {
57 ws->gaps_outer.right = -ws->gaps_inner;
58 }
59 if (ws->gaps_outer.bottom < -ws->gaps_inner) {
60 ws->gaps_outer.bottom = -ws->gaps_inner;
61 }
62 if (ws->gaps_outer.left < -ws->gaps_inner) {
63 ws->gaps_outer.left = -ws->gaps_inner;
64 }
65}
66
52struct sway_workspace *workspace_create(struct sway_output *output, 67struct sway_workspace *workspace_create(struct sway_output *output,
53 const char *name) { 68 const char *name) {
54 if (output == NULL) { 69 if (output == NULL) {
@@ -77,12 +92,24 @@ struct sway_workspace *workspace_create(struct sway_output *output,
77 if (name) { 92 if (name) {
78 struct workspace_config *wsc = workspace_find_config(name); 93 struct workspace_config *wsc = workspace_find_config(name);
79 if (wsc) { 94 if (wsc) {
80 if (wsc->gaps_outer != INT_MIN) { 95 if (wsc->gaps_outer.top != INT_MIN) {
81 ws->gaps_outer = wsc->gaps_outer; 96 ws->gaps_outer.top = wsc->gaps_outer.top;
97 }
98 if (wsc->gaps_outer.right != INT_MIN) {
99 ws->gaps_outer.right = wsc->gaps_outer.right;
100 }
101 if (wsc->gaps_outer.bottom != INT_MIN) {
102 ws->gaps_outer.bottom = wsc->gaps_outer.bottom;
103 }
104 if (wsc->gaps_outer.left != INT_MIN) {
105 ws->gaps_outer.left = wsc->gaps_outer.left;
82 } 106 }
83 if (wsc->gaps_inner != INT_MIN) { 107 if (wsc->gaps_inner != INT_MIN) {
84 ws->gaps_inner = wsc->gaps_inner; 108 ws->gaps_inner = wsc->gaps_inner;
85 } 109 }
110 // Since default outer gaps can be smaller than the negation of
111 // workspace specific inner gaps, check outer gaps again
112 prevent_invalid_outer_gaps(ws);
86 } 113 }
87 } 114 }
88 115
@@ -615,19 +642,25 @@ void workspace_insert_tiling(struct sway_workspace *workspace,
615} 642}
616 643
617void workspace_remove_gaps(struct sway_workspace *ws) { 644void workspace_remove_gaps(struct sway_workspace *ws) {
618 if (ws->current_gaps == 0) { 645 if (ws->current_gaps.top == 0 && ws->current_gaps.right == 0 &&
646 ws->current_gaps.bottom == 0 && ws->current_gaps.left == 0) {
619 return; 647 return;
620 } 648 }
621 649
622 ws->width += ws->current_gaps * 2; 650 ws->width += ws->current_gaps.left + ws->current_gaps.right;
623 ws->height += ws->current_gaps * 2; 651 ws->height += ws->current_gaps.top + ws->current_gaps.bottom;
624 ws->x -= ws->current_gaps; 652 ws->x -= ws->current_gaps.left;
625 ws->y -= ws->current_gaps; 653 ws->y -= ws->current_gaps.top;
626 ws->current_gaps = 0; 654
655 ws->current_gaps.top = 0;
656 ws->current_gaps.right = 0;
657 ws->current_gaps.bottom = 0;
658 ws->current_gaps.left = 0;
627} 659}
628 660
629void workspace_add_gaps(struct sway_workspace *ws) { 661void workspace_add_gaps(struct sway_workspace *ws) {
630 if (ws->current_gaps > 0) { 662 if (ws->current_gaps.top > 0 || ws->current_gaps.right > 0 ||
663 ws->current_gaps.bottom > 0 || ws->current_gaps.left > 0) {
631 return; 664 return;
632 } 665 }
633 if (config->smart_gaps) { 666 if (config->smart_gaps) {
@@ -643,18 +676,20 @@ void workspace_add_gaps(struct sway_workspace *ws) {
643 } 676 }
644 677
645 ws->current_gaps = ws->gaps_outer; 678 ws->current_gaps = ws->gaps_outer;
646
647 if (ws->layout == L_TABBED || ws->layout == L_STACKED) { 679 if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
648 // We have to add inner gaps for this, because children of tabbed and 680 // We have to add inner gaps for this, because children of tabbed and
649 // stacked containers don't apply their own gaps - they assume the 681 // stacked containers don't apply their own gaps - they assume the
650 // tabbed/stacked container is using gaps. 682 // tabbed/stacked container is using gaps.
651 ws->current_gaps += ws->gaps_inner; 683 ws->current_gaps.top += ws->gaps_inner;
684 ws->current_gaps.right += ws->gaps_inner;
685 ws->current_gaps.bottom += ws->gaps_inner;
686 ws->current_gaps.left += ws->gaps_inner;
652 } 687 }
653 688
654 ws->x += ws->current_gaps; 689 ws->x += ws->current_gaps.left;
655 ws->y += ws->current_gaps; 690 ws->y += ws->current_gaps.top;
656 ws->width -= 2 * ws->current_gaps; 691 ws->width -= ws->current_gaps.left + ws->current_gaps.right;
657 ws->height -= 2 * ws->current_gaps; 692 ws->height -= ws->current_gaps.top + ws->current_gaps.bottom;
658} 693}
659 694
660struct sway_container *workspace_split(struct sway_workspace *workspace, 695struct sway_container *workspace_split(struct sway_workspace *workspace,