diff options
Diffstat (limited to 'sway')
61 files changed, 831 insertions, 814 deletions
diff --git a/sway/commands.c b/sway/commands.c index 07169f1e..03761c52 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -55,22 +55,6 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type | |||
55 | return error; | 55 | return error; |
56 | } | 56 | } |
57 | 57 | ||
58 | void apply_input_config(struct input_config *input) { | ||
59 | int i; | ||
60 | i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); | ||
61 | if (i >= 0) { | ||
62 | // merge existing config | ||
63 | struct input_config *ic = config->input_configs->items[i]; | ||
64 | merge_input_config(ic, input); | ||
65 | free_input_config(input); | ||
66 | input = ic; | ||
67 | } else { | ||
68 | list_add(config->input_configs, input); | ||
69 | } | ||
70 | |||
71 | input_manager_apply_input_config(input_manager, input); | ||
72 | } | ||
73 | |||
74 | void apply_seat_config(struct seat_config *seat_config) { | 58 | void apply_seat_config(struct seat_config *seat_config) { |
75 | int i; | 59 | int i; |
76 | i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name); | 60 | i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name); |
@@ -237,7 +221,8 @@ static void set_config_node(struct sway_node *node) { | |||
237 | } | 221 | } |
238 | } | 222 | } |
239 | 223 | ||
240 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | 224 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, |
225 | struct sway_container *con) { | ||
241 | // Even though this function will process multiple commands we will only | 226 | // Even though this function will process multiple commands we will only |
242 | // return the last error, if any (for now). (Since we have access to an | 227 | // return the last error, if any (for now). (Since we have access to an |
243 | // error string we could e.g. concatenate all errors there.) | 228 | // error string we could e.g. concatenate all errors there.) |
@@ -256,6 +241,15 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
256 | } | 241 | } |
257 | } | 242 | } |
258 | 243 | ||
244 | // This is the container or workspace which this command will run on. | ||
245 | // Ignored if the command string contains criteria. | ||
246 | struct sway_node *node; | ||
247 | if (con) { | ||
248 | node = &con->node; | ||
249 | } else { | ||
250 | node = seat_get_focus_inactive(seat, &root->node); | ||
251 | } | ||
252 | |||
259 | config->handler_context.seat = seat; | 253 | config->handler_context.seat = seat; |
260 | 254 | ||
261 | head = exec; | 255 | head = exec; |
@@ -318,9 +312,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
318 | } | 312 | } |
319 | 313 | ||
320 | if (!config->handler_context.using_criteria) { | 314 | if (!config->handler_context.using_criteria) { |
321 | // without criteria, the command acts upon the focused | 315 | set_config_node(node); |
322 | // container | ||
323 | set_config_node(seat_get_focus_inactive(seat, &root->node)); | ||
324 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 316 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
325 | if (res->status != CMD_SUCCESS) { | 317 | if (res->status != CMD_SUCCESS) { |
326 | free_argv(argc, argv); | 318 | free_argv(argc, argv); |
@@ -399,14 +391,12 @@ struct cmd_results *config_command(char *exec) { | |||
399 | // Var replacement, for all but first argument of set | 391 | // Var replacement, for all but first argument of set |
400 | // TODO commands | 392 | // TODO commands |
401 | for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { | 393 | for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { |
394 | if (*argv[i] == '\"' || *argv[i] == '\'') { | ||
395 | strip_quotes(argv[i]); | ||
396 | } | ||
402 | argv[i] = do_var_replacement(argv[i]); | 397 | argv[i] = do_var_replacement(argv[i]); |
403 | unescape_string(argv[i]); | 398 | unescape_string(argv[i]); |
404 | } | 399 | } |
405 | // Strip quotes for first argument. | ||
406 | // TODO This part needs to be handled much better | ||
407 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { | ||
408 | strip_quotes(argv[1]); | ||
409 | } | ||
410 | if (handler->handle) { | 400 | if (handler->handle) { |
411 | results = handler->handle(argc-1, argv+1); | 401 | results = handler->handle(argc-1, argv+1); |
412 | } else { | 402 | } else { |
@@ -430,11 +420,6 @@ struct cmd_results *config_subcommand(char **argv, int argc, | |||
430 | char *input = argv[0] ? argv[0] : "(empty)"; | 420 | char *input = argv[0] ? argv[0] : "(empty)"; |
431 | return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); | 421 | return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); |
432 | } | 422 | } |
433 | // Strip quotes for first argument. | ||
434 | // TODO This part needs to be handled much better | ||
435 | if (argc > 1 && (*argv[1] == '\"' || *argv[1] == '\'')) { | ||
436 | strip_quotes(argv[1]); | ||
437 | } | ||
438 | if (handler->handle) { | 423 | if (handler->handle) { |
439 | return handler->handle(argc - 1, argv + 1); | 424 | return handler->handle(argc - 1, argv + 1); |
440 | } | 425 | } |
diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c index 0c48bee9..f18b8d7c 100644 --- a/sway/commands/bar/binding_mode_indicator.c +++ b/sway/commands/bar/binding_mode_indicator.c | |||
@@ -21,7 +21,9 @@ struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) { | |||
21 | config->current_bar->binding_mode_indicator = false; | 21 | config->current_bar->binding_mode_indicator = false; |
22 | wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s", | 22 | wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s", |
23 | config->current_bar->id); | 23 | config->current_bar->id); |
24 | } else { | ||
25 | return cmd_results_new(CMD_INVALID, "binding_mode_indicator", | ||
26 | "Invalid value %s", argv[0]); | ||
24 | } | 27 | } |
25 | return cmd_results_new(CMD_INVALID, "binding_mode_indicator", | 28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | "Invalid value %s", argv[0]); | ||
27 | } | 29 | } |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 047018e0..820c2a6a 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -321,7 +321,7 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) | |||
321 | } | 321 | } |
322 | 322 | ||
323 | config->handler_context.seat = seat; | 323 | config->handler_context.seat = seat; |
324 | struct cmd_results *results = execute_command(binding->command, NULL); | 324 | struct cmd_results *results = execute_command(binding->command, NULL, NULL); |
325 | if (results->status == CMD_SUCCESS) { | 325 | if (results->status == CMD_SUCCESS) { |
326 | ipc_event_binding(binding_copy); | 326 | ipc_event_binding(binding_copy); |
327 | } else { | 327 | } else { |
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index d676e475..2e0876a9 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <string.h> | 1 | #include <string.h> |
2 | #include <strings.h> | ||
2 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 4 | #include "sway/config.h" |
4 | #include "sway/tree/arrange.h" | 5 | #include "sway/tree/arrange.h" |
@@ -13,172 +14,173 @@ enum gaps_op { | |||
13 | GAPS_OP_SUBTRACT | 14 | GAPS_OP_SUBTRACT |
14 | }; | 15 | }; |
15 | 16 | ||
16 | enum gaps_scope { | 17 | struct gaps_data { |
17 | GAPS_SCOPE_ALL, | 18 | bool inner; |
18 | GAPS_SCOPE_WORKSPACE, | 19 | enum gaps_op operation; |
19 | GAPS_SCOPE_CURRENT | 20 | int amount; |
20 | }; | 21 | }; |
21 | 22 | ||
22 | struct cmd_results *cmd_gaps(int argc, char **argv) { | 23 | // gaps edge_gaps on|off|toggle |
23 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1); | 24 | static struct cmd_results *gaps_edge_gaps(int argc, char **argv) { |
24 | if (error) { | 25 | struct cmd_results *error; |
26 | if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) { | ||
25 | return error; | 27 | return error; |
26 | } | 28 | } |
27 | 29 | ||
28 | if (strcmp(argv[0], "edge_gaps") == 0) { | 30 | if (strcmp(argv[1], "on") == 0) { |
29 | if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) { | 31 | config->edge_gaps = true; |
30 | return error; | 32 | } else if (strcmp(argv[1], "off") == 0) { |
31 | } | 33 | config->edge_gaps = false; |
32 | 34 | } else if (strcmp(argv[1], "toggle") == 0) { | |
33 | if (strcmp(argv[1], "on") == 0) { | 35 | if (!config->active) { |
34 | config->edge_gaps = true; | ||
35 | } else if (strcmp(argv[1], "off") == 0) { | ||
36 | config->edge_gaps = false; | ||
37 | } else if (strcmp(argv[1], "toggle") == 0) { | ||
38 | if (!config->active) { | ||
39 | return cmd_results_new(CMD_INVALID, "gaps", | ||
40 | "Cannot toggle gaps while not running."); | ||
41 | } | ||
42 | config->edge_gaps = !config->edge_gaps; | ||
43 | } else { | ||
44 | return cmd_results_new(CMD_INVALID, "gaps", | 36 | return cmd_results_new(CMD_INVALID, "gaps", |
45 | "gaps edge_gaps on|off|toggle"); | 37 | "Cannot toggle gaps while not running."); |
46 | } | 38 | } |
47 | arrange_root(); | 39 | config->edge_gaps = !config->edge_gaps; |
48 | } else { | 40 | } else { |
49 | int amount_idx = 0; // the current index in argv | 41 | return cmd_results_new(CMD_INVALID, "gaps", |
50 | enum gaps_op op = GAPS_OP_SET; | 42 | "gaps edge_gaps on|off|toggle"); |
51 | enum gaps_scope scope = GAPS_SCOPE_ALL; | 43 | } |
52 | bool inner = true; | 44 | arrange_root(); |
53 | 45 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | |
54 | if (strcmp(argv[0], "inner") == 0) { | 46 | } |
55 | amount_idx++; | ||
56 | inner = true; | ||
57 | } else if (strcmp(argv[0], "outer") == 0) { | ||
58 | amount_idx++; | ||
59 | inner = false; | ||
60 | } | ||
61 | 47 | ||
62 | // If one of the long variants of the gaps command is used | 48 | // gaps inner|outer <px> |
63 | // (which starts with inner|outer) check the number of args | 49 | static struct cmd_results *gaps_set_defaults(int argc, char **argv) { |
64 | if (amount_idx > 0) { // if we've seen inner|outer | 50 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2); |
65 | if (argc > 2) { // check the longest variant | 51 | if (error) { |
66 | error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4); | 52 | return error; |
67 | if (error) { | 53 | } |
68 | return error; | ||
69 | } | ||
70 | } else { // check the next longest format | ||
71 | error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2); | ||
72 | if (error) { | ||
73 | return error; | ||
74 | } | ||
75 | } | ||
76 | } else { | ||
77 | error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 1); | ||
78 | if (error) { | ||
79 | return error; | ||
80 | } | ||
81 | } | ||
82 | 54 | ||
83 | if (argc == 4) { | 55 | bool inner; |
84 | // Long format: all|workspace|current. | 56 | if (strcasecmp(argv[0], "inner") == 0) { |
85 | if (strcmp(argv[amount_idx], "all") == 0) { | 57 | inner = true; |
86 | amount_idx++; | 58 | } else if (strcasecmp(argv[0], "outer") == 0) { |
87 | scope = GAPS_SCOPE_ALL; | 59 | inner = false; |
88 | } else if (strcmp(argv[amount_idx], "workspace") == 0) { | 60 | } else { |
89 | amount_idx++; | 61 | return cmd_results_new(CMD_INVALID, "gaps", |
90 | scope = GAPS_SCOPE_WORKSPACE; | 62 | "Expected 'gaps inner|outer <px>'"); |
91 | } else if (strcmp(argv[amount_idx], "current") == 0) { | 63 | } |
92 | amount_idx++; | ||
93 | scope = GAPS_SCOPE_CURRENT; | ||
94 | } | ||
95 | |||
96 | // Long format: set|plus|minus | ||
97 | if (strcmp(argv[amount_idx], "set") == 0) { | ||
98 | amount_idx++; | ||
99 | op = GAPS_OP_SET; | ||
100 | } else if (strcmp(argv[amount_idx], "plus") == 0) { | ||
101 | amount_idx++; | ||
102 | op = GAPS_OP_ADD; | ||
103 | } else if (strcmp(argv[amount_idx], "minus") == 0) { | ||
104 | amount_idx++; | ||
105 | op = GAPS_OP_SUBTRACT; | ||
106 | } | ||
107 | } | ||
108 | 64 | ||
109 | char *end; | 65 | char *end; |
110 | double val = strtod(argv[amount_idx], &end); | 66 | int amount = strtol(argv[1], &end, 10); |
111 | 67 | if (strlen(end) && strcasecmp(end, "px") != 0) { | |
112 | if (strlen(end) && val == 0.0) { // invalid <amount> | 68 | return cmd_results_new(CMD_INVALID, "gaps", |
113 | // guess which variant of the command was attempted | 69 | "Expected 'gaps inner|outer <px>'"); |
114 | if (argc == 1) { | 70 | } |
115 | return cmd_results_new(CMD_INVALID, "gaps", "gaps <amount>"); | 71 | if (amount < 0) { |
116 | } | 72 | amount = 0; |
117 | if (argc == 2) { | 73 | } |
118 | return cmd_results_new(CMD_INVALID, "gaps", | ||
119 | "gaps inner|outer <amount>"); | ||
120 | } | ||
121 | return cmd_results_new(CMD_INVALID, "gaps", | ||
122 | "gaps inner|outer all|workspace|current set|plus|minus <amount>"); | ||
123 | } | ||
124 | 74 | ||
125 | if (amount_idx == 0) { // gaps <amount> | 75 | if (inner) { |
126 | config->gaps_inner = val; | 76 | config->gaps_inner = amount; |
127 | config->gaps_outer = val; | 77 | } else { |
128 | arrange_root(); | 78 | config->gaps_outer = amount; |
129 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 79 | } |
130 | } | 80 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
131 | // Other variants. The middle-length variant (gaps inner|outer <amount>) | 81 | } |
132 | // just defaults the scope to "all" and defaults the op to "set". | ||
133 | |||
134 | double total; | ||
135 | switch (op) { | ||
136 | case GAPS_OP_SUBTRACT: { | ||
137 | total = (inner ? config->gaps_inner : config->gaps_outer) - val; | ||
138 | if (total < 0) { | ||
139 | total = 0; | ||
140 | } | ||
141 | break; | ||
142 | } | ||
143 | case GAPS_OP_ADD: { | ||
144 | total = (inner ? config->gaps_inner : config->gaps_outer) + val; | ||
145 | break; | ||
146 | } | ||
147 | case GAPS_OP_SET: { | ||
148 | total = val; | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | 82 | ||
153 | if (scope == GAPS_SCOPE_ALL) { | 83 | static void configure_gaps(struct sway_workspace *ws, void *_data) { |
154 | if (inner) { | 84 | struct gaps_data *data = _data; |
155 | config->gaps_inner = total; | 85 | int *prop = data->inner ? &ws->gaps_inner : &ws->gaps_outer; |
156 | } else { | 86 | |
157 | config->gaps_outer = total; | 87 | switch (data->operation) { |
158 | } | 88 | case GAPS_OP_SET: |
159 | arrange_root(); | 89 | *prop = data->amount; |
160 | } else { | 90 | break; |
161 | if (scope == GAPS_SCOPE_WORKSPACE) { | 91 | case GAPS_OP_ADD: |
162 | struct sway_workspace *ws = config->handler_context.workspace; | 92 | *prop += data->amount; |
163 | ws->has_gaps = true; | 93 | break; |
164 | if (inner) { | 94 | case GAPS_OP_SUBTRACT: |
165 | ws->gaps_inner = total; | 95 | *prop -= data->amount; |
166 | } else { | 96 | break; |
167 | ws->gaps_outer = total; | 97 | } |
168 | } | 98 | if (*prop < 0) { |
169 | arrange_workspace(ws); | 99 | *prop = 0; |
170 | } else { | 100 | } |
171 | struct sway_container *c = config->handler_context.container; | 101 | arrange_workspace(ws); |
172 | c->has_gaps = true; | 102 | } |
173 | if (inner) { | 103 | |
174 | c->gaps_inner = total; | 104 | // gaps inner|outer current|all set|plus|minus <px> |
175 | } else { | 105 | static struct cmd_results *gaps_set_runtime(int argc, char **argv) { |
176 | c->gaps_outer = total; | 106 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4); |
177 | } | 107 | if (error) { |
178 | arrange_workspace(c->workspace); | 108 | return error; |
179 | } | 109 | } |
180 | } | 110 | |
111 | struct gaps_data data; | ||
112 | |||
113 | if (strcasecmp(argv[0], "inner") == 0) { | ||
114 | data.inner = true; | ||
115 | } else if (strcasecmp(argv[0], "outer") == 0) { | ||
116 | data.inner = false; | ||
117 | } else { | ||
118 | return cmd_results_new(CMD_INVALID, "gaps", | ||
119 | "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); | ||
120 | } | ||
121 | |||
122 | bool all; | ||
123 | if (strcasecmp(argv[1], "current") == 0) { | ||
124 | all = false; | ||
125 | } else if (strcasecmp(argv[1], "all") == 0) { | ||
126 | all = true; | ||
127 | } else { | ||
128 | return cmd_results_new(CMD_INVALID, "gaps", | ||
129 | "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); | ||
130 | } | ||
131 | |||
132 | if (strcasecmp(argv[2], "set") == 0) { | ||
133 | data.operation = GAPS_OP_SET; | ||
134 | } else if (strcasecmp(argv[2], "plus") == 0) { | ||
135 | data.operation = GAPS_OP_ADD; | ||
136 | } else if (strcasecmp(argv[2], "minus") == 0) { | ||
137 | data.operation = GAPS_OP_SUBTRACT; | ||
138 | } else { | ||
139 | return cmd_results_new(CMD_INVALID, "gaps", | ||
140 | "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); | ||
141 | } | ||
142 | |||
143 | char *end; | ||
144 | data.amount = strtol(argv[3], &end, 10); | ||
145 | if (strlen(end) && strcasecmp(end, "px") != 0) { | ||
146 | return cmd_results_new(CMD_INVALID, "gaps", | ||
147 | "Expected 'gaps inner|outer current|all set|plus|minus <px>'"); | ||
148 | } | ||
149 | |||
150 | if (all) { | ||
151 | root_for_each_workspace(configure_gaps, &data); | ||
152 | } else { | ||
153 | configure_gaps(config->handler_context.workspace, &data); | ||
181 | } | 154 | } |
182 | 155 | ||
183 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 156 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
184 | } | 157 | } |
158 | |||
159 | // gaps edge_gaps on|off|toggle | ||
160 | // gaps inner|outer <px> - sets defaults for workspaces | ||
161 | // gaps inner|outer current|all set|plus|minus <px> - runtime only | ||
162 | struct cmd_results *cmd_gaps(int argc, char **argv) { | ||
163 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2); | ||
164 | if (error) { | ||
165 | return error; | ||
166 | } | ||
167 | |||
168 | if (strcmp(argv[0], "edge_gaps") == 0) { | ||
169 | return gaps_edge_gaps(argc, argv); | ||
170 | } | ||
171 | |||
172 | if (argc == 2) { | ||
173 | return gaps_set_defaults(argc, argv); | ||
174 | } | ||
175 | if (argc == 4) { | ||
176 | if (config->active) { | ||
177 | return gaps_set_runtime(argc, argv); | ||
178 | } else { | ||
179 | return cmd_results_new(CMD_INVALID, "gaps", | ||
180 | "This syntax can only be used when sway is running"); | ||
181 | } | ||
182 | } | ||
183 | return cmd_results_new(CMD_INVALID, "gaps", | ||
184 | "Expected 'gaps inner|outer <px>' or " | ||
185 | "'gaps inner|outer current|all set|plus|minus <px>'"); | ||
186 | } | ||
diff --git a/sway/commands/input.c b/sway/commands/input.c index 84888fbb..2889d47d 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c | |||
@@ -9,6 +9,7 @@ | |||
9 | static struct cmd_handler input_handlers[] = { | 9 | static struct cmd_handler input_handlers[] = { |
10 | { "accel_profile", input_cmd_accel_profile }, | 10 | { "accel_profile", input_cmd_accel_profile }, |
11 | { "click_method", input_cmd_click_method }, | 11 | { "click_method", input_cmd_click_method }, |
12 | { "drag", input_cmd_drag }, | ||
12 | { "drag_lock", input_cmd_drag_lock }, | 13 | { "drag_lock", input_cmd_drag_lock }, |
13 | { "dwt", input_cmd_dwt }, | 14 | { "dwt", input_cmd_dwt }, |
14 | { "events", input_cmd_events }, | 15 | { "events", input_cmd_events }, |
@@ -66,7 +67,15 @@ struct cmd_results *cmd_input(int argc, char **argv) { | |||
66 | input_handlers, sizeof(input_handlers)); | 67 | input_handlers, sizeof(input_handlers)); |
67 | } | 68 | } |
68 | 69 | ||
69 | free_input_config(config->handler_context.input_config); | 70 | if (!res || res->status == CMD_SUCCESS) { |
71 | struct input_config *ic = | ||
72 | store_input_config(config->handler_context.input_config); | ||
73 | |||
74 | input_manager_apply_input_config(input_manager, ic); | ||
75 | } else { | ||
76 | free_input_config(config->handler_context.input_config); | ||
77 | } | ||
78 | |||
70 | config->handler_context.input_config = NULL; | 79 | config->handler_context.input_config = NULL; |
71 | 80 | ||
72 | return res; | 81 | return res; |
diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c index a4108ec3..f7016790 100644 --- a/sway/commands/input/accel_profile.c +++ b/sway/commands/input/accel_profile.c | |||
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_accel_profile(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) { | 9 | if ((error = checkarg(argc, "accel_profile", EXPECTED_AT_LEAST, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, "accel_profile", | 14 | return cmd_results_new(CMD_FAILURE, "accel_profile", |
16 | "No input device defined."); | 15 | "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | if (strcasecmp(argv[0], "adaptive") == 0) { | 18 | if (strcasecmp(argv[0], "adaptive") == 0) { |
22 | new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; | 19 | ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; |
23 | } else if (strcasecmp(argv[0], "flat") == 0) { | 20 | } else if (strcasecmp(argv[0], "flat") == 0) { |
24 | new_config->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; | 21 | ic->accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; |
25 | } else { | 22 | } else { |
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "accel_profile", | 23 | return cmd_results_new(CMD_INVALID, "accel_profile", |
28 | "Expected 'accel_profile <adaptive|flat>'"); | 24 | "Expected 'accel_profile <adaptive|flat>'"); |
29 | } | 25 | } |
30 | 26 | ||
31 | apply_input_config(new_config); | ||
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
33 | } | 28 | } |
diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c index 5d0d8cc2..4d7e1c93 100644 --- a/sway/commands/input/click_method.c +++ b/sway/commands/input/click_method.c | |||
@@ -10,27 +10,22 @@ struct cmd_results *input_cmd_click_method(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "click_method", | 15 | return cmd_results_new(CMD_FAILURE, "click_method", |
17 | "No input device defined."); | 16 | "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | if (strcasecmp(argv[0], "none") == 0) { | 19 | if (strcasecmp(argv[0], "none") == 0) { |
23 | new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; | 20 | ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; |
24 | } else if (strcasecmp(argv[0], "button_areas") == 0) { | 21 | } else if (strcasecmp(argv[0], "button_areas") == 0) { |
25 | new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; | 22 | ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; |
26 | } else if (strcasecmp(argv[0], "clickfinger") == 0) { | 23 | } else if (strcasecmp(argv[0], "clickfinger") == 0) { |
27 | new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; | 24 | ic->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; |
28 | } else { | 25 | } else { |
29 | free_input_config(new_config); | ||
30 | return cmd_results_new(CMD_INVALID, "click_method", | 26 | return cmd_results_new(CMD_INVALID, "click_method", |
31 | "Expected 'click_method <none|button_areas|clickfinger'"); | 27 | "Expected 'click_method <none|button_areas|clickfinger'"); |
32 | } | 28 | } |
33 | 29 | ||
34 | apply_input_config(new_config); | ||
35 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
36 | } | 31 | } |
diff --git a/sway/commands/input/drag.c b/sway/commands/input/drag.c new file mode 100644 index 00000000..e325df29 --- /dev/null +++ b/sway/commands/input/drag.c | |||
@@ -0,0 +1,26 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/config.h" | ||
4 | #include "sway/commands.h" | ||
5 | #include "sway/input/input-manager.h" | ||
6 | #include "util.h" | ||
7 | |||
8 | struct cmd_results *input_cmd_drag(int argc, char **argv) { | ||
9 | struct cmd_results *error = NULL; | ||
10 | if ((error = checkarg(argc, "drag", EXPECTED_AT_LEAST, 1))) { | ||
11 | return error; | ||
12 | } | ||
13 | struct input_config *ic = config->handler_context.input_config; | ||
14 | if (!ic) { | ||
15 | return cmd_results_new(CMD_FAILURE, | ||
16 | "drag", "No input device defined."); | ||
17 | } | ||
18 | |||
19 | if (parse_boolean(argv[0], true)) { | ||
20 | ic->drag = LIBINPUT_CONFIG_DRAG_ENABLED; | ||
21 | } else { | ||
22 | ic->drag = LIBINPUT_CONFIG_DRAG_DISABLED; | ||
23 | } | ||
24 | |||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
26 | } | ||
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c index f9ddeef2..db5d5afa 100644 --- a/sway/commands/input/drag_lock.c +++ b/sway/commands/input/drag_lock.c | |||
@@ -10,21 +10,17 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, | 15 | return cmd_results_new(CMD_FAILURE, |
17 | "drag_lock", "No input device defined."); | 16 | "drag_lock", "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | if (parse_boolean(argv[0], true)) { | 19 | if (parse_boolean(argv[0], true)) { |
23 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; | 20 | ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; |
24 | } else { | 21 | } else { |
25 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; | 22 | ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; |
26 | } | 23 | } |
27 | 24 | ||
28 | apply_input_config(new_config); | ||
29 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
30 | } | 26 | } |
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c index 15134268..0c3881dd 100644 --- a/sway/commands/input/dwt.c +++ b/sway/commands/input/dwt.c | |||
@@ -10,20 +10,16 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); | 15 | return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | if (parse_boolean(argv[0], true)) { | 18 | if (parse_boolean(argv[0], true)) { |
22 | new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; | 19 | ic->dwt = LIBINPUT_CONFIG_DWT_ENABLED; |
23 | } else { | 20 | } else { |
24 | new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; | 21 | ic->dwt = LIBINPUT_CONFIG_DWT_DISABLED; |
25 | } | 22 | } |
26 | 23 | ||
27 | apply_input_config(new_config); | ||
28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 24 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
29 | } | 25 | } |
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c index abfe3b12..e7ed69c6 100644 --- a/sway/commands/input/events.c +++ b/sway/commands/input/events.c | |||
@@ -10,30 +10,23 @@ struct cmd_results *input_cmd_events(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "events", | 15 | return cmd_results_new(CMD_FAILURE, "events", |
17 | "No input device defined."); | 16 | "No input device defined."); |
18 | } | 17 | } |
19 | wlr_log(WLR_DEBUG, "events for device: %s", | ||
20 | current_input_config->identifier); | ||
21 | struct input_config *new_config = | ||
22 | new_input_config(current_input_config->identifier); | ||
23 | 18 | ||
24 | if (strcasecmp(argv[0], "enabled") == 0) { | 19 | if (strcasecmp(argv[0], "enabled") == 0) { |
25 | new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; | 20 | ic->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; |
26 | } else if (strcasecmp(argv[0], "disabled") == 0) { | 21 | } else if (strcasecmp(argv[0], "disabled") == 0) { |
27 | new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; | 22 | ic->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; |
28 | } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { | 23 | } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { |
29 | new_config->send_events = | 24 | ic->send_events = |
30 | LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; | 25 | LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; |
31 | } else { | 26 | } else { |
32 | free_input_config(new_config); | ||
33 | return cmd_results_new(CMD_INVALID, "events", | 27 | return cmd_results_new(CMD_INVALID, "events", |
34 | "Expected 'events <enabled|disabled|disabled_on_external_mouse>'"); | 28 | "Expected 'events <enabled|disabled|disabled_on_external_mouse>'"); |
35 | } | 29 | } |
36 | 30 | ||
37 | apply_input_config(new_config); | ||
38 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
39 | } | 32 | } |
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c index e770043a..2e0f757b 100644 --- a/sway/commands/input/left_handed.c +++ b/sway/commands/input/left_handed.c | |||
@@ -10,17 +10,13 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "left_handed", | 15 | return cmd_results_new(CMD_FAILURE, "left_handed", |
17 | "No input device defined."); | 16 | "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | new_config->left_handed = parse_boolean(argv[0], true); | 19 | ic->left_handed = parse_boolean(argv[0], true); |
23 | 20 | ||
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 21 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 22 | } |
diff --git a/sway/commands/input/map_from_region.c b/sway/commands/input/map_from_region.c index 40f04214..53608a67 100644 --- a/sway/commands/input/map_from_region.c +++ b/sway/commands/input/map_from_region.c | |||
@@ -38,50 +38,44 @@ struct cmd_results *input_cmd_map_from_region(int argc, char **argv) { | |||
38 | if ((error = checkarg(argc, "map_from_region", EXPECTED_EQUAL_TO, 2))) { | 38 | if ((error = checkarg(argc, "map_from_region", EXPECTED_EQUAL_TO, 2))) { |
39 | return error; | 39 | return error; |
40 | } | 40 | } |
41 | struct input_config *current_input_config = | 41 | struct input_config *ic = config->handler_context.input_config; |
42 | config->handler_context.input_config; | 42 | if (!ic) { |
43 | if (!current_input_config) { | ||
44 | return cmd_results_new(CMD_FAILURE, "map_from_region", | 43 | return cmd_results_new(CMD_FAILURE, "map_from_region", |
45 | "No input device defined"); | 44 | "No input device defined"); |
46 | } | 45 | } |
47 | 46 | ||
48 | struct input_config *new_config = | 47 | ic->mapped_from_region = |
49 | new_input_config(current_input_config->identifier); | ||
50 | |||
51 | new_config->mapped_from_region = | ||
52 | calloc(1, sizeof(struct input_config_mapped_from_region)); | 48 | calloc(1, sizeof(struct input_config_mapped_from_region)); |
53 | 49 | ||
54 | bool mm1, mm2; | 50 | bool mm1, mm2; |
55 | if (!parse_coords(argv[0], &new_config->mapped_from_region->x1, | 51 | if (!parse_coords(argv[0], &ic->mapped_from_region->x1, |
56 | &new_config->mapped_from_region->y1, &mm1)) { | 52 | &ic->mapped_from_region->y1, &mm1)) { |
57 | free(new_config->mapped_from_region); | 53 | free(ic->mapped_from_region); |
58 | free_input_config(new_config); | 54 | ic->mapped_from_region = NULL; |
59 | return cmd_results_new(CMD_FAILURE, "map_from_region", | 55 | return cmd_results_new(CMD_FAILURE, "map_from_region", |
60 | "Invalid top-left coordinates"); | 56 | "Invalid top-left coordinates"); |
61 | } | 57 | } |
62 | if (!parse_coords(argv[1], &new_config->mapped_from_region->x2, | 58 | if (!parse_coords(argv[1], &ic->mapped_from_region->x2, |
63 | &new_config->mapped_from_region->y2, &mm2)) { | 59 | &ic->mapped_from_region->y2, &mm2)) { |
64 | free(new_config->mapped_from_region); | 60 | free(ic->mapped_from_region); |
65 | free_input_config(new_config); | 61 | ic->mapped_from_region = NULL; |
66 | return cmd_results_new(CMD_FAILURE, "map_from_region", | 62 | return cmd_results_new(CMD_FAILURE, "map_from_region", |
67 | "Invalid bottom-right coordinates"); | 63 | "Invalid bottom-right coordinates"); |
68 | } | 64 | } |
69 | if (new_config->mapped_from_region->x1 > new_config->mapped_from_region->x2 || | 65 | if (ic->mapped_from_region->x1 > ic->mapped_from_region->x2 || |
70 | new_config->mapped_from_region->y1 > new_config->mapped_from_region->y2) { | 66 | ic->mapped_from_region->y1 > ic->mapped_from_region->y2) { |
71 | free(new_config->mapped_from_region); | 67 | free(ic->mapped_from_region); |
72 | free_input_config(new_config); | 68 | ic->mapped_from_region = NULL; |
73 | return cmd_results_new(CMD_FAILURE, "map_from_region", | 69 | return cmd_results_new(CMD_FAILURE, "map_from_region", |
74 | "Invalid rectangle"); | 70 | "Invalid rectangle"); |
75 | } | 71 | } |
76 | if (mm1 != mm2) { | 72 | if (mm1 != mm2) { |
77 | free(new_config->mapped_from_region); | 73 | free(ic->mapped_from_region); |
78 | free_input_config(new_config); | 74 | ic->mapped_from_region = NULL; |
79 | return cmd_results_new(CMD_FAILURE, "map_from_region", | 75 | return cmd_results_new(CMD_FAILURE, "map_from_region", |
80 | "Both coordinates must be in the same unit"); | 76 | "Both coordinates must be in the same unit"); |
81 | } | 77 | } |
82 | new_config->mapped_from_region->mm = mm1; | 78 | ic->mapped_from_region->mm = mm1; |
83 | |||
84 | apply_input_config(new_config); | ||
85 | 79 | ||
86 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 80 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
87 | } | 81 | } |
diff --git a/sway/commands/input/map_to_output.c b/sway/commands/input/map_to_output.c index 68439bec..8b16c557 100644 --- a/sway/commands/input/map_to_output.c +++ b/sway/commands/input/map_to_output.c | |||
@@ -11,17 +11,13 @@ struct cmd_results *input_cmd_map_to_output(int argc, char **argv) { | |||
11 | if ((error = checkarg(argc, "map_to_output", EXPECTED_EQUAL_TO, 1))) { | 11 | if ((error = checkarg(argc, "map_to_output", EXPECTED_EQUAL_TO, 1))) { |
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct input_config *current_input_config = | 14 | struct input_config *ic = config->handler_context.input_config; |
15 | config->handler_context.input_config; | 15 | if (!ic) { |
16 | if (!current_input_config) { | ||
17 | return cmd_results_new(CMD_FAILURE, "map_to_output", | 16 | return cmd_results_new(CMD_FAILURE, "map_to_output", |
18 | "No input device defined."); | 17 | "No input device defined."); |
19 | } | 18 | } |
20 | struct input_config *new_config = | ||
21 | new_input_config(current_input_config->identifier); | ||
22 | 19 | ||
23 | new_config->mapped_to_output = strdup(argv[0]); | 20 | ic->mapped_to_output = strdup(argv[0]); |
24 | apply_input_config(new_config); | ||
25 | 21 | ||
26 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
27 | } | 23 | } |
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c index 414d4d2b..80d26838 100644 --- a/sway/commands/input/middle_emulation.c +++ b/sway/commands/input/middle_emulation.c | |||
@@ -10,22 +10,17 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "middle_emulation", | 15 | return cmd_results_new(CMD_FAILURE, "middle_emulation", |
17 | "No input device defined."); | 16 | "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | if (parse_boolean(argv[0], true)) { | 19 | if (parse_boolean(argv[0], true)) { |
23 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; | 20 | ic->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; |
24 | } else { | 21 | } else { |
25 | new_config->middle_emulation = | 22 | ic->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; |
26 | LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; | ||
27 | } | 23 | } |
28 | 24 | ||
29 | apply_input_config(new_config); | ||
30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
31 | } | 26 | } |
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c index 77c3ff00..e2a93500 100644 --- a/sway/commands/input/natural_scroll.c +++ b/sway/commands/input/natural_scroll.c | |||
@@ -10,17 +10,13 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "natural_scoll", | 15 | return cmd_results_new(CMD_FAILURE, "natural_scoll", |
17 | "No input device defined."); | 16 | "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | new_config->natural_scroll = parse_boolean(argv[0], true); | 19 | ic->natural_scroll = parse_boolean(argv[0], true); |
23 | 20 | ||
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 21 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 22 | } |
diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c index 8bbd0724..df487b1c 100644 --- a/sway/commands/input/pointer_accel.c +++ b/sway/commands/input/pointer_accel.c | |||
@@ -9,23 +9,18 @@ struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) { | 9 | if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, | 14 | return cmd_results_new(CMD_FAILURE, |
16 | "pointer_accel", "No input device defined."); | 15 | "pointer_accel", "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | float pointer_accel = atof(argv[0]); | 18 | float pointer_accel = atof(argv[0]); |
22 | if (pointer_accel < -1 || pointer_accel > 1) { | 19 | if (pointer_accel < -1 || pointer_accel > 1) { |
23 | free_input_config(new_config); | ||
24 | return cmd_results_new(CMD_INVALID, "pointer_accel", | 20 | return cmd_results_new(CMD_INVALID, "pointer_accel", |
25 | "Input out of range [-1, 1]"); | 21 | "Input out of range [-1, 1]"); |
26 | } | 22 | } |
27 | new_config->pointer_accel = pointer_accel; | 23 | ic->pointer_accel = pointer_accel; |
28 | 24 | ||
29 | apply_input_config(new_config); | ||
30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
31 | } | 26 | } |
diff --git a/sway/commands/input/repeat_delay.c b/sway/commands/input/repeat_delay.c index c9ddbf0e..d94b3e4d 100644 --- a/sway/commands/input/repeat_delay.c +++ b/sway/commands/input/repeat_delay.c | |||
@@ -9,23 +9,18 @@ struct cmd_results *input_cmd_repeat_delay(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "repeat_delay", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "repeat_delay", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, | 14 | return cmd_results_new(CMD_FAILURE, |
16 | "repeat_delay", "No input device defined."); | 15 | "repeat_delay", "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | int repeat_delay = atoi(argv[0]); | 18 | int repeat_delay = atoi(argv[0]); |
22 | if (repeat_delay < 0) { | 19 | if (repeat_delay < 0) { |
23 | free_input_config(new_config); | ||
24 | return cmd_results_new(CMD_INVALID, "repeat_delay", | 20 | return cmd_results_new(CMD_INVALID, "repeat_delay", |
25 | "Repeat delay cannot be negative"); | 21 | "Repeat delay cannot be negative"); |
26 | } | 22 | } |
27 | new_config->repeat_delay = repeat_delay; | 23 | ic->repeat_delay = repeat_delay; |
28 | 24 | ||
29 | apply_input_config(new_config); | ||
30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
31 | } | 26 | } |
diff --git a/sway/commands/input/repeat_rate.c b/sway/commands/input/repeat_rate.c index 56878176..ebec4cdb 100644 --- a/sway/commands/input/repeat_rate.c +++ b/sway/commands/input/repeat_rate.c | |||
@@ -9,23 +9,18 @@ struct cmd_results *input_cmd_repeat_rate(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "repeat_rate", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "repeat_rate", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, | 14 | return cmd_results_new(CMD_FAILURE, |
16 | "repeat_rate", "No input device defined."); | 15 | "repeat_rate", "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | int repeat_rate = atoi(argv[0]); | 18 | int repeat_rate = atoi(argv[0]); |
22 | if (repeat_rate < 0) { | 19 | if (repeat_rate < 0) { |
23 | free_input_config(new_config); | ||
24 | return cmd_results_new(CMD_INVALID, "repeat_rate", | 20 | return cmd_results_new(CMD_INVALID, "repeat_rate", |
25 | "Repeat rate cannot be negative"); | 21 | "Repeat rate cannot be negative"); |
26 | } | 22 | } |
27 | new_config->repeat_rate = repeat_rate; | 23 | ic->repeat_rate = repeat_rate; |
28 | 24 | ||
29 | apply_input_config(new_config); | ||
30 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
31 | } | 26 | } |
diff --git a/sway/commands/input/scroll_button.c b/sway/commands/input/scroll_button.c index 350fcca2..1958f23c 100644 --- a/sway/commands/input/scroll_button.c +++ b/sway/commands/input/scroll_button.c | |||
@@ -10,35 +10,28 @@ struct cmd_results *input_cmd_scroll_button(int argc, char **argv) { | |||
10 | if ((error = checkarg(argc, "scroll_button", EXPECTED_AT_LEAST, 1))) { | 10 | if ((error = checkarg(argc, "scroll_button", EXPECTED_AT_LEAST, 1))) { |
11 | return error; | 11 | return error; |
12 | } | 12 | } |
13 | struct input_config *current_input_config = | 13 | struct input_config *ic = config->handler_context.input_config; |
14 | config->handler_context.input_config; | 14 | if (!ic) { |
15 | if (!current_input_config) { | ||
16 | return cmd_results_new(CMD_FAILURE, "scroll_button", | 15 | return cmd_results_new(CMD_FAILURE, "scroll_button", |
17 | "No input device defined."); | 16 | "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | errno = 0; | 19 | errno = 0; |
23 | char *endptr; | 20 | char *endptr; |
24 | int scroll_button = strtol(*argv, &endptr, 10); | 21 | int scroll_button = strtol(*argv, &endptr, 10); |
25 | if (endptr == *argv && scroll_button == 0) { | 22 | if (endptr == *argv && scroll_button == 0) { |
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "scroll_button", | 23 | return cmd_results_new(CMD_INVALID, "scroll_button", |
28 | "Scroll button identifier must be an integer."); | 24 | "Scroll button identifier must be an integer."); |
29 | } | 25 | } |
30 | if (errno == ERANGE) { | 26 | if (errno == ERANGE) { |
31 | free_input_config(new_config); | ||
32 | return cmd_results_new(CMD_INVALID, "scroll_button", | 27 | return cmd_results_new(CMD_INVALID, "scroll_button", |
33 | "Scroll button identifier out of range."); | 28 | "Scroll button identifier out of range."); |
34 | } | 29 | } |
35 | if (scroll_button < 0) { | 30 | if (scroll_button < 0) { |
36 | free_input_config(new_config); | ||
37 | return cmd_results_new(CMD_INVALID, "scroll_button", | 31 | return cmd_results_new(CMD_INVALID, "scroll_button", |
38 | "Scroll button identifier cannot be negative."); | 32 | "Scroll button identifier cannot be negative."); |
39 | } | 33 | } |
40 | new_config->scroll_button = scroll_button; | 34 | ic->scroll_button = scroll_button; |
41 | 35 | ||
42 | apply_input_config(new_config); | ||
43 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
44 | } | 37 | } |
diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c index 4c6ac6b6..c116b052 100644 --- a/sway/commands/input/scroll_method.c +++ b/sway/commands/input/scroll_method.c | |||
@@ -9,29 +9,24 @@ struct cmd_results *input_cmd_scroll_method(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) { | 9 | if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, "scroll_method", | 14 | return cmd_results_new(CMD_FAILURE, "scroll_method", |
16 | "No input device defined."); | 15 | "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | if (strcasecmp(argv[0], "none") == 0) { | 18 | if (strcasecmp(argv[0], "none") == 0) { |
22 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; | 19 | ic->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; |
23 | } else if (strcasecmp(argv[0], "two_finger") == 0) { | 20 | } else if (strcasecmp(argv[0], "two_finger") == 0) { |
24 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; | 21 | ic->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; |
25 | } else if (strcasecmp(argv[0], "edge") == 0) { | 22 | } else if (strcasecmp(argv[0], "edge") == 0) { |
26 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; | 23 | ic->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; |
27 | } else if (strcasecmp(argv[0], "on_button_down") == 0) { | 24 | } else if (strcasecmp(argv[0], "on_button_down") == 0) { |
28 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; | 25 | ic->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; |
29 | } else { | 26 | } else { |
30 | free_input_config(new_config); | ||
31 | return cmd_results_new(CMD_INVALID, "scroll_method", | 27 | return cmd_results_new(CMD_INVALID, "scroll_method", |
32 | "Expected 'scroll_method <none|two_finger|edge|on_button_down>'"); | 28 | "Expected 'scroll_method <none|two_finger|edge|on_button_down>'"); |
33 | } | 29 | } |
34 | 30 | ||
35 | apply_input_config(new_config); | ||
36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
37 | } | 32 | } |
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c index ac3b8237..c455b696 100644 --- a/sway/commands/input/tap.c +++ b/sway/commands/input/tap.c | |||
@@ -11,22 +11,16 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) { | |||
11 | if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { | 11 | if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { |
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct input_config *current_input_config = | 14 | struct input_config *ic = config->handler_context.input_config; |
15 | config->handler_context.input_config; | 15 | if (!ic) { |
16 | if (!current_input_config) { | ||
17 | return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); | 16 | return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); |
18 | } | 17 | } |
19 | struct input_config *new_config = | ||
20 | new_input_config(current_input_config->identifier); | ||
21 | 18 | ||
22 | if (parse_boolean(argv[0], true)) { | 19 | if (parse_boolean(argv[0], true)) { |
23 | new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; | 20 | ic->tap = LIBINPUT_CONFIG_TAP_ENABLED; |
24 | } else { | 21 | } else { |
25 | new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; | 22 | ic->tap = LIBINPUT_CONFIG_TAP_DISABLED; |
26 | } | 23 | } |
27 | 24 | ||
28 | wlr_log(WLR_DEBUG, "apply-tap for device: %s", | ||
29 | current_input_config->identifier); | ||
30 | apply_input_config(new_config); | ||
31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
32 | } | 26 | } |
diff --git a/sway/commands/input/tap_button_map.c b/sway/commands/input/tap_button_map.c index bdbba472..dff2985b 100644 --- a/sway/commands/input/tap_button_map.c +++ b/sway/commands/input/tap_button_map.c | |||
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) { | 9 | if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, "tap_button_map", | 14 | return cmd_results_new(CMD_FAILURE, "tap_button_map", |
16 | "No input device defined."); | 15 | "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | if (strcasecmp(argv[0], "lrm") == 0) { | 18 | if (strcasecmp(argv[0], "lrm") == 0) { |
22 | new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; | 19 | ic->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; |
23 | } else if (strcasecmp(argv[0], "lmr") == 0) { | 20 | } else if (strcasecmp(argv[0], "lmr") == 0) { |
24 | new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR; | 21 | ic->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR; |
25 | } else { | 22 | } else { |
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "tap_button_map", | 23 | return cmd_results_new(CMD_INVALID, "tap_button_map", |
28 | "Expected 'tap_button_map <lrm|lmr>'"); | 24 | "Expected 'tap_button_map <lrm|lmr>'"); |
29 | } | 25 | } |
30 | 26 | ||
31 | apply_input_config(new_config); | ||
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
33 | } | 28 | } |
diff --git a/sway/commands/input/xkb_capslock.c b/sway/commands/input/xkb_capslock.c index 5442c463..669b4ea9 100644 --- a/sway/commands/input/xkb_capslock.c +++ b/sway/commands/input/xkb_capslock.c | |||
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_xkb_capslock(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_capslock", EXPECTED_AT_LEAST, 1))) { | 9 | if ((error = checkarg(argc, "xkb_capslock", EXPECTED_AT_LEAST, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, "xkb_capslock", | 14 | return cmd_results_new(CMD_FAILURE, "xkb_capslock", |
16 | "No input device defined."); | 15 | "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 18 | if (strcasecmp(argv[0], "enabled") == 0) { |
22 | new_config->xkb_capslock = 1; | 19 | ic->xkb_capslock = 1; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | 20 | } else if (strcasecmp(argv[0], "disabled") == 0) { |
24 | new_config->xkb_capslock = 0; | 21 | ic->xkb_capslock = 0; |
25 | } else { | 22 | } else { |
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "xkb_capslock", | 23 | return cmd_results_new(CMD_INVALID, "xkb_capslock", |
28 | "Expected 'xkb_capslock <enabled|disabled>'"); | 24 | "Expected 'xkb_capslock <enabled|disabled>'"); |
29 | } | 25 | } |
30 | 26 | ||
31 | apply_input_config(new_config); | ||
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
33 | } | 28 | } |
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c index 9fa5a344..5fccd4a3 100644 --- a/sway/commands/input/xkb_layout.c +++ b/sway/commands/input/xkb_layout.c | |||
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | 14 | return cmd_results_new(CMD_FAILURE, "xkb_layout", |
15 | return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined."); | 15 | "No input device defined."); |
16 | } | 16 | } |
17 | struct input_config *new_config = | ||
18 | new_input_config(current_input_config->identifier); | ||
19 | 17 | ||
20 | new_config->xkb_layout = strdup(argv[0]); | 18 | ic->xkb_layout = strdup(argv[0]); |
21 | 19 | ||
22 | wlr_log(WLR_DEBUG, "apply-xkb_layout for device: %s layout: %s", | 20 | wlr_log(WLR_DEBUG, "set-xkb_layout for config: %s layout: %s", |
23 | current_input_config->identifier, new_config->xkb_layout); | 21 | ic->identifier, ic->xkb_layout); |
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 23 | } |
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c index 0d082625..c4d04638 100644 --- a/sway/commands/input/xkb_model.c +++ b/sway/commands/input/xkb_model.c | |||
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_model(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | 14 | return cmd_results_new(CMD_FAILURE, "xkb_model", |
15 | return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined."); | 15 | "No input device defined."); |
16 | } | 16 | } |
17 | struct input_config *new_config = | ||
18 | new_input_config(current_input_config->identifier); | ||
19 | 17 | ||
20 | new_config->xkb_model = strdup(argv[0]); | 18 | ic->xkb_model = strdup(argv[0]); |
21 | 19 | ||
22 | wlr_log(WLR_DEBUG, "apply-xkb_model for device: %s model: %s", | 20 | wlr_log(WLR_DEBUG, "set-xkb_model for config: %s model: %s", |
23 | current_input_config->identifier, new_config->xkb_model); | 21 | ic->identifier, ic->xkb_model); |
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 23 | } |
diff --git a/sway/commands/input/xkb_numlock.c b/sway/commands/input/xkb_numlock.c index 39675366..1367da44 100644 --- a/sway/commands/input/xkb_numlock.c +++ b/sway/commands/input/xkb_numlock.c | |||
@@ -9,25 +9,20 @@ struct cmd_results *input_cmd_xkb_numlock(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_numlock", EXPECTED_AT_LEAST, 1))) { | 9 | if ((error = checkarg(argc, "xkb_numlock", EXPECTED_AT_LEAST, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, "xkb_numlock", | 14 | return cmd_results_new(CMD_FAILURE, "xkb_numlock", |
16 | "No input device defined."); | 15 | "No input device defined."); |
17 | } | 16 | } |
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | 17 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 18 | if (strcasecmp(argv[0], "enabled") == 0) { |
22 | new_config->xkb_numlock = 1; | 19 | ic->xkb_numlock = 1; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | 20 | } else if (strcasecmp(argv[0], "disabled") == 0) { |
24 | new_config->xkb_numlock = 0; | 21 | ic->xkb_numlock = 0; |
25 | } else { | 22 | } else { |
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "xkb_numlock", | 23 | return cmd_results_new(CMD_INVALID, "xkb_numlock", |
28 | "Expected 'xkb_numlock <enabled|disabled>'"); | 24 | "Expected 'xkb_numlock <enabled|disabled>'"); |
29 | } | 25 | } |
30 | 26 | ||
31 | apply_input_config(new_config); | ||
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
33 | } | 28 | } |
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c index 3059d941..794ab6e9 100644 --- a/sway/commands/input/xkb_options.c +++ b/sway/commands/input/xkb_options.c | |||
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_options(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | 14 | return cmd_results_new(CMD_FAILURE, "xkb_options", |
15 | return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined."); | 15 | "No input device defined."); |
16 | } | 16 | } |
17 | struct input_config *new_config = | ||
18 | new_input_config(current_input_config->identifier); | ||
19 | 17 | ||
20 | new_config->xkb_options = strdup(argv[0]); | 18 | ic->xkb_options = strdup(argv[0]); |
21 | 19 | ||
22 | wlr_log(WLR_DEBUG, "apply-xkb_options for device: %s options: %s", | 20 | wlr_log(WLR_DEBUG, "set-xkb_options for config: %s options: %s", |
23 | current_input_config->identifier, new_config->xkb_options); | 21 | ic->identifier, ic->xkb_options); |
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 23 | } |
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c index 560f088e..257c3288 100644 --- a/sway/commands/input/xkb_rules.c +++ b/sway/commands/input/xkb_rules.c | |||
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | 14 | return cmd_results_new(CMD_FAILURE, "xkb_rules", |
15 | return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined."); | 15 | "No input device defined."); |
16 | } | 16 | } |
17 | struct input_config *new_config = | ||
18 | new_input_config(current_input_config->identifier); | ||
19 | 17 | ||
20 | new_config->xkb_rules = strdup(argv[0]); | 18 | ic->xkb_rules = strdup(argv[0]); |
21 | 19 | ||
22 | wlr_log(WLR_DEBUG, "apply-xkb_rules for device: %s rules: %s", | 20 | wlr_log(WLR_DEBUG, "set-xkb_rules for config: %s rules: %s", |
23 | current_input_config->identifier, new_config->xkb_rules); | 21 | ic->identifier, ic->xkb_rules); |
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 23 | } |
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c index 0aa03440..3832dc8e 100644 --- a/sway/commands/input/xkb_variant.c +++ b/sway/commands/input/xkb_variant.c | |||
@@ -9,18 +9,15 @@ struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) { | |||
9 | if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) { | 9 | if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) { |
10 | return error; | 10 | return error; |
11 | } | 11 | } |
12 | struct input_config *current_input_config = | 12 | struct input_config *ic = config->handler_context.input_config; |
13 | config->handler_context.input_config; | 13 | if (!ic) { |
14 | if (!current_input_config) { | 14 | return cmd_results_new(CMD_FAILURE, "xkb_variant", |
15 | return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined."); | 15 | "No input device defined."); |
16 | } | 16 | } |
17 | struct input_config *new_config = | ||
18 | new_input_config(current_input_config->identifier); | ||
19 | 17 | ||
20 | new_config->xkb_variant = strdup(argv[0]); | 18 | ic->xkb_variant = strdup(argv[0]); |
21 | 19 | ||
22 | wlr_log(WLR_DEBUG, "apply-xkb_variant for device: %s variant: %s", | 20 | wlr_log(WLR_DEBUG, "set-xkb_variant for config: %s variant: %s", |
23 | current_input_config->identifier, new_config->xkb_variant); | 21 | ic->identifier, ic->xkb_variant); |
24 | apply_input_config(new_config); | ||
25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
26 | } | 23 | } |
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index ef3ec1cb..c2ce2e78 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -138,15 +138,14 @@ struct cmd_results *cmd_layout(int argc, char **argv) { | |||
138 | } | 138 | } |
139 | container->layout = new_layout; | 139 | container->layout = new_layout; |
140 | container_update_representation(container); | 140 | container_update_representation(container); |
141 | arrange_container(container); | ||
142 | } else { | 141 | } else { |
143 | if (old_layout != L_TABBED && old_layout != L_STACKED) { | 142 | if (old_layout != L_TABBED && old_layout != L_STACKED) { |
144 | workspace->prev_split_layout = old_layout; | 143 | workspace->prev_split_layout = old_layout; |
145 | } | 144 | } |
146 | workspace->layout = new_layout; | 145 | workspace->layout = new_layout; |
147 | workspace_update_representation(workspace); | 146 | workspace_update_representation(workspace); |
148 | arrange_workspace(workspace); | ||
149 | } | 147 | } |
148 | arrange_workspace(workspace); | ||
150 | } | 149 | } |
151 | 150 | ||
152 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 151 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 849a18ad..fc2f1cc1 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -259,50 +259,24 @@ static void container_move_to_container(struct sway_container *container, | |||
259 | * In other words, rejigger it. */ | 259 | * In other words, rejigger it. */ |
260 | static void workspace_rejigger(struct sway_workspace *ws, | 260 | static void workspace_rejigger(struct sway_workspace *ws, |
261 | struct sway_container *child, enum movement_direction move_dir) { | 261 | struct sway_container *child, enum movement_direction move_dir) { |
262 | if (!child->parent && ws->tiling->length == 1) { | ||
263 | ws->layout = | ||
264 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | ||
265 | workspace_update_representation(ws); | ||
266 | return; | ||
267 | } | ||
262 | container_detach(child); | 268 | container_detach(child); |
263 | workspace_wrap_children(ws); | 269 | struct sway_container *new_parent = workspace_wrap_children(ws); |
264 | 270 | ||
265 | int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; | 271 | int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; |
266 | workspace_insert_tiling(ws, child, index); | 272 | workspace_insert_tiling(ws, child, index); |
273 | container_flatten(new_parent); | ||
267 | ws->layout = | 274 | ws->layout = |
268 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 275 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; |
269 | workspace_update_representation(ws); | 276 | workspace_update_representation(ws); |
270 | child->width = child->height = 0; | 277 | child->width = child->height = 0; |
271 | } | 278 | } |
272 | 279 | ||
273 | static void move_out_of_tabs_stacks(struct sway_container *container, | ||
274 | struct sway_container *current, enum movement_direction move_dir, | ||
275 | int offs) { | ||
276 | enum sway_container_layout layout = move_dir == | ||
277 | MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | ||
278 | list_t *siblings = container_get_siblings(container); | ||
279 | if (container == current && siblings->length == 1) { | ||
280 | wlr_log(WLR_DEBUG, "Changing layout of parent"); | ||
281 | if (container->parent) { | ||
282 | container->parent->layout = layout; | ||
283 | container_update_representation(container); | ||
284 | } else { | ||
285 | container->workspace->layout = layout; | ||
286 | workspace_update_representation(container->workspace); | ||
287 | } | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); | ||
292 | if (current->parent) { | ||
293 | struct sway_container *new_parent = | ||
294 | container_split(current->parent, layout); | ||
295 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); | ||
296 | container_reap_empty(new_parent); | ||
297 | container_flatten(new_parent); | ||
298 | } else { | ||
299 | // Changing a workspace | ||
300 | struct sway_workspace *workspace = container->workspace; | ||
301 | workspace_split(workspace, layout); | ||
302 | workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | // Returns true if moved | 280 | // Returns true if moved |
307 | static bool container_move_in_direction(struct sway_container *container, | 281 | static bool container_move_in_direction(struct sway_container *container, |
308 | enum movement_direction move_dir) { | 282 | enum movement_direction move_dir) { |
@@ -334,7 +308,6 @@ static bool container_move_in_direction(struct sway_container *container, | |||
334 | int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; | 308 | int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; |
335 | 309 | ||
336 | while (current) { | 310 | while (current) { |
337 | struct sway_container *parent = current->parent; | ||
338 | list_t *siblings = container_get_siblings(current); | 311 | list_t *siblings = container_get_siblings(current); |
339 | enum sway_container_layout layout = container_parent_layout(current); | 312 | enum sway_container_layout layout = container_parent_layout(current); |
340 | int index = list_find(siblings, current); | 313 | int index = list_find(siblings, current); |
@@ -343,15 +316,8 @@ static bool container_move_in_direction(struct sway_container *container, | |||
343 | if (is_parallel(layout, move_dir)) { | 316 | if (is_parallel(layout, move_dir)) { |
344 | if (desired == -1 || desired == siblings->length) { | 317 | if (desired == -1 || desired == siblings->length) { |
345 | if (current->parent == container->parent) { | 318 | if (current->parent == container->parent) { |
346 | if (!(parent && parent->is_fullscreen) && | 319 | current = current->parent; |
347 | (layout == L_TABBED || layout == L_STACKED)) { | 320 | continue; |
348 | move_out_of_tabs_stacks(container, current, | ||
349 | move_dir, offs); | ||
350 | return true; | ||
351 | } else { | ||
352 | current = current->parent; | ||
353 | continue; | ||
354 | } | ||
355 | } else { | 321 | } else { |
356 | // Special case | 322 | // Special case |
357 | if (current->parent) { | 323 | if (current->parent) { |
@@ -369,10 +335,6 @@ static bool container_move_in_direction(struct sway_container *container, | |||
369 | siblings->items[desired], move_dir); | 335 | siblings->items[desired], move_dir); |
370 | return true; | 336 | return true; |
371 | } | 337 | } |
372 | } else if (!(parent && parent->is_fullscreen) && | ||
373 | (layout == L_TABBED || layout == L_STACKED)) { | ||
374 | move_out_of_tabs_stacks(container, current, move_dir, offs); | ||
375 | return true; | ||
376 | } | 338 | } |
377 | 339 | ||
378 | current = current->parent; | 340 | current = current->parent; |
@@ -388,10 +350,8 @@ static bool container_move_in_direction(struct sway_container *container, | |||
388 | // Maybe rejigger the workspace | 350 | // Maybe rejigger the workspace |
389 | struct sway_workspace *ws = container->workspace; | 351 | struct sway_workspace *ws = container->workspace; |
390 | if (!is_parallel(ws->layout, move_dir)) { | 352 | if (!is_parallel(ws->layout, move_dir)) { |
391 | if (ws->tiling->length >= 2) { | 353 | workspace_rejigger(ws, container, move_dir); |
392 | workspace_rejigger(ws, container, move_dir); | 354 | return true; |
393 | return true; | ||
394 | } | ||
395 | } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) { | 355 | } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) { |
396 | workspace_rejigger(ws, container, move_dir); | 356 | workspace_rejigger(ws, container, move_dir); |
397 | return true; | 357 | return true; |
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index 9e370d43..30fb47c4 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c | |||
@@ -123,19 +123,13 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { | |||
123 | } | 123 | } |
124 | free(src); | 124 | free(src); |
125 | } else { | 125 | } else { |
126 | // Escape spaces and quotes in the final path for swaybg | 126 | // Escape double quotes in the final path for swaybg |
127 | for (size_t i = 0; i < strlen(src); i++) { | 127 | for (size_t i = 0; i < strlen(src); i++) { |
128 | switch (src[i]) { | 128 | if (src[i] == '"') { |
129 | case ' ': | 129 | src = realloc(src, strlen(src) + 2); |
130 | case '\'': | 130 | memmove(src + i + 1, src + i, strlen(src + i) + 1); |
131 | case '\"': | 131 | *(src + i) = '\\'; |
132 | src = realloc(src, strlen(src) + 2); | 132 | i++; |
133 | memmove(src + i + 1, src + i, strlen(src + i) + 1); | ||
134 | *(src + i) = '\\'; | ||
135 | i++; | ||
136 | break; | ||
137 | default: | ||
138 | break; | ||
139 | } | 133 | } |
140 | } | 134 | } |
141 | 135 | ||
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 99e9dbda..1343b165 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -179,11 +179,11 @@ static void container_recursive_resize(struct sway_container *container, | |||
179 | } | 179 | } |
180 | } | 180 | } |
181 | 181 | ||
182 | static void resize_tiled(struct sway_container *parent, int amount, | 182 | static bool resize_tiled(struct sway_container *parent, int amount, |
183 | enum resize_axis axis) { | 183 | enum resize_axis axis) { |
184 | struct sway_container *focused = parent; | 184 | struct sway_container *focused = parent; |
185 | if (!parent) { | 185 | if (!parent) { |
186 | return; | 186 | return false; |
187 | } | 187 | } |
188 | 188 | ||
189 | enum sway_container_layout parallel_layout = | 189 | enum sway_container_layout parallel_layout = |
@@ -216,7 +216,7 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
216 | } | 216 | } |
217 | if (!parent) { | 217 | if (!parent) { |
218 | // Can't resize in this direction | 218 | // Can't resize in this direction |
219 | return; | 219 | return false; |
220 | } | 220 | } |
221 | 221 | ||
222 | // Implement up/down/left/right direction by zeroing one of the weights, | 222 | // Implement up/down/left/right direction by zeroing one of the weights, |
@@ -248,22 +248,22 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
248 | if (sibling_pos < parent_pos && minor_weight) { | 248 | if (sibling_pos < parent_pos && minor_weight) { |
249 | double pixels = -amount / minor_weight; | 249 | double pixels = -amount / minor_weight; |
250 | if (major_weight && (sibling_size + pixels / 2) < min_sane) { | 250 | if (major_weight && (sibling_size + pixels / 2) < min_sane) { |
251 | return; // Too small | 251 | return false; // Too small |
252 | } else if (!major_weight && sibling_size + pixels < min_sane) { | 252 | } else if (!major_weight && sibling_size + pixels < min_sane) { |
253 | return; // Too small | 253 | return false; // Too small |
254 | } | 254 | } |
255 | } else if (sibling_pos > parent_pos && major_weight) { | 255 | } else if (sibling_pos > parent_pos && major_weight) { |
256 | double pixels = -amount / major_weight; | 256 | double pixels = -amount / major_weight; |
257 | if (minor_weight && (sibling_size + pixels / 2) < min_sane) { | 257 | if (minor_weight && (sibling_size + pixels / 2) < min_sane) { |
258 | return; // Too small | 258 | return false; // Too small |
259 | } else if (!minor_weight && sibling_size + pixels < min_sane) { | 259 | } else if (!minor_weight && sibling_size + pixels < min_sane) { |
260 | return; // Too small | 260 | return false; // Too small |
261 | } | 261 | } |
262 | } | 262 | } |
263 | } else { | 263 | } else { |
264 | double pixels = amount; | 264 | double pixels = amount; |
265 | if (parent_size + pixels < min_sane) { | 265 | if (parent_size + pixels < min_sane) { |
266 | return; // Too small | 266 | return false; // Too small |
267 | } | 267 | } |
268 | } | 268 | } |
269 | } | 269 | } |
@@ -317,9 +317,10 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
317 | } else { | 317 | } else { |
318 | arrange_workspace(parent->workspace); | 318 | arrange_workspace(parent->workspace); |
319 | } | 319 | } |
320 | return true; | ||
320 | } | 321 | } |
321 | 322 | ||
322 | void container_resize_tiled(struct sway_container *parent, | 323 | bool container_resize_tiled(struct sway_container *parent, |
323 | enum wlr_edges edge, int amount) { | 324 | enum wlr_edges edge, int amount) { |
324 | enum resize_axis axis = RESIZE_AXIS_INVALID; | 325 | enum resize_axis axis = RESIZE_AXIS_INVALID; |
325 | switch (edge) { | 326 | switch (edge) { |
@@ -338,7 +339,7 @@ void container_resize_tiled(struct sway_container *parent, | |||
338 | case WLR_EDGE_NONE: | 339 | case WLR_EDGE_NONE: |
339 | break; | 340 | break; |
340 | } | 341 | } |
341 | resize_tiled(parent, amount, axis); | 342 | return resize_tiled(parent, amount, axis); |
342 | } | 343 | } |
343 | 344 | ||
344 | /** | 345 | /** |
@@ -395,6 +396,10 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | |||
395 | case RESIZE_AXIS_INVALID: | 396 | case RESIZE_AXIS_INVALID: |
396 | return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction"); | 397 | return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction"); |
397 | } | 398 | } |
399 | if (grow_x == 0 && grow_y == 0) { | ||
400 | return cmd_results_new(CMD_INVALID, "resize", | ||
401 | "Cannot resize any further"); | ||
402 | } | ||
398 | con->x += grow_x; | 403 | con->x += grow_x; |
399 | con->y += grow_y; | 404 | con->y += grow_y; |
400 | con->width += grow_width; | 405 | con->width += grow_width; |
@@ -442,7 +447,10 @@ static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, | |||
442 | } | 447 | } |
443 | } | 448 | } |
444 | 449 | ||
445 | resize_tiled(current, amount->amount, axis); | 450 | if (!resize_tiled(current, amount->amount, axis)) { |
451 | return cmd_results_new(CMD_INVALID, "resize", | ||
452 | "Cannot resize any further"); | ||
453 | } | ||
446 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 454 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
447 | } | 455 | } |
448 | 456 | ||
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index f026a39d..63f29641 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -10,6 +10,28 @@ | |||
10 | #include "log.h" | 10 | #include "log.h" |
11 | #include "stringop.h" | 11 | #include "stringop.h" |
12 | 12 | ||
13 | static struct workspace_config *workspace_config_find_or_create(char *ws_name) { | ||
14 | struct workspace_config *wsc = workspace_find_config(ws_name); | ||
15 | if (wsc) { | ||
16 | return wsc; | ||
17 | } | ||
18 | wsc = calloc(1, sizeof(struct workspace_config)); | ||
19 | if (!wsc) { | ||
20 | return NULL; | ||
21 | } | ||
22 | wsc->workspace = strdup(ws_name); | ||
23 | wsc->gaps_inner = -1; | ||
24 | wsc->gaps_outer = -1; | ||
25 | list_add(config->workspace_configs, wsc); | ||
26 | return wsc; | ||
27 | } | ||
28 | |||
29 | void free_workspace_config(struct workspace_config *wsc) { | ||
30 | free(wsc->workspace); | ||
31 | free(wsc->output); | ||
32 | free(wsc); | ||
33 | } | ||
34 | |||
13 | struct cmd_results *cmd_workspace(int argc, char **argv) { | 35 | struct cmd_results *cmd_workspace(int argc, char **argv) { |
14 | struct cmd_results *error = NULL; | 36 | struct cmd_results *error = NULL; |
15 | if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) { | 37 | if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1))) { |
@@ -17,6 +39,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
17 | } | 39 | } |
18 | 40 | ||
19 | int output_location = -1; | 41 | int output_location = -1; |
42 | int gaps_location = -1; | ||
20 | 43 | ||
21 | for (int i = 0; i < argc; ++i) { | 44 | for (int i = 0; i < argc; ++i) { |
22 | if (strcasecmp(argv[i], "output") == 0) { | 45 | if (strcasecmp(argv[i], "output") == 0) { |
@@ -24,25 +47,54 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
24 | break; | 47 | break; |
25 | } | 48 | } |
26 | } | 49 | } |
50 | for (int i = 0; i < argc; ++i) { | ||
51 | if (strcasecmp(argv[i], "gaps") == 0) { | ||
52 | gaps_location = i; | ||
53 | break; | ||
54 | } | ||
55 | } | ||
27 | if (output_location >= 0) { | 56 | if (output_location >= 0) { |
28 | if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) { | 57 | if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) { |
29 | return error; | 58 | return error; |
30 | } | 59 | } |
31 | struct workspace_output *wso = calloc(1, sizeof(struct workspace_output)); | 60 | char *ws_name = join_args(argv, argc - 2); |
32 | if (!wso) { | 61 | struct workspace_config *wsc = workspace_config_find_or_create(ws_name); |
62 | free(ws_name); | ||
63 | if (!wsc) { | ||
33 | return cmd_results_new(CMD_FAILURE, "workspace output", | 64 | return cmd_results_new(CMD_FAILURE, "workspace output", |
34 | "Unable to allocate workspace output"); | 65 | "Unable to allocate workspace output"); |
35 | } | 66 | } |
36 | wso->workspace = join_args(argv, argc - 2); | 67 | free(wsc->output); |
37 | wso->output = strdup(argv[output_location + 1]); | 68 | wsc->output = strdup(argv[output_location + 1]); |
38 | int i = -1; | 69 | } else if (gaps_location >= 0) { |
39 | if ((i = list_seq_find(config->workspace_outputs, workspace_output_cmp_workspace, wso)) != -1) { | 70 | if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, gaps_location + 3))) { |
40 | struct workspace_output *old = config->workspace_outputs->items[i]; | 71 | return error; |
41 | free(old); // workspaces can only be assigned to a single output | 72 | } |
42 | list_del(config->workspace_outputs, i); | 73 | char *ws_name = join_args(argv, argc - 3); |
74 | struct workspace_config *wsc = workspace_config_find_or_create(ws_name); | ||
75 | free(ws_name); | ||
76 | if (!wsc) { | ||
77 | return cmd_results_new(CMD_FAILURE, "workspace gaps", | ||
78 | "Unable to allocate workspace output"); | ||
79 | } | ||
80 | int *prop = NULL; | ||
81 | if (strcasecmp(argv[gaps_location + 1], "inner") == 0) { | ||
82 | prop = &wsc->gaps_inner; | ||
83 | } else if (strcasecmp(argv[gaps_location + 1], "outer") == 0) { | ||
84 | prop = &wsc->gaps_outer; | ||
85 | } else { | ||
86 | return cmd_results_new(CMD_FAILURE, "workspace gaps", | ||
87 | "Expected 'workspace <ws> gaps inner|outer <px>'"); | ||
88 | } | ||
89 | char *end; | ||
90 | int val = strtol(argv[gaps_location + 2], &end, 10); | ||
91 | |||
92 | if (strlen(end)) { | ||
93 | free(end); | ||
94 | return cmd_results_new(CMD_FAILURE, "workspace gaps", | ||
95 | "Expected 'workspace <ws> gaps inner|outer <px>'"); | ||
43 | } | 96 | } |
44 | wlr_log(WLR_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output); | 97 | *prop = val >= 0 ? val : 0; |
45 | list_add(config->workspace_outputs, wso); | ||
46 | } else { | 98 | } else { |
47 | if (config->reading || !config->active) { | 99 | if (config->reading || !config->active) { |
48 | return cmd_results_new(CMD_DEFER, "workspace", NULL); | 100 | return cmd_results_new(CMD_DEFER, "workspace", NULL); |
diff --git a/sway/config.c b/sway/config.c index 830fb65f..1e08559d 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -95,7 +95,12 @@ void free_config(struct sway_config *config) { | |||
95 | list_free(config->bars); | 95 | list_free(config->bars); |
96 | } | 96 | } |
97 | list_free(config->cmd_queue); | 97 | list_free(config->cmd_queue); |
98 | list_free(config->workspace_outputs); | 98 | if (config->workspace_configs) { |
99 | for (int i = 0; i < config->workspace_configs->length; i++) { | ||
100 | free_workspace_config(config->workspace_configs->items[i]); | ||
101 | } | ||
102 | list_free(config->workspace_configs); | ||
103 | } | ||
99 | if (config->output_configs) { | 104 | if (config->output_configs) { |
100 | for (int i = 0; i < config->output_configs->length; i++) { | 105 | for (int i = 0; i < config->output_configs->length; i++) { |
101 | free_output_config(config->output_configs->items[i]); | 106 | free_output_config(config->output_configs->items[i]); |
@@ -175,7 +180,7 @@ static void config_defaults(struct sway_config *config) { | |||
175 | if (!(config->symbols = create_list())) goto cleanup; | 180 | if (!(config->symbols = create_list())) goto cleanup; |
176 | if (!(config->modes = create_list())) goto cleanup; | 181 | if (!(config->modes = create_list())) goto cleanup; |
177 | if (!(config->bars = create_list())) goto cleanup; | 182 | if (!(config->bars = create_list())) goto cleanup; |
178 | if (!(config->workspace_outputs = create_list())) goto cleanup; | 183 | if (!(config->workspace_configs = create_list())) goto cleanup; |
179 | if (!(config->criteria = create_list())) goto cleanup; | 184 | if (!(config->criteria = create_list())) goto cleanup; |
180 | if (!(config->no_focus = create_list())) goto cleanup; | 185 | if (!(config->no_focus = create_list())) goto cleanup; |
181 | if (!(config->input_configs = create_list())) goto cleanup; | 186 | if (!(config->input_configs = create_list())) goto cleanup; |
@@ -804,7 +809,7 @@ char *do_var_replacement(char *str) { | |||
804 | // would compare two structs in full, while this method only compares the | 809 | // would compare two structs in full, while this method only compares the |
805 | // workspace. | 810 | // workspace. |
806 | int workspace_output_cmp_workspace(const void *a, const void *b) { | 811 | int workspace_output_cmp_workspace(const void *a, const void *b) { |
807 | const struct workspace_output *wsa = a, *wsb = b; | 812 | const struct workspace_config *wsa = a, *wsb = b; |
808 | return lenient_strcmp(wsa->workspace, wsb->workspace); | 813 | return lenient_strcmp(wsa->workspace, wsb->workspace); |
809 | } | 814 | } |
810 | 815 | ||
diff --git a/sway/config/bar.c b/sway/config/bar.c index f83b37d1..48a632fb 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -165,7 +165,7 @@ cleanup: | |||
165 | return NULL; | 165 | return NULL; |
166 | } | 166 | } |
167 | 167 | ||
168 | void invoke_swaybar(struct bar_config *bar) { | 168 | static void invoke_swaybar(struct bar_config *bar) { |
169 | // Pipe to communicate errors | 169 | // Pipe to communicate errors |
170 | int filedes[2]; | 170 | int filedes[2]; |
171 | if (pipe(filedes) == -1) { | 171 | if (pipe(filedes) == -1) { |
@@ -219,27 +219,13 @@ void invoke_swaybar(struct bar_config *bar) { | |||
219 | close(filedes[1]); | 219 | close(filedes[1]); |
220 | } | 220 | } |
221 | 221 | ||
222 | void load_swaybars() { | 222 | void load_swaybars(void) { |
223 | for (int i = 0; i < config->bars->length; ++i) { | 223 | for (int i = 0; i < config->bars->length; ++i) { |
224 | struct bar_config *bar = config->bars->items[i]; | 224 | struct bar_config *bar = config->bars->items[i]; |
225 | bool apply = false; | 225 | if (bar->pid != 0) { |
226 | if (bar->outputs) { | 226 | terminate_swaybar(bar->pid); |
227 | for (int j = 0; j < bar->outputs->length; ++j) { | ||
228 | char *o = bar->outputs->items[j]; | ||
229 | if (!strcmp(o, "*") || output_by_name(o)) { | ||
230 | apply = true; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | } else { | ||
235 | apply = true; | ||
236 | } | ||
237 | if (apply) { | ||
238 | if (bar->pid != 0) { | ||
239 | terminate_swaybar(bar->pid); | ||
240 | } | ||
241 | wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
242 | invoke_swaybar(bar); | ||
243 | } | 227 | } |
228 | wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
229 | invoke_swaybar(bar); | ||
244 | } | 230 | } |
245 | } | 231 | } |
diff --git a/sway/config/input.c b/sway/config/input.c index ad5b96c8..794d5194 100644 --- a/sway/config/input.c +++ b/sway/config/input.c | |||
@@ -20,6 +20,7 @@ struct input_config *new_input_config(const char* identifier) { | |||
20 | 20 | ||
21 | input->tap = INT_MIN; | 21 | input->tap = INT_MIN; |
22 | input->tap_button_map = INT_MIN; | 22 | input->tap_button_map = INT_MIN; |
23 | input->drag = INT_MIN; | ||
23 | input->drag_lock = INT_MIN; | 24 | input->drag_lock = INT_MIN; |
24 | input->dwt = INT_MIN; | 25 | input->dwt = INT_MIN; |
25 | input->send_events = INT_MIN; | 26 | input->send_events = INT_MIN; |
@@ -40,22 +41,24 @@ struct input_config *new_input_config(const char* identifier) { | |||
40 | } | 41 | } |
41 | 42 | ||
42 | void merge_input_config(struct input_config *dst, struct input_config *src) { | 43 | void merge_input_config(struct input_config *dst, struct input_config *src) { |
43 | if (src->identifier) { | ||
44 | free(dst->identifier); | ||
45 | dst->identifier = strdup(src->identifier); | ||
46 | } | ||
47 | if (src->accel_profile != INT_MIN) { | 44 | if (src->accel_profile != INT_MIN) { |
48 | dst->accel_profile = src->accel_profile; | 45 | dst->accel_profile = src->accel_profile; |
49 | } | 46 | } |
50 | if (src->click_method != INT_MIN) { | 47 | if (src->click_method != INT_MIN) { |
51 | dst->click_method = src->click_method; | 48 | dst->click_method = src->click_method; |
52 | } | 49 | } |
50 | if (src->drag != INT_MIN) { | ||
51 | dst->drag = src->drag; | ||
52 | } | ||
53 | if (src->drag_lock != INT_MIN) { | 53 | if (src->drag_lock != INT_MIN) { |
54 | dst->drag_lock = src->drag_lock; | 54 | dst->drag_lock = src->drag_lock; |
55 | } | 55 | } |
56 | if (src->dwt != INT_MIN) { | 56 | if (src->dwt != INT_MIN) { |
57 | dst->dwt = src->dwt; | 57 | dst->dwt = src->dwt; |
58 | } | 58 | } |
59 | if (src->left_handed != INT_MIN) { | ||
60 | dst->left_handed = src->left_handed; | ||
61 | } | ||
59 | if (src->middle_emulation != INT_MIN) { | 62 | if (src->middle_emulation != INT_MIN) { |
60 | dst->middle_emulation = src->middle_emulation; | 63 | dst->middle_emulation = src->middle_emulation; |
61 | } | 64 | } |
@@ -125,14 +128,51 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { | |||
125 | } | 128 | } |
126 | } | 129 | } |
127 | 130 | ||
128 | struct input_config *copy_input_config(struct input_config *ic) { | 131 | static void merge_wildcard_on_all(struct input_config *wildcard) { |
129 | struct input_config *copy = calloc(1, sizeof(struct input_config)); | 132 | for (int i = 0; i < config->input_configs->length; i++) { |
130 | if (copy == NULL) { | 133 | struct input_config *ic = config->input_configs->items[i]; |
131 | wlr_log(WLR_ERROR, "could not allocate input config"); | 134 | if (strcmp(wildcard->identifier, ic->identifier) != 0) { |
132 | return NULL; | 135 | wlr_log(WLR_DEBUG, "Merging input * config on %s", ic->identifier); |
136 | merge_input_config(ic, wildcard); | ||
137 | } | ||
133 | } | 138 | } |
134 | merge_input_config(copy, ic); | 139 | } |
135 | return copy; | 140 | |
141 | struct input_config *store_input_config(struct input_config *ic) { | ||
142 | bool wildcard = strcmp(ic->identifier, "*") == 0; | ||
143 | if (wildcard) { | ||
144 | merge_wildcard_on_all(ic); | ||
145 | } | ||
146 | |||
147 | int i = list_seq_find(config->input_configs, input_identifier_cmp, | ||
148 | ic->identifier); | ||
149 | if (i >= 0) { | ||
150 | wlr_log(WLR_DEBUG, "Merging on top of existing input config"); | ||
151 | struct input_config *current = config->input_configs->items[i]; | ||
152 | merge_input_config(current, ic); | ||
153 | free_input_config(ic); | ||
154 | ic = current; | ||
155 | } else if (!wildcard) { | ||
156 | wlr_log(WLR_DEBUG, "Adding non-wildcard input config"); | ||
157 | i = list_seq_find(config->input_configs, input_identifier_cmp, "*"); | ||
158 | if (i >= 0) { | ||
159 | wlr_log(WLR_DEBUG, "Merging on top of input * config"); | ||
160 | struct input_config *current = new_input_config(ic->identifier); | ||
161 | merge_input_config(current, config->input_configs->items[i]); | ||
162 | merge_input_config(current, ic); | ||
163 | free_input_config(ic); | ||
164 | ic = current; | ||
165 | } | ||
166 | list_add(config->input_configs, ic); | ||
167 | } else { | ||
168 | // New wildcard config. Just add it | ||
169 | wlr_log(WLR_DEBUG, "Adding input * config"); | ||
170 | list_add(config->input_configs, ic); | ||
171 | } | ||
172 | |||
173 | wlr_log(WLR_DEBUG, "Config stored for input %s", ic->identifier); | ||
174 | |||
175 | return ic; | ||
136 | } | 176 | } |
137 | 177 | ||
138 | void free_input_config(struct input_config *ic) { | 178 | void free_input_config(struct input_config *ic) { |
diff --git a/sway/config/output.c b/sway/config/output.c index 74d79130..6f337b66 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -237,7 +237,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
237 | wlr_log(WLR_DEBUG, "Setting background for output %d to %s", | 237 | wlr_log(WLR_DEBUG, "Setting background for output %d to %s", |
238 | output_i, oc->background); | 238 | output_i, oc->background); |
239 | 239 | ||
240 | size_t len = snprintf(NULL, 0, "%s %d %s %s %s", | 240 | size_t len = snprintf(NULL, 0, "%s %d \"%s\" %s %s", |
241 | config->swaybg_command ? config->swaybg_command : "swaybg", | 241 | config->swaybg_command ? config->swaybg_command : "swaybg", |
242 | output_i, oc->background, oc->background_option, | 242 | output_i, oc->background, oc->background_option, |
243 | oc->background_fallback ? oc->background_fallback : ""); | 243 | oc->background_fallback ? oc->background_fallback : ""); |
@@ -246,7 +246,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
246 | wlr_log(WLR_DEBUG, "Unable to allocate swaybg command"); | 246 | wlr_log(WLR_DEBUG, "Unable to allocate swaybg command"); |
247 | return; | 247 | return; |
248 | } | 248 | } |
249 | snprintf(command, len + 1, "%s %d %s %s %s", | 249 | snprintf(command, len + 1, "%s %d \"%s\" %s %s", |
250 | config->swaybg_command ? config->swaybg_command : "swaybg", | 250 | config->swaybg_command ? config->swaybg_command : "swaybg", |
251 | output_i, oc->background, oc->background_option, | 251 | output_i, oc->background, oc->background_option, |
252 | oc->background_fallback ? oc->background_fallback : ""); | 252 | oc->background_fallback ? oc->background_fallback : ""); |
diff --git a/sway/config/seat.c b/sway/config/seat.c index 83dac4c0..46456caf 100644 --- a/sway/config/seat.c +++ b/sway/config/seat.c | |||
@@ -30,7 +30,7 @@ struct seat_config *new_seat_config(const char* name) { | |||
30 | return seat; | 30 | return seat; |
31 | } | 31 | } |
32 | 32 | ||
33 | struct seat_attachment_config *seat_attachment_config_new() { | 33 | struct seat_attachment_config *seat_attachment_config_new(void) { |
34 | struct seat_attachment_config *attachment = | 34 | struct seat_attachment_config *attachment = |
35 | calloc(1, sizeof(struct seat_attachment_config)); | 35 | calloc(1, sizeof(struct seat_attachment_config)); |
36 | if (!attachment) { | 36 | if (!attachment) { |
diff --git a/sway/debug-tree.c b/sway/debug-tree.c index 9644f4e5..16b479f9 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c | |||
@@ -120,7 +120,7 @@ static int draw_node(cairo_t *cairo, struct sway_node *node, | |||
120 | return height; | 120 | return height; |
121 | } | 121 | } |
122 | 122 | ||
123 | void update_debug_tree() { | 123 | void update_debug_tree(void) { |
124 | if (!debug.render_tree) { | 124 | if (!debug.render_tree) { |
125 | return; | 125 | return; |
126 | } | 126 | } |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d747e279..34d99d52 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <time.h> | 7 | #include <time.h> |
8 | #include <wlr/types/wlr_buffer.h> | 8 | #include <wlr/types/wlr_buffer.h> |
9 | #include "sway/config.h" | ||
9 | #include "sway/debug.h" | 10 | #include "sway/debug.h" |
10 | #include "sway/desktop.h" | 11 | #include "sway/desktop.h" |
11 | #include "sway/desktop/idle_inhibit_v1.h" | 12 | #include "sway/desktop/idle_inhibit_v1.h" |
@@ -30,14 +31,14 @@ struct sway_transaction_instruction { | |||
30 | struct sway_transaction *transaction; | 31 | struct sway_transaction *transaction; |
31 | struct sway_node *node; | 32 | struct sway_node *node; |
32 | union { | 33 | union { |
33 | struct sway_output_state *output_state; | 34 | struct sway_output_state output_state; |
34 | struct sway_workspace_state *workspace_state; | 35 | struct sway_workspace_state workspace_state; |
35 | struct sway_container_state *container_state; | 36 | struct sway_container_state container_state; |
36 | }; | 37 | }; |
37 | uint32_t serial; | 38 | uint32_t serial; |
38 | }; | 39 | }; |
39 | 40 | ||
40 | static struct sway_transaction *transaction_create() { | 41 | static struct sway_transaction *transaction_create(void) { |
41 | struct sway_transaction *transaction = | 42 | struct sway_transaction *transaction = |
42 | calloc(1, sizeof(struct sway_transaction)); | 43 | calloc(1, sizeof(struct sway_transaction)); |
43 | if (!sway_assert(transaction, "Unable to allocate transaction")) { | 44 | if (!sway_assert(transaction, "Unable to allocate transaction")) { |
@@ -85,14 +86,7 @@ static void transaction_destroy(struct sway_transaction *transaction) { | |||
85 | 86 | ||
86 | static void copy_output_state(struct sway_output *output, | 87 | static void copy_output_state(struct sway_output *output, |
87 | struct sway_transaction_instruction *instruction) { | 88 | struct sway_transaction_instruction *instruction) { |
88 | struct sway_output_state *state = | 89 | struct sway_output_state *state = &instruction->output_state; |
89 | calloc(1, sizeof(struct sway_output_state)); | ||
90 | if (!state) { | ||
91 | wlr_log(WLR_ERROR, "Could not allocate output state"); | ||
92 | return; | ||
93 | } | ||
94 | instruction->output_state = state; | ||
95 | |||
96 | state->workspaces = create_list(); | 90 | state->workspaces = create_list(); |
97 | list_cat(state->workspaces, output->workspaces); | 91 | list_cat(state->workspaces, output->workspaces); |
98 | 92 | ||
@@ -101,13 +95,7 @@ static void copy_output_state(struct sway_output *output, | |||
101 | 95 | ||
102 | static void copy_workspace_state(struct sway_workspace *ws, | 96 | static void copy_workspace_state(struct sway_workspace *ws, |
103 | struct sway_transaction_instruction *instruction) { | 97 | struct sway_transaction_instruction *instruction) { |
104 | struct sway_workspace_state *state = | 98 | struct sway_workspace_state *state = &instruction->workspace_state; |
105 | calloc(1, sizeof(struct sway_workspace_state)); | ||
106 | if (!state) { | ||
107 | wlr_log(WLR_ERROR, "Could not allocate workspace state"); | ||
108 | return; | ||
109 | } | ||
110 | instruction->workspace_state = state; | ||
111 | 99 | ||
112 | state->fullscreen = ws->fullscreen; | 100 | state->fullscreen = ws->fullscreen; |
113 | state->x = ws->x; | 101 | state->x = ws->x; |
@@ -137,13 +125,7 @@ static void copy_workspace_state(struct sway_workspace *ws, | |||
137 | 125 | ||
138 | static void copy_container_state(struct sway_container *container, | 126 | static void copy_container_state(struct sway_container *container, |
139 | struct sway_transaction_instruction *instruction) { | 127 | struct sway_transaction_instruction *instruction) { |
140 | struct sway_container_state *state = | 128 | struct sway_container_state *state = &instruction->container_state; |
141 | calloc(1, sizeof(struct sway_container_state)); | ||
142 | if (!state) { | ||
143 | wlr_log(WLR_ERROR, "Could not allocate container state"); | ||
144 | return; | ||
145 | } | ||
146 | instruction->container_state = state; | ||
147 | 129 | ||
148 | state->layout = container->layout; | 130 | state->layout = container->layout; |
149 | state->con_x = container->x; | 131 | state->con_x = container->x; |
@@ -300,15 +282,15 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
300 | case N_ROOT: | 282 | case N_ROOT: |
301 | break; | 283 | break; |
302 | case N_OUTPUT: | 284 | case N_OUTPUT: |
303 | apply_output_state(node->sway_output, instruction->output_state); | 285 | apply_output_state(node->sway_output, &instruction->output_state); |
304 | break; | 286 | break; |
305 | case N_WORKSPACE: | 287 | case N_WORKSPACE: |
306 | apply_workspace_state(node->sway_workspace, | 288 | apply_workspace_state(node->sway_workspace, |
307 | instruction->workspace_state); | 289 | &instruction->workspace_state); |
308 | break; | 290 | break; |
309 | case N_CONTAINER: | 291 | case N_CONTAINER: |
310 | apply_container_state(node->sway_container, | 292 | apply_container_state(node->sway_container, |
311 | instruction->container_state); | 293 | &instruction->container_state); |
312 | break; | 294 | break; |
313 | } | 295 | } |
314 | 296 | ||
@@ -334,7 +316,7 @@ static bool transaction_same_nodes(struct sway_transaction *a, | |||
334 | return true; | 316 | return true; |
335 | } | 317 | } |
336 | 318 | ||
337 | static void transaction_progress_queue() { | 319 | static void transaction_progress_queue(void) { |
338 | if (!server.transactions->length) { | 320 | if (!server.transactions->length) { |
339 | return; | 321 | return; |
340 | } | 322 | } |
@@ -389,7 +371,17 @@ static bool should_configure(struct sway_node *node, | |||
389 | return false; | 371 | return false; |
390 | } | 372 | } |
391 | struct sway_container_state *cstate = &node->sway_container->current; | 373 | struct sway_container_state *cstate = &node->sway_container->current; |
392 | struct sway_container_state *istate = instruction->container_state; | 374 | struct sway_container_state *istate = &instruction->container_state; |
375 | #ifdef HAVE_XWAYLAND | ||
376 | // Xwayland views are position-aware and need to be reconfigured | ||
377 | // when their position changes. | ||
378 | if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) { | ||
379 | if (cstate->view_x != istate->view_x || | ||
380 | cstate->view_y != istate->view_y) { | ||
381 | return true; | ||
382 | } | ||
383 | } | ||
384 | #endif | ||
393 | if (cstate->view_width == istate->view_width && | 385 | if (cstate->view_width == istate->view_width && |
394 | cstate->view_height == istate->view_height) { | 386 | cstate->view_height == istate->view_height) { |
395 | return false; | 387 | return false; |
@@ -407,10 +399,10 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
407 | struct sway_node *node = instruction->node; | 399 | struct sway_node *node = instruction->node; |
408 | if (should_configure(node, instruction)) { | 400 | if (should_configure(node, instruction)) { |
409 | instruction->serial = view_configure(node->sway_container->view, | 401 | instruction->serial = view_configure(node->sway_container->view, |
410 | instruction->container_state->view_x, | 402 | instruction->container_state.view_x, |
411 | instruction->container_state->view_y, | 403 | instruction->container_state.view_y, |
412 | instruction->container_state->view_width, | 404 | instruction->container_state.view_width, |
413 | instruction->container_state->view_height); | 405 | instruction->container_state.view_height); |
414 | ++transaction->num_waiting; | 406 | ++transaction->num_waiting; |
415 | 407 | ||
416 | // From here on we are rendering a saved buffer of the view, which | 408 | // From here on we are rendering a saved buffer of the view, which |
@@ -502,8 +494,8 @@ void transaction_notify_view_ready_by_size(struct sway_view *view, | |||
502 | int width, int height) { | 494 | int width, int height) { |
503 | struct sway_transaction_instruction *instruction = | 495 | struct sway_transaction_instruction *instruction = |
504 | view->container->node.instruction; | 496 | view->container->node.instruction; |
505 | if (instruction->container_state->view_width == width && | 497 | if (instruction->container_state.view_width == width && |
506 | instruction->container_state->view_height == height) { | 498 | instruction->container_state.view_height == height) { |
507 | set_instruction_ready(instruction); | 499 | set_instruction_ready(instruction); |
508 | } | 500 | } |
509 | } | 501 | } |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 00448be7..6d1ccdd7 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -401,7 +401,7 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
401 | } else { | 401 | } else { |
402 | if (view->container->parent) { | 402 | if (view->container->parent) { |
403 | arrange_container(view->container->parent); | 403 | arrange_container(view->container->parent); |
404 | } else { | 404 | } else if (view->container->workspace) { |
405 | arrange_workspace(view->container->workspace); | 405 | arrange_workspace(view->container->workspace); |
406 | } | 406 | } |
407 | } | 407 | } |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index d2c9a68b..95ca396c 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -398,7 +398,7 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
398 | } else { | 398 | } else { |
399 | if (view->container->parent) { | 399 | if (view->container->parent) { |
400 | arrange_container(view->container->parent); | 400 | arrange_container(view->container->parent); |
401 | } else { | 401 | } else if (view->container->workspace) { |
402 | arrange_workspace(view->container->workspace); | 402 | arrange_workspace(view->container->workspace); |
403 | } | 403 | } |
404 | } | 404 | } |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 3619f202..a12ac854 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -394,7 +394,7 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
394 | } else { | 394 | } else { |
395 | if (view->container->parent) { | 395 | if (view->container->parent) { |
396 | arrange_container(view->container->parent); | 396 | arrange_container(view->container->parent); |
397 | } else { | 397 | } else if (view->container->workspace) { |
398 | arrange_workspace(view->container->workspace); | 398 | arrange_workspace(view->container->workspace); |
399 | } | 399 | } |
400 | } | 400 | } |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 85951c09..3ddc27a0 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -30,7 +30,7 @@ | |||
30 | // when dragging to the edge of a layout container. | 30 | // when dragging to the edge of a layout container. |
31 | #define DROP_LAYOUT_BORDER 30 | 31 | #define DROP_LAYOUT_BORDER 30 |
32 | 32 | ||
33 | static uint32_t get_current_time_msec() { | 33 | static uint32_t get_current_time_msec(void) { |
34 | struct timespec now; | 34 | struct timespec now; |
35 | clock_gettime(CLOCK_MONOTONIC, &now); | 35 | clock_gettime(CLOCK_MONOTONIC, &now); |
36 | return now.tv_nsec / 1000; | 36 | return now.tv_nsec / 1000; |
@@ -897,7 +897,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
897 | 897 | ||
898 | // Handle moving a tiling container | 898 | // Handle moving a tiling container |
899 | if (config->tiling_drag && mod_pressed && state == WLR_BUTTON_PRESSED && | 899 | if (config->tiling_drag && mod_pressed && state == WLR_BUTTON_PRESSED && |
900 | !is_floating_or_child && !cont->is_fullscreen) { | 900 | !is_floating_or_child && cont && !cont->is_fullscreen) { |
901 | seat_pointer_notify_button(seat, time_msec, button, state); | 901 | seat_pointer_notify_button(seat, time_msec, button, state); |
902 | seat_begin_move_tiling(seat, cont, button); | 902 | seat_begin_move_tiling(seat, cont, button); |
903 | return; | 903 | return; |
@@ -911,9 +911,10 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
911 | return; | 911 | return; |
912 | } | 912 | } |
913 | 913 | ||
914 | // Handle clicking a container surface | 914 | // Handle clicking a container surface or decorations |
915 | if (cont) { | 915 | if (cont) { |
916 | seat_set_focus_container(seat, cont); | 916 | node = seat_get_focus_inactive(seat, &cont->node); |
917 | seat_set_focus(seat, node); | ||
917 | seat_pointer_notify_button(seat, time_msec, button, state); | 918 | seat_pointer_notify_button(seat, time_msec, button, state); |
918 | return; | 919 | return; |
919 | } | 920 | } |
@@ -930,12 +931,52 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { | |||
930 | transaction_commit_dirty(); | 931 | transaction_commit_dirty(); |
931 | } | 932 | } |
932 | 933 | ||
934 | static void dispatch_cursor_axis(struct sway_cursor *cursor, | ||
935 | struct wlr_event_pointer_axis *event) { | ||
936 | struct sway_seat *seat = cursor->seat; | ||
937 | |||
938 | // Determine what's under the cursor | ||
939 | struct wlr_surface *surface = NULL; | ||
940 | double sx, sy; | ||
941 | struct sway_node *node = node_at_coords(seat, | ||
942 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | ||
943 | struct sway_container *cont = node && node->type == N_CONTAINER ? | ||
944 | node->sway_container : NULL; | ||
945 | enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE; | ||
946 | bool on_border = edge != WLR_EDGE_NONE; | ||
947 | bool on_titlebar = cont && !on_border && !surface; | ||
948 | |||
949 | // Scrolling on a tabbed or stacked title bar | ||
950 | if (on_titlebar) { | ||
951 | enum sway_container_layout layout = container_parent_layout(cont); | ||
952 | if (layout == L_TABBED || layout == L_STACKED) { | ||
953 | struct sway_node *active = | ||
954 | seat_get_active_tiling_child(seat, node_get_parent(node)); | ||
955 | list_t *siblings = container_get_siblings(cont); | ||
956 | int desired = list_find(siblings, active->sway_container) + | ||
957 | event->delta_discrete; | ||
958 | if (desired < 0) { | ||
959 | desired = 0; | ||
960 | } else if (desired >= siblings->length) { | ||
961 | desired = siblings->length - 1; | ||
962 | } | ||
963 | struct sway_container *new_focus = siblings->items[desired]; | ||
964 | node = seat_get_focus_inactive(seat, &new_focus->node); | ||
965 | seat_set_focus(seat, node); | ||
966 | return; | ||
967 | } | ||
968 | } | ||
969 | |||
970 | wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, | ||
971 | event->orientation, event->delta, event->delta_discrete, event->source); | ||
972 | } | ||
973 | |||
933 | static void handle_cursor_axis(struct wl_listener *listener, void *data) { | 974 | static void handle_cursor_axis(struct wl_listener *listener, void *data) { |
934 | struct sway_cursor *cursor = wl_container_of(listener, cursor, axis); | 975 | struct sway_cursor *cursor = wl_container_of(listener, cursor, axis); |
935 | wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat); | 976 | wlr_idle_notify_activity(cursor->seat->input->server->idle, cursor->seat->wlr_seat); |
936 | struct wlr_event_pointer_axis *event = data; | 977 | struct wlr_event_pointer_axis *event = data; |
937 | wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, | 978 | dispatch_cursor_axis(cursor, event); |
938 | event->orientation, event->delta, event->delta_discrete, event->source); | 979 | transaction_commit_dirty(); |
939 | } | 980 | } |
940 | 981 | ||
941 | static void handle_touch_down(struct wl_listener *listener, void *data) { | 982 | static void handle_touch_down(struct wl_listener *listener, void *data) { |
@@ -965,8 +1006,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { | |||
965 | if (seat_is_input_allowed(seat, surface)) { | 1006 | if (seat_is_input_allowed(seat, surface)) { |
966 | wlr_seat_touch_notify_down(wlr_seat, surface, event->time_msec, | 1007 | wlr_seat_touch_notify_down(wlr_seat, surface, event->time_msec, |
967 | event->touch_id, sx, sy); | 1008 | event->touch_id, sx, sy); |
968 | cursor->image_client = NULL; | 1009 | cursor_set_image(cursor, NULL, NULL); |
969 | wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); | ||
970 | } | 1010 | } |
971 | } | 1011 | } |
972 | 1012 | ||
@@ -1134,11 +1174,13 @@ static void handle_request_set_cursor(struct wl_listener *listener, | |||
1134 | 1174 | ||
1135 | void cursor_set_image(struct sway_cursor *cursor, const char *image, | 1175 | void cursor_set_image(struct sway_cursor *cursor, const char *image, |
1136 | struct wl_client *client) { | 1176 | struct wl_client *client) { |
1137 | if (!cursor->image || strcmp(cursor->image, image) != 0) { | 1177 | if (!image) { |
1178 | wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); | ||
1179 | } else if (!cursor->image || strcmp(cursor->image, image) != 0) { | ||
1138 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, | 1180 | wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, |
1139 | cursor->cursor); | 1181 | cursor->cursor); |
1140 | cursor->image = image; | ||
1141 | } | 1182 | } |
1183 | cursor->image = image; | ||
1142 | cursor->image_client = client; | 1184 | cursor->image_client = client; |
1143 | } | 1185 | } |
1144 | 1186 | ||
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index b4352c6a..32f0355e 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -120,6 +120,13 @@ static void input_manager_libinput_config_pointer( | |||
120 | libinput_device_config_click_set_method(libinput_device, | 120 | libinput_device_config_click_set_method(libinput_device, |
121 | ic->click_method); | 121 | ic->click_method); |
122 | } | 122 | } |
123 | if (ic->drag != INT_MIN) { | ||
124 | wlr_log(WLR_DEBUG, | ||
125 | "libinput_config_pointer(%s) tap_set_drag_enabled(%d)", | ||
126 | ic->identifier, ic->click_method); | ||
127 | libinput_device_config_tap_set_drag_enabled(libinput_device, | ||
128 | ic->drag); | ||
129 | } | ||
123 | if (ic->drag_lock != INT_MIN) { | 130 | if (ic->drag_lock != INT_MIN) { |
124 | wlr_log(WLR_DEBUG, | 131 | wlr_log(WLR_DEBUG, |
125 | "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)", | 132 | "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)", |
@@ -233,7 +240,8 @@ static void handle_new_input(struct wl_listener *listener, void *data) { | |||
233 | wlr_log(WLR_DEBUG, "adding device: '%s'", | 240 | wlr_log(WLR_DEBUG, "adding device: '%s'", |
234 | input_device->identifier); | 241 | input_device->identifier); |
235 | 242 | ||
236 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { | 243 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER || |
244 | input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { | ||
237 | input_manager_libinput_config_pointer(input_device); | 245 | input_manager_libinput_config_pointer(input_device); |
238 | } | 246 | } |
239 | 247 | ||
@@ -389,9 +397,12 @@ void input_manager_set_focus(struct sway_input_manager *input, | |||
389 | void input_manager_apply_input_config(struct sway_input_manager *input, | 397 | void input_manager_apply_input_config(struct sway_input_manager *input, |
390 | struct input_config *input_config) { | 398 | struct input_config *input_config) { |
391 | struct sway_input_device *input_device = NULL; | 399 | struct sway_input_device *input_device = NULL; |
400 | bool wildcard = strcmp(input_config->identifier, "*") == 0; | ||
392 | wl_list_for_each(input_device, &input->devices, link) { | 401 | wl_list_for_each(input_device, &input->devices, link) { |
393 | if (strcmp(input_device->identifier, input_config->identifier) == 0) { | 402 | if (strcmp(input_device->identifier, input_config->identifier) == 0 |
394 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { | 403 | || wildcard) { |
404 | if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER || | ||
405 | input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { | ||
395 | input_manager_libinput_config_pointer(input_device); | 406 | input_manager_libinput_config_pointer(input_device); |
396 | } | 407 | } |
397 | 408 | ||
@@ -480,13 +491,16 @@ struct sway_seat *input_manager_get_default_seat( | |||
480 | } | 491 | } |
481 | 492 | ||
482 | struct input_config *input_device_get_config(struct sway_input_device *device) { | 493 | struct input_config *input_device_get_config(struct sway_input_device *device) { |
494 | struct input_config *wildcard_config = NULL; | ||
483 | struct input_config *input_config = NULL; | 495 | struct input_config *input_config = NULL; |
484 | for (int i = 0; i < config->input_configs->length; ++i) { | 496 | for (int i = 0; i < config->input_configs->length; ++i) { |
485 | input_config = config->input_configs->items[i]; | 497 | input_config = config->input_configs->items[i]; |
486 | if (strcmp(input_config->identifier, device->identifier) == 0) { | 498 | if (strcmp(input_config->identifier, device->identifier) == 0) { |
487 | return input_config; | 499 | return input_config; |
500 | } else if (strcmp(input_config->identifier, "*") == 0) { | ||
501 | wildcard_config = input_config; | ||
488 | } | 502 | } |
489 | } | 503 | } |
490 | 504 | ||
491 | return NULL; | 505 | return wildcard_config; |
492 | } | 506 | } |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 49fe46ba..4817eae7 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -348,17 +348,42 @@ struct sway_seat *seat_create(struct sway_input_manager *input, | |||
348 | seat->input = input; | 348 | seat->input = input; |
349 | wl_list_init(&seat->devices); | 349 | wl_list_init(&seat->devices); |
350 | 350 | ||
351 | wlr_seat_set_capabilities(seat->wlr_seat, | ||
352 | WL_SEAT_CAPABILITY_KEYBOARD | | ||
353 | WL_SEAT_CAPABILITY_POINTER | | ||
354 | WL_SEAT_CAPABILITY_TOUCH); | ||
355 | |||
356 | |||
357 | wl_list_insert(&input->seats, &seat->link); | 351 | wl_list_insert(&input->seats, &seat->link); |
358 | 352 | ||
359 | return seat; | 353 | return seat; |
360 | } | 354 | } |
361 | 355 | ||
356 | static void seat_update_capabilities(struct sway_seat *seat) { | ||
357 | uint32_t caps = 0; | ||
358 | struct sway_seat_device *seat_device; | ||
359 | wl_list_for_each(seat_device, &seat->devices, link) { | ||
360 | switch (seat_device->input_device->wlr_device->type) { | ||
361 | case WLR_INPUT_DEVICE_KEYBOARD: | ||
362 | caps |= WL_SEAT_CAPABILITY_KEYBOARD; | ||
363 | break; | ||
364 | case WLR_INPUT_DEVICE_POINTER: | ||
365 | caps |= WL_SEAT_CAPABILITY_POINTER; | ||
366 | break; | ||
367 | case WLR_INPUT_DEVICE_TOUCH: | ||
368 | caps |= WL_SEAT_CAPABILITY_TOUCH; | ||
369 | break; | ||
370 | case WLR_INPUT_DEVICE_TABLET_TOOL: | ||
371 | caps |= WL_SEAT_CAPABILITY_POINTER; | ||
372 | break; | ||
373 | case WLR_INPUT_DEVICE_TABLET_PAD: | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | wlr_seat_set_capabilities(seat->wlr_seat, caps); | ||
378 | |||
379 | // Hide cursor if seat doesn't have pointer capability | ||
380 | if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) { | ||
381 | cursor_set_image(seat->cursor, NULL, NULL); | ||
382 | } else { | ||
383 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
384 | } | ||
385 | } | ||
386 | |||
362 | static void seat_apply_input_config(struct sway_seat *seat, | 387 | static void seat_apply_input_config(struct sway_seat *seat, |
363 | struct sway_seat_device *sway_device) { | 388 | struct sway_seat_device *sway_device) { |
364 | const char *mapped_to_output = NULL; | 389 | const char *mapped_to_output = NULL; |
@@ -489,6 +514,8 @@ void seat_add_device(struct sway_seat *seat, | |||
489 | wl_list_insert(&seat->devices, &seat_device->link); | 514 | wl_list_insert(&seat->devices, &seat_device->link); |
490 | 515 | ||
491 | seat_configure_device(seat, input_device); | 516 | seat_configure_device(seat, input_device); |
517 | |||
518 | seat_update_capabilities(seat); | ||
492 | } | 519 | } |
493 | 520 | ||
494 | void seat_remove_device(struct sway_seat *seat, | 521 | void seat_remove_device(struct sway_seat *seat, |
@@ -503,6 +530,8 @@ void seat_remove_device(struct sway_seat *seat, | |||
503 | input_device->identifier, seat->wlr_seat->name); | 530 | input_device->identifier, seat->wlr_seat->name); |
504 | 531 | ||
505 | seat_device_destroy(seat_device); | 532 | seat_device_destroy(seat_device); |
533 | |||
534 | seat_update_capabilities(seat); | ||
506 | } | 535 | } |
507 | 536 | ||
508 | void seat_configure_xcursor(struct sway_seat *seat) { | 537 | void seat_configure_xcursor(struct sway_seat *seat) { |
@@ -532,8 +561,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { | |||
532 | output->name, (double)output->scale); | 561 | output->name, (double)output->scale); |
533 | } | 562 | } |
534 | 563 | ||
535 | wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, | 564 | cursor_set_image(seat->cursor, "left_ptr", NULL); |
536 | "left_ptr", seat->cursor->cursor); | ||
537 | wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, | 565 | wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, |
538 | seat->cursor->cursor->y); | 566 | seat->cursor->cursor->y); |
539 | } | 567 | } |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index f054ac9f..45915094 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -42,7 +42,7 @@ static const char *ipc_json_orientation_description(enum sway_container_layout l | |||
42 | return "none"; | 42 | return "none"; |
43 | } | 43 | } |
44 | 44 | ||
45 | json_object *ipc_json_get_version() { | 45 | json_object *ipc_json_get_version(void) { |
46 | int major = 0, minor = 0, patch = 0; | 46 | int major = 0, minor = 0, patch = 0; |
47 | json_object *version = json_object_new_object(); | 47 | json_object *version = json_object_new_object(); |
48 | 48 | ||
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 8ae265f6..2d915502 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -1,8 +1,5 @@ | |||
1 | // See https://i3wm.org/docs/ipc.html for protocol information | 1 | // See https://i3wm.org/docs/ipc.html for protocol information |
2 | #ifndef __FreeBSD__ | 2 | #define _POSIX_C_SOURCE 200112L |
3 | // Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) | ||
4 | #define _XOPEN_SOURCE 700 | ||
5 | #endif | ||
6 | #ifdef __linux__ | 3 | #ifdef __linux__ |
7 | #include <linux/input-event-codes.h> | 4 | #include <linux/input-event-codes.h> |
8 | #elif __FreeBSD__ | 5 | #elif __FreeBSD__ |
@@ -89,10 +86,16 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { | |||
89 | } | 86 | } |
90 | 87 | ||
91 | void ipc_init(struct sway_server *server) { | 88 | void ipc_init(struct sway_server *server) { |
92 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); | 89 | ipc_socket = socket(AF_UNIX, SOCK_STREAM, 0); |
93 | if (ipc_socket == -1) { | 90 | if (ipc_socket == -1) { |
94 | sway_abort("Unable to create IPC socket"); | 91 | sway_abort("Unable to create IPC socket"); |
95 | } | 92 | } |
93 | if (fcntl(ipc_socket, F_SETFD, FD_CLOEXEC) == -1) { | ||
94 | sway_abort("Unable to set CLOEXEC on IPC socket"); | ||
95 | } | ||
96 | if (fcntl(ipc_socket, F_SETFL, O_NONBLOCK) == -1) { | ||
97 | sway_abort("Unable to set NONBLOCK on IPC socket"); | ||
98 | } | ||
96 | 99 | ||
97 | ipc_sockaddr = ipc_user_sockaddr(); | 100 | ipc_sockaddr = ipc_user_sockaddr(); |
98 | 101 | ||
@@ -580,7 +583,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
580 | switch (client->current_command) { | 583 | switch (client->current_command) { |
581 | case IPC_COMMAND: | 584 | case IPC_COMMAND: |
582 | { | 585 | { |
583 | struct cmd_results *results = execute_command(buf, NULL); | 586 | struct cmd_results *results = execute_command(buf, NULL, NULL); |
584 | transaction_commit_dirty(); | 587 | transaction_commit_dirty(); |
585 | char *json = cmd_results_to_json(results); | 588 | char *json = cmd_results_to_json(results); |
586 | int length = strlen(json); | 589 | int length = strlen(json); |
diff --git a/sway/main.c b/sway/main.c index fb4f0d8c..dea4a31c 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -12,10 +12,6 @@ | |||
12 | #include <sys/wait.h> | 12 | #include <sys/wait.h> |
13 | #include <sys/un.h> | 13 | #include <sys/un.h> |
14 | #include <unistd.h> | 14 | #include <unistd.h> |
15 | #ifdef __linux__ | ||
16 | #include <sys/capability.h> | ||
17 | #include <sys/prctl.h> | ||
18 | #endif | ||
19 | #include <wlr/util/log.h> | 15 | #include <wlr/util/log.h> |
20 | #include "sway/commands.h" | 16 | #include "sway/commands.h" |
21 | #include "sway/config.h" | 17 | #include "sway/config.h" |
@@ -45,7 +41,7 @@ void sig_handler(int signal) { | |||
45 | sway_terminate(EXIT_SUCCESS); | 41 | sway_terminate(EXIT_SUCCESS); |
46 | } | 42 | } |
47 | 43 | ||
48 | void detect_raspi() { | 44 | void detect_raspi(void) { |
49 | bool raspi = false; | 45 | bool raspi = false; |
50 | FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); | 46 | FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); |
51 | if (!f) { | 47 | if (!f) { |
@@ -85,7 +81,7 @@ void detect_raspi() { | |||
85 | } | 81 | } |
86 | } | 82 | } |
87 | 83 | ||
88 | void detect_proprietary() { | 84 | void detect_proprietary(void) { |
89 | FILE *f = fopen("/proc/modules", "r"); | 85 | FILE *f = fopen("/proc/modules", "r"); |
90 | if (!f) { | 86 | if (!f) { |
91 | return; | 87 | return; |
@@ -120,7 +116,7 @@ void run_as_ipc_client(char *command, char *socket_path) { | |||
120 | close(socketfd); | 116 | close(socketfd); |
121 | } | 117 | } |
122 | 118 | ||
123 | static void log_env() { | 119 | static void log_env(void) { |
124 | const char *log_vars[] = { | 120 | const char *log_vars[] = { |
125 | "PATH", | 121 | "PATH", |
126 | "LD_LIBRARY_PATH", | 122 | "LD_LIBRARY_PATH", |
@@ -135,7 +131,7 @@ static void log_env() { | |||
135 | } | 131 | } |
136 | } | 132 | } |
137 | 133 | ||
138 | static void log_distro() { | 134 | static void log_distro(void) { |
139 | const char *paths[] = { | 135 | const char *paths[] = { |
140 | "/etc/lsb-release", | 136 | "/etc/lsb-release", |
141 | "/etc/os-release", | 137 | "/etc/os-release", |
@@ -162,7 +158,7 @@ static void log_distro() { | |||
162 | } | 158 | } |
163 | } | 159 | } |
164 | 160 | ||
165 | static void log_kernel() { | 161 | static void log_kernel(void) { |
166 | FILE *f = popen("uname -a", "r"); | 162 | FILE *f = popen("uname -a", "r"); |
167 | if (!f) { | 163 | if (!f) { |
168 | wlr_log(WLR_INFO, "Unable to determine kernel version"); | 164 | wlr_log(WLR_INFO, "Unable to determine kernel version"); |
@@ -181,28 +177,8 @@ static void log_kernel() { | |||
181 | pclose(f); | 177 | pclose(f); |
182 | } | 178 | } |
183 | 179 | ||
184 | static void executable_sanity_check() { | ||
185 | #ifdef __linux__ | ||
186 | struct stat sb; | ||
187 | char *exe = realpath("/proc/self/exe", NULL); | ||
188 | stat(exe, &sb); | ||
189 | // We assume that cap_get_file returning NULL implies ENODATA | ||
190 | if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) { | ||
191 | wlr_log(WLR_ERROR, | ||
192 | "sway executable has both the s(g)uid bit AND file caps set."); | ||
193 | wlr_log(WLR_ERROR, | ||
194 | "This is strongly discouraged (and completely broken)."); | ||
195 | wlr_log(WLR_ERROR, | ||
196 | "Please clear one of them (either the suid bit, or the file caps)."); | ||
197 | wlr_log(WLR_ERROR, | ||
198 | "If unsure, strip the file caps."); | ||
199 | exit(EXIT_FAILURE); | ||
200 | } | ||
201 | free(exe); | ||
202 | #endif | ||
203 | } | ||
204 | 180 | ||
205 | static void drop_permissions(bool keep_caps) { | 181 | static void drop_permissions(void) { |
206 | if (getuid() != geteuid() || getgid() != getegid()) { | 182 | if (getuid() != geteuid() || getgid() != getegid()) { |
207 | if (setgid(getgid()) != 0) { | 183 | if (setgid(getgid()) != 0) { |
208 | wlr_log(WLR_ERROR, "Unable to drop root"); | 184 | wlr_log(WLR_ERROR, "Unable to drop root"); |
@@ -217,20 +193,6 @@ static void drop_permissions(bool keep_caps) { | |||
217 | wlr_log(WLR_ERROR, "Root privileges can be restored."); | 193 | wlr_log(WLR_ERROR, "Root privileges can be restored."); |
218 | exit(EXIT_FAILURE); | 194 | exit(EXIT_FAILURE); |
219 | } | 195 | } |
220 | #ifdef __linux__ | ||
221 | if (keep_caps) { | ||
222 | // Drop every cap except CAP_SYS_PTRACE | ||
223 | cap_t caps = cap_init(); | ||
224 | cap_value_t keep = CAP_SYS_PTRACE; | ||
225 | wlr_log(WLR_INFO, "Dropping extra capabilities"); | ||
226 | if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || | ||
227 | cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || | ||
228 | cap_set_proc(caps)) { | ||
229 | wlr_log(WLR_ERROR, "Failed to drop extra capabilities"); | ||
230 | exit(EXIT_FAILURE); | ||
231 | } | ||
232 | } | ||
233 | #endif | ||
234 | } | 196 | } |
235 | 197 | ||
236 | void enable_debug_flag(const char *flag) { | 198 | void enable_debug_flag(const char *flag) { |
@@ -279,14 +241,6 @@ int main(int argc, char **argv) { | |||
279 | " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" | 241 | " --get-socketpath Gets the IPC socket path and prints it, then exits.\n" |
280 | "\n"; | 242 | "\n"; |
281 | 243 | ||
282 | // Security: | ||
283 | unsetenv("LD_PRELOAD"); | ||
284 | #ifdef _LD_LIBRARY_PATH | ||
285 | setenv("LD_LIBRARY_PATH", _LD_LIBRARY_PATH, 1); | ||
286 | #else | ||
287 | unsetenv("LD_LIBRARY_PATH"); | ||
288 | #endif | ||
289 | |||
290 | int c; | 244 | int c; |
291 | while (1) { | 245 | while (1) { |
292 | int option_index = 0; | 246 | int option_index = 0; |
@@ -347,7 +301,7 @@ int main(int argc, char **argv) { | |||
347 | wlr_log(WLR_ERROR, "Don't use options with the IPC client"); | 301 | wlr_log(WLR_ERROR, "Don't use options with the IPC client"); |
348 | exit(EXIT_FAILURE); | 302 | exit(EXIT_FAILURE); |
349 | } | 303 | } |
350 | drop_permissions(false); | 304 | drop_permissions(); |
351 | char *socket_path = getenv("SWAYSOCK"); | 305 | char *socket_path = getenv("SWAYSOCK"); |
352 | if (!socket_path) { | 306 | if (!socket_path) { |
353 | wlr_log(WLR_ERROR, "Unable to retrieve socket path"); | 307 | wlr_log(WLR_ERROR, "Unable to retrieve socket path"); |
@@ -358,34 +312,17 @@ int main(int argc, char **argv) { | |||
358 | return 0; | 312 | return 0; |
359 | } | 313 | } |
360 | 314 | ||
361 | executable_sanity_check(); | ||
362 | bool suid = false; | ||
363 | |||
364 | if (!server_privileged_prepare(&server)) { | 315 | if (!server_privileged_prepare(&server)) { |
365 | return 1; | 316 | return 1; |
366 | } | 317 | } |
367 | 318 | ||
368 | #if defined(__linux__) || defined(__FreeBSD__) | ||
369 | if (getuid() != geteuid() || getgid() != getegid()) { | ||
370 | #ifdef __linux__ | ||
371 | // Retain capabilities after setuid() | ||
372 | if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { | ||
373 | wlr_log(WLR_ERROR, "Cannot keep caps after setuid()"); | ||
374 | exit(EXIT_FAILURE); | ||
375 | } | ||
376 | #endif | ||
377 | suid = true; | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | log_kernel(); | 319 | log_kernel(); |
382 | log_distro(); | 320 | log_distro(); |
383 | detect_proprietary(); | 321 | detect_proprietary(); |
384 | detect_raspi(); | 322 | detect_raspi(); |
385 | 323 | ||
386 | #if defined(__linux__) || defined(__FreeBSD__) | 324 | drop_permissions(); |
387 | drop_permissions(suid); | 325 | |
388 | #endif | ||
389 | // handle SIGTERM signals | 326 | // handle SIGTERM signals |
390 | signal(SIGTERM, sig_handler); | 327 | signal(SIGTERM, sig_handler); |
391 | 328 | ||
@@ -424,11 +361,12 @@ int main(int argc, char **argv) { | |||
424 | } | 361 | } |
425 | 362 | ||
426 | config->active = true; | 363 | config->active = true; |
364 | load_swaybars(); | ||
427 | // Execute commands until there are none left | 365 | // Execute commands until there are none left |
428 | wlr_log(WLR_DEBUG, "Running deferred commands"); | 366 | wlr_log(WLR_DEBUG, "Running deferred commands"); |
429 | while (config->cmd_queue->length) { | 367 | while (config->cmd_queue->length) { |
430 | char *line = config->cmd_queue->items[0]; | 368 | char *line = config->cmd_queue->items[0]; |
431 | struct cmd_results *res = execute_command(line, NULL); | 369 | struct cmd_results *res = execute_command(line, NULL, NULL); |
432 | if (res->status != CMD_SUCCESS) { | 370 | if (res->status != CMD_SUCCESS) { |
433 | wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); | 371 | wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); |
434 | } | 372 | } |
diff --git a/sway/meson.build b/sway/meson.build index d67a4c64..6eb9a9d7 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -119,6 +119,7 @@ sway_sources = files( | |||
119 | 119 | ||
120 | 'commands/input/accel_profile.c', | 120 | 'commands/input/accel_profile.c', |
121 | 'commands/input/click_method.c', | 121 | 'commands/input/click_method.c', |
122 | 'commands/input/drag.c', | ||
122 | 'commands/input/drag_lock.c', | 123 | 'commands/input/drag_lock.c', |
123 | 'commands/input/dwt.c', | 124 | 'commands/input/dwt.c', |
124 | 'commands/input/events.c', | 125 | 'commands/input/events.c', |
@@ -164,7 +165,6 @@ sway_deps = [ | |||
164 | cairo, | 165 | cairo, |
165 | gdk_pixbuf, | 166 | gdk_pixbuf, |
166 | jsonc, | 167 | jsonc, |
167 | libcap, | ||
168 | libinput, | 168 | libinput, |
169 | math, | 169 | math, |
170 | pango, | 170 | pango, |
@@ -187,5 +187,6 @@ executable( | |||
187 | include_directories: [sway_inc], | 187 | include_directories: [sway_inc], |
188 | dependencies: sway_deps, | 188 | dependencies: sway_deps, |
189 | link_with: [lib_sway_common], | 189 | link_with: [lib_sway_common], |
190 | install_rpath : rpathdir, | ||
190 | install: true | 191 | install: true |
191 | ) | 192 | ) |
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index a61e2829..00b9386e 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd | |||
@@ -6,8 +6,7 @@ sway-bar - bar configuration file and commands | |||
6 | 6 | ||
7 | # DESCRIPTION | 7 | # DESCRIPTION |
8 | 8 | ||
9 | Sway allows configuring swaybar in the sway configuration file. Swaybar | 9 | Sway allows configuring swaybar in the sway configuration file. |
10 | commands must be used inside a _bar { }_ block in the config file. | ||
11 | 10 | ||
12 | # COMMANDS | 11 | # COMMANDS |
13 | 12 | ||
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 707c36af..14f2a007 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd | |||
@@ -7,7 +7,6 @@ sway-input - input configuration file and commands | |||
7 | # DESCRIPTION | 7 | # DESCRIPTION |
8 | 8 | ||
9 | Sway allows for configuration of devices within the sway configuration file. | 9 | Sway allows for configuration of devices within the sway configuration file. |
10 | sway-input commands must be used inside an _input { }_ block in the config. | ||
11 | To obtain a list of available device identifiers, run *swaymsg -t get\_inputs*. | 10 | To obtain a list of available device identifiers, run *swaymsg -t get\_inputs*. |
12 | 11 | ||
13 | # INPUT COMMANDS | 12 | # INPUT COMMANDS |
@@ -68,6 +67,9 @@ The following commands may only be used in the configuration file. | |||
68 | *input* <identifier> click\_method none|button\_areas|clickfinger | 67 | *input* <identifier> click\_method none|button\_areas|clickfinger |
69 | Changes the click method for the specified device. | 68 | Changes the click method for the specified device. |
70 | 69 | ||
70 | *input* <identifier> drag enabled|disabled | ||
71 | Enables or disables tap-and-drag for specified input device. | ||
72 | |||
71 | *input* <identifier> drag\_lock enabled|disabled | 73 | *input* <identifier> drag\_lock enabled|disabled |
72 | Enables or disables drag lock for specified input device. | 74 | Enables or disables drag lock for specified input device. |
73 | 75 | ||
@@ -116,8 +118,7 @@ The following commands may only be used in the configuration file. | |||
116 | 118 | ||
117 | ## SEAT CONFIGURATION | 119 | ## SEAT CONFIGURATION |
118 | 120 | ||
119 | Configure options for multiseat mode. sway-seat commands must be used inside a | 121 | Configure options for multiseat mode. |
120 | _seat { }_ block in the config. | ||
121 | 122 | ||
122 | A *seat* is a collection of input devices that act independently of each other. | 123 | A *seat* is a collection of input devices that act independently of each other. |
123 | Seats are identified by name and the default seat is _seat0_ if no seats are | 124 | Seats are identified by name and the default seat is _seat0_ if no seats are |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 927bf55c..aa5b38ab 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -19,6 +19,24 @@ bindsym Shift+XF86AudioRaiseVolume exec \\ | |||
19 | pactl set-sink-volume @DEFAULT_SINK@ -1% | 19 | pactl set-sink-volume @DEFAULT_SINK@ -1% |
20 | ``` | 20 | ``` |
21 | 21 | ||
22 | Commands can also be given as a block in the form *command { <subcommands...> | ||
23 | }*. Anything before the opening *{* will be prepended to the lines inside the | ||
24 | block. For example: | ||
25 | |||
26 | ``` | ||
27 | output eDP-1 { | ||
28 | background ~/wallpaper.png | ||
29 | resolution 1920x1080 | ||
30 | } | ||
31 | ``` | ||
32 | |||
33 | is identical to | ||
34 | |||
35 | ``` | ||
36 | output eDP-1 background ~/wallpaper.png | ||
37 | output eDP-1 resolution 1920x1080 | ||
38 | ``` | ||
39 | |||
22 | These commands can be executed in your config file, via *swaymsg*(1), or via | 40 | These commands can be executed in your config file, via *swaymsg*(1), or via |
23 | the bindsym command. | 41 | the bindsym command. |
24 | 42 | ||
@@ -37,10 +55,8 @@ which you may only select one. *[...]* is used for optional arguments, and | |||
37 | 55 | ||
38 | The following commands may only be used in the configuration file. | 56 | The following commands may only be used in the configuration file. |
39 | 57 | ||
40 | *bar {* <commands...> *}* | 58 | *bar* [<bar-id>] <bar-subcommands...> |
41 | _commands..._ after *{* will be interpreted as bar commands. For | 59 | For details on bar subcommands, see *sway-bar*(5). |
42 | details, see *sway-bar*(5). A newline is required between *{* and the | ||
43 | first command, and *}* must be alone on a line. | ||
44 | 60 | ||
45 | *default\_orientation* horizontal|vertical|auto | 61 | *default\_orientation* horizontal|vertical|auto |
46 | Sets the default container layout for tiled containers. | 62 | Sets the default container layout for tiled containers. |
@@ -51,10 +67,6 @@ The following commands may only be used in the configuration file. | |||
51 | *wordexp*(3) for details). The same include file can only be included once; | 67 | *wordexp*(3) for details). The same include file can only be included once; |
52 | subsequent attempts will be ignored. | 68 | subsequent attempts will be ignored. |
53 | 69 | ||
54 | *set* $<name> <value> | ||
55 | Sets variable $_name_ to _value_. You can use the new variable in the | ||
56 | arguments of future commands. | ||
57 | |||
58 | *swaybg\_command* <command> | 70 | *swaybg\_command* <command> |
59 | Executes custom background _command_. Default is _swaybg_. Refer to | 71 | Executes custom background _command_. Default is _swaybg_. Refer to |
60 | *output* below for more information. | 72 | *output* below for more information. |
@@ -407,37 +419,30 @@ The default colors are: | |||
407 | inner gap is nonzero. When _off_, gaps will only be added between views. | 419 | inner gap is nonzero. When _off_, gaps will only be added between views. |
408 | _toggle_ cannot be used in the configuration file. | 420 | _toggle_ cannot be used in the configuration file. |
409 | 421 | ||
410 | *gaps* <amount> | ||
411 | Sets _amount_ pixels of gap between windows and around each workspace. | ||
412 | |||
413 | *gaps* inner|outer <amount> | 422 | *gaps* inner|outer <amount> |
414 | Sets default _amount_ pixels of _inner_ or _outer_ gap, where the former | 423 | Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner |
415 | affects spacing between views and the latter affects the space around each | 424 | affects spacing around each view and outer affects the spacing around each |
416 | workspace. | 425 | workspace. Outer gaps are in addition to inner gaps. |
426 | |||
427 | This affects new workspaces only, and is used when the workspace doesn't | ||
428 | have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>). | ||
417 | 429 | ||
418 | *gaps* inner|outer all|workspace|current set|plus|minus <amount> | 430 | *gaps* inner|outer all|current set|plus|minus <amount> |
419 | Changes the gaps for the _inner_ or _outer_ gap. _all_ changes the gaps for | 431 | Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the |
420 | all views or workspace, _workspace_ changes gaps for all views in current | 432 | _current_ workspace. |
421 | workspace (or current workspace), and _current_ changes gaps for the current | ||
422 | view or workspace. | ||
423 | 433 | ||
424 | *hide\_edge\_borders* none|vertical|horizontal|both|smart | 434 | *hide\_edge\_borders* none|vertical|horizontal|both|smart |
425 | Hides window borders adjacent to the screen edges. Default is _none_. | 435 | Hides window borders adjacent to the screen edges. Default is _none_. |
426 | 436 | ||
427 | *input* <input\_device> *{* <commands...> *}* | 437 | *input* <input\_device> <input-subcommands...> |
428 | _commands..._ after *{* will be interpreted as input commands applying to | 438 | For details on input subcommands, see *sway-input*(5). |
429 | the specified input device. For details, see *sway-input*(5). A newline is | ||
430 | required between *{* and the first command, and *}* must be alone on a | ||
431 | line. | ||
432 | 439 | ||
433 | \* may be used in lieu of a specific device name to configure all input | 440 | \* may be used in lieu of a specific device name to configure all input |
434 | devices. A list of input device names may be obtained via *swaymsg -t | 441 | devices. A list of input device names may be obtained via *swaymsg -t |
435 | get\_inputs*. | 442 | get\_inputs*. |
436 | 443 | ||
437 | *seat* <seat> *{* <commands...> *}* | 444 | *seat* <seat> <seat-subcommands...> |
438 | _commands..._ after *{* will be interpreted as seat commands applying to | 445 | For details on seat subcommands, see *sway-input*(5). |
439 | the specified seat. For details, see *sway-input*(5). A newline is required | ||
440 | between *{* and the first command, and *}* must be alone on a line. | ||
441 | 446 | ||
442 | *seat* <seat> cursor move|set <x> <y> | 447 | *seat* <seat> cursor move|set <x> <y> |
443 | Move specified seat's cursor relative to current position or wrap to | 448 | Move specified seat's cursor relative to current position or wrap to |
@@ -465,10 +470,8 @@ The default colors are: | |||
465 | *mode* <mode> | 470 | *mode* <mode> |
466 | Switches to the specified mode. The default mode _default_. | 471 | Switches to the specified mode. The default mode _default_. |
467 | 472 | ||
468 | *mode* [--pango\_markup] <mode> *{* <commands...> *}* | 473 | *mode* [--pango\_markup] <mode> <mode-subcommands...> |
469 | _commands..._ after *{* will be added to the specified mode. A newline is | 474 | The only two valid _mode-subcommands..._ are *bindsym* and *bindcode*. |
470 | required between *{* and the first command, and *}* must be alone on a | ||
471 | line. Only *bindsym* and *bindcode* commands are permitted in mode blocks. | ||
472 | If _--pango\_markup_ is given, then _mode_ will be interpreted as pango | 475 | If _--pango\_markup_ is given, then _mode_ will be interpreted as pango |
473 | markup. | 476 | markup. |
474 | 477 | ||
@@ -533,8 +536,15 @@ You may combine output commands into one, like so: | |||
533 | output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch | 536 | output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch |
534 | 537 | ||
535 | You can get a list of output names with *swaymsg -t get\_outputs*. You may also | 538 | You can get a list of output names with *swaymsg -t get\_outputs*. You may also |
536 | match any output by using the output name "\*". Be sure to add this output | 539 | match any output by using the output name "\*". |
537 | config after the others, or it will be matched instead of the others. | 540 | |
541 | *set* $<name> <value> | ||
542 | Sets variable $_name_ to _value_. You can use the new variable in the | ||
543 | arguments of future commands. When the variable is used, it can be escaped | ||
544 | with an additional $ (ie $$_name_) to have the replacement happen at run | ||
545 | time instead of when reading the config. However, it does not always make | ||
546 | sense for the variable to be replaced at run time since some arguments do | ||
547 | need to be known at config time. | ||
538 | 548 | ||
539 | *show\_marks* yes|no | 549 | *show\_marks* yes|no |
540 | If *show\_marks* is yes, marks will be displayed in the window borders. | 550 | If *show\_marks* is yes, marks will be displayed in the window borders. |
@@ -568,6 +578,10 @@ config after the others, or it will be matched instead of the others. | |||
568 | *workspace* back_and_forth | 578 | *workspace* back_and_forth |
569 | Switches to the previously focused workspace. | 579 | Switches to the previously focused workspace. |
570 | 580 | ||
581 | *workspace* <name> gaps inner|outer <amount> | ||
582 | Specifies that workspace _name_ should have the given gaps settings when it | ||
583 | is created. | ||
584 | |||
571 | *workspace* <name> output <output> | 585 | *workspace* <name> output <output> |
572 | Specifies that workspace _name_ should be shown on the specified _output_. | 586 | Specifies that workspace _name_ should be shown on the specified _output_. |
573 | 587 | ||
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index d50be25d..373460a2 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -186,6 +186,7 @@ void arrange_workspace(struct sway_workspace *workspace) { | |||
186 | area->width, area->height, area->x, area->y); | 186 | area->width, area->height, area->x, area->y); |
187 | workspace_remove_gaps(workspace); | 187 | workspace_remove_gaps(workspace); |
188 | 188 | ||
189 | bool first_arrange = workspace->width == 0 && workspace->height == 0; | ||
189 | double prev_x = workspace->x; | 190 | double prev_x = workspace->x; |
190 | double prev_y = workspace->y; | 191 | double prev_y = workspace->y; |
191 | workspace->width = area->width; | 192 | workspace->width = area->width; |
@@ -196,7 +197,7 @@ void arrange_workspace(struct sway_workspace *workspace) { | |||
196 | // Adjust any floating containers | 197 | // Adjust any floating containers |
197 | double diff_x = workspace->x - prev_x; | 198 | double diff_x = workspace->x - prev_x; |
198 | double diff_y = workspace->y - prev_y; | 199 | double diff_y = workspace->y - prev_y; |
199 | if (diff_x != 0 || diff_y != 0) { | 200 | if (!first_arrange && (diff_x != 0 || diff_y != 0)) { |
200 | for (int i = 0; i < workspace->floating->length; ++i) { | 201 | for (int i = 0; i < workspace->floating->length; ++i) { |
201 | struct sway_container *floater = workspace->floating->items[i]; | 202 | struct sway_container *floater = workspace->floating->items[i]; |
202 | container_floating_translate(floater, diff_x, diff_y); | 203 | container_floating_translate(floater, diff_x, diff_y); |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 47687744..788300cc 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -67,12 +67,10 @@ void container_destroy(struct sway_container *con) { | |||
67 | list_free(con->outputs); | 67 | list_free(con->outputs); |
68 | 68 | ||
69 | if (con->view) { | 69 | if (con->view) { |
70 | struct sway_view *view = con->view; | 70 | if (con->view->container == con) { |
71 | view->container = NULL; | 71 | con->view->container = NULL; |
72 | free(view->title_format); | 72 | } |
73 | view->title_format = NULL; | 73 | if (con->view->destroying) { |
74 | |||
75 | if (view->destroying) { | ||
76 | view_destroy(con->view); | 74 | view_destroy(con->view); |
77 | } | 75 | } |
78 | } | 76 | } |
@@ -215,8 +213,7 @@ static struct sway_container *container_at_tabbed(struct sway_node *parent, | |||
215 | child_index = children->length - 1; | 213 | child_index = children->length - 1; |
216 | } | 214 | } |
217 | struct sway_container *child = children->items[child_index]; | 215 | struct sway_container *child = children->items[child_index]; |
218 | struct sway_node *node = seat_get_focus_inactive(seat, &child->node); | 216 | return child; |
219 | return node->sway_container; | ||
220 | } | 217 | } |
221 | 218 | ||
222 | // Surfaces | 219 | // Surfaces |
@@ -243,8 +240,7 @@ static struct sway_container *container_at_stacked(struct sway_node *parent, | |||
243 | int child_index = (ly - box.y) / title_height; | 240 | int child_index = (ly - box.y) / title_height; |
244 | if (child_index < children->length) { | 241 | if (child_index < children->length) { |
245 | struct sway_container *child = children->items[child_index]; | 242 | struct sway_container *child = children->items[child_index]; |
246 | struct sway_node *node = seat_get_focus_inactive(seat, &child->node); | 243 | return child; |
247 | return node->sway_container; | ||
248 | } | 244 | } |
249 | 245 | ||
250 | // Surfaces | 246 | // Surfaces |
@@ -465,11 +461,17 @@ static void update_title_texture(struct sway_container *con, | |||
465 | cairo_surface_t *surface = cairo_image_surface_create( | 461 | cairo_surface_t *surface = cairo_image_surface_create( |
466 | CAIRO_FORMAT_ARGB32, width, height); | 462 | CAIRO_FORMAT_ARGB32, width, height); |
467 | cairo_t *cairo = cairo_create(surface); | 463 | cairo_t *cairo = cairo_create(surface); |
464 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | ||
465 | cairo_font_options_t *fo = cairo_font_options_create(); | ||
466 | cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); | ||
467 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); | ||
468 | cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel)); | ||
469 | cairo_set_font_options(cairo, fo); | ||
470 | cairo_font_options_destroy(fo); | ||
468 | cairo_set_source_rgba(cairo, class->background[0], class->background[1], | 471 | cairo_set_source_rgba(cairo, class->background[0], class->background[1], |
469 | class->background[2], class->background[3]); | 472 | class->background[2], class->background[3]); |
470 | cairo_paint(cairo); | 473 | cairo_paint(cairo); |
471 | PangoContext *pango = pango_cairo_create_context(cairo); | 474 | PangoContext *pango = pango_cairo_create_context(cairo); |
472 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | ||
473 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], | 475 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], |
474 | class->text[2], class->text[3]); | 476 | class->text[2], class->text[3]); |
475 | cairo_move_to(cairo, 0, 0); | 477 | cairo_move_to(cairo, 0, 0); |
@@ -591,7 +593,7 @@ void container_update_representation(struct sway_container *con) { | |||
591 | } | 593 | } |
592 | } | 594 | } |
593 | 595 | ||
594 | size_t container_titlebar_height() { | 596 | size_t container_titlebar_height(void) { |
595 | return config->font_height + TITLEBAR_V_PADDING * 2; | 597 | return config->font_height + TITLEBAR_V_PADDING * 2; |
596 | } | 598 | } |
597 | 599 | ||
@@ -821,9 +823,16 @@ void container_floating_move_to_center(struct sway_container *con) { | |||
821 | return; | 823 | return; |
822 | } | 824 | } |
823 | struct sway_workspace *ws = con->workspace; | 825 | struct sway_workspace *ws = con->workspace; |
826 | bool full = con->is_fullscreen; | ||
827 | if (full) { | ||
828 | container_set_fullscreen(con, false); | ||
829 | } | ||
824 | double new_lx = ws->x + (ws->width - con->width) / 2; | 830 | double new_lx = ws->x + (ws->width - con->width) / 2; |
825 | double new_ly = ws->y + (ws->height - con->height) / 2; | 831 | double new_ly = ws->y + (ws->height - con->height) / 2; |
826 | container_floating_translate(con, new_lx - con->x, new_ly - con->y); | 832 | container_floating_translate(con, new_lx - con->x, new_ly - con->y); |
833 | if (full) { | ||
834 | container_set_fullscreen(con, true); | ||
835 | } | ||
827 | } | 836 | } |
828 | 837 | ||
829 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 838 | static bool find_urgent_iterator(struct sway_container *con, void *data) { |
@@ -981,7 +990,8 @@ void container_discover_outputs(struct sway_container *con) { | |||
981 | } | 990 | } |
982 | } | 991 | } |
983 | struct sway_output *new_output = container_get_effective_output(con); | 992 | struct sway_output *new_output = container_get_effective_output(con); |
984 | double old_scale = old_output ? old_output->wlr_output->scale : -1; | 993 | double old_scale = old_output && old_output->enabled ? |
994 | old_output->wlr_output->scale : -1; | ||
985 | double new_scale = new_output ? new_output->wlr_output->scale : -1; | 995 | double new_scale = new_output ? new_output->wlr_output->scale : -1; |
986 | if (old_scale != new_scale) { | 996 | if (old_scale != new_scale) { |
987 | container_update_title_textures(con); | 997 | container_update_title_textures(con); |
@@ -1019,7 +1029,7 @@ void container_add_gaps(struct sway_container *c) { | |||
1019 | 1029 | ||
1020 | struct sway_workspace *ws = c->workspace; | 1030 | struct sway_workspace *ws = c->workspace; |
1021 | 1031 | ||
1022 | c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; | 1032 | c->current_gaps = ws->gaps_inner; |
1023 | c->x += c->current_gaps; | 1033 | c->x += c->current_gaps; |
1024 | c->y += c->current_gaps; | 1034 | c->y += c->current_gaps; |
1025 | c->width -= 2 * c->current_gaps; | 1035 | c->width -= 2 * c->current_gaps; |
diff --git a/sway/tree/output.c b/sway/tree/output.c index 1976ad51..c3176325 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -109,12 +109,24 @@ void output_enable(struct sway_output *output, struct output_config *oc) { | |||
109 | 109 | ||
110 | wl_signal_emit(&root->events.new_node, &output->node); | 110 | wl_signal_emit(&root->events.new_node, &output->node); |
111 | 111 | ||
112 | load_swaybars(); | ||
113 | |||
114 | arrange_layers(output); | 112 | arrange_layers(output); |
115 | arrange_root(); | 113 | arrange_root(); |
116 | } | 114 | } |
117 | 115 | ||
116 | static void evacuate_sticky(struct sway_workspace *old_ws, | ||
117 | struct sway_output *new_output) { | ||
118 | struct sway_workspace *new_ws = output_get_active_workspace(new_output); | ||
119 | while (old_ws->floating->length) { | ||
120 | struct sway_container *sticky = old_ws->floating->items[0]; | ||
121 | container_detach(sticky); | ||
122 | workspace_add_floating(new_ws, sticky); | ||
123 | container_handle_fullscreen_reparent(sticky); | ||
124 | container_floating_move_to_center(sticky); | ||
125 | ipc_event_window(sticky, "move"); | ||
126 | } | ||
127 | workspace_detect_urgent(new_ws); | ||
128 | } | ||
129 | |||
118 | static void output_evacuate(struct sway_output *output) { | 130 | static void output_evacuate(struct sway_output *output) { |
119 | if (!output->workspaces->length) { | 131 | if (!output->workspaces->length) { |
120 | return; | 132 | return; |
@@ -132,17 +144,21 @@ static void output_evacuate(struct sway_output *output) { | |||
132 | 144 | ||
133 | workspace_detach(workspace); | 145 | workspace_detach(workspace); |
134 | 146 | ||
135 | if (workspace_is_empty(workspace)) { | ||
136 | workspace_begin_destroy(workspace); | ||
137 | continue; | ||
138 | } | ||
139 | |||
140 | struct sway_output *new_output = | 147 | struct sway_output *new_output = |
141 | workspace_output_get_highest_available(workspace, output); | 148 | workspace_output_get_highest_available(workspace, output); |
142 | if (!new_output) { | 149 | if (!new_output) { |
143 | new_output = fallback_output; | 150 | new_output = fallback_output; |
144 | } | 151 | } |
145 | 152 | ||
153 | if (workspace_is_empty(workspace)) { | ||
154 | // If floating is not empty, there are sticky containers to move | ||
155 | if (workspace->floating->length) { | ||
156 | evacuate_sticky(workspace, new_output); | ||
157 | } | ||
158 | workspace_begin_destroy(workspace); | ||
159 | continue; | ||
160 | } | ||
161 | |||
146 | if (new_output) { | 162 | if (new_output) { |
147 | workspace_output_add_priority(workspace, new_output); | 163 | workspace_output_add_priority(workspace, new_output); |
148 | output_add_workspace(new_output, workspace); | 164 | output_add_workspace(new_output, workspace); |
diff --git a/sway/tree/root.c b/sway/tree/root.c index ecc04ddb..6748e9c9 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -265,14 +265,20 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data), | |||
265 | // Scratchpad | 265 | // Scratchpad |
266 | for (int i = 0; i < root->scratchpad->length; ++i) { | 266 | for (int i = 0; i < root->scratchpad->length; ++i) { |
267 | struct sway_container *container = root->scratchpad->items[i]; | 267 | struct sway_container *container = root->scratchpad->items[i]; |
268 | // If the container has a parent then it's visible on a workspace | 268 | // If the container has a workspace then it's visible on a workspace |
269 | // and will have been iterated in the previous for loop. So we only | 269 | // and will have been iterated in the previous for loop. So we only |
270 | // iterate the hidden scratchpad containers here. | 270 | // iterate the hidden scratchpad containers here. |
271 | if (!container->parent) { | 271 | if (!container->workspace) { |
272 | f(container, data); | 272 | f(container, data); |
273 | container_for_each_child(container, f, data); | 273 | container_for_each_child(container, f, data); |
274 | } | 274 | } |
275 | } | 275 | } |
276 | |||
277 | // Saved workspaces | ||
278 | for (int i = 0; i < root->saved_workspaces->length; ++i) { | ||
279 | struct sway_workspace *ws = root->saved_workspaces->items[i]; | ||
280 | workspace_for_each_container(ws, f, data); | ||
281 | } | ||
276 | } | 282 | } |
277 | 283 | ||
278 | struct sway_output *root_find_output( | 284 | struct sway_output *root_find_output( |
@@ -311,7 +317,7 @@ struct sway_container *root_find_container( | |||
311 | // Scratchpad | 317 | // Scratchpad |
312 | for (int i = 0; i < root->scratchpad->length; ++i) { | 318 | for (int i = 0; i < root->scratchpad->length; ++i) { |
313 | struct sway_container *container = root->scratchpad->items[i]; | 319 | struct sway_container *container = root->scratchpad->items[i]; |
314 | if (!container->parent) { | 320 | if (!container->workspace) { |
315 | if (test(container, data)) { | 321 | if (test(container, data)) { |
316 | return container; | 322 | return container; |
317 | } | 323 | } |
@@ -320,6 +326,15 @@ struct sway_container *root_find_container( | |||
320 | } | 326 | } |
321 | } | 327 | } |
322 | } | 328 | } |
329 | |||
330 | // Saved workspaces | ||
331 | for (int i = 0; i < root->saved_workspaces->length; ++i) { | ||
332 | struct sway_workspace *ws = root->saved_workspaces->items[i]; | ||
333 | if ((result = workspace_find_container(ws, test, data))) { | ||
334 | return result; | ||
335 | } | ||
336 | } | ||
337 | |||
323 | return NULL; | 338 | return NULL; |
324 | } | 339 | } |
325 | 340 | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index 4398f518..a024f325 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -391,8 +391,6 @@ static bool view_has_executed_criteria(struct sway_view *view, | |||
391 | } | 391 | } |
392 | 392 | ||
393 | void view_execute_criteria(struct sway_view *view) { | 393 | void view_execute_criteria(struct sway_view *view) { |
394 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
395 | struct sway_node *prior_focus = seat_get_focus(seat); | ||
396 | list_t *criterias = criteria_for_view(view, CT_COMMAND); | 394 | list_t *criterias = criteria_for_view(view, CT_COMMAND); |
397 | for (int i = 0; i < criterias->length; i++) { | 395 | for (int i = 0; i < criterias->length; i++) { |
398 | struct criteria *criteria = criterias->items[i]; | 396 | struct criteria *criteria = criterias->items[i]; |
@@ -403,16 +401,12 @@ void view_execute_criteria(struct sway_view *view) { | |||
403 | } | 401 | } |
404 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", | 402 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", |
405 | criteria->raw, view, criteria->cmdlist); | 403 | criteria->raw, view, criteria->cmdlist); |
406 | seat_set_focus_container(seat, view->container); | ||
407 | list_add(view->executed_criteria, criteria); | 404 | list_add(view->executed_criteria, criteria); |
408 | struct cmd_results *res = execute_command(criteria->cmdlist, NULL); | 405 | struct cmd_results *res = execute_command( |
409 | if (res->status != CMD_SUCCESS) { | 406 | criteria->cmdlist, NULL, view->container); |
410 | wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error); | ||
411 | } | ||
412 | free_cmd_results(res); | 407 | free_cmd_results(res); |
413 | } | 408 | } |
414 | list_free(criterias); | 409 | list_free(criterias); |
415 | seat_set_focus(seat, prior_focus); | ||
416 | } | 410 | } |
417 | 411 | ||
418 | static struct sway_workspace *select_workspace(struct sway_view *view) { | 412 | static struct sway_workspace *select_workspace(struct sway_view *view) { |
@@ -785,14 +779,9 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) { | |||
785 | } | 779 | } |
786 | 780 | ||
787 | static char *escape_title(char *buffer) { | 781 | static char *escape_title(char *buffer) { |
788 | int length = escape_markup_text(buffer, NULL, 0); | 782 | size_t length = escape_markup_text(buffer, NULL); |
789 | char *escaped_title = calloc(length + 1, sizeof(char)); | 783 | char *escaped_title = calloc(length + 1, sizeof(char)); |
790 | int result = escape_markup_text(buffer, escaped_title, length); | 784 | escape_markup_text(buffer, escaped_title); |
791 | if (result != length) { | ||
792 | wlr_log(WLR_ERROR, "Could not escape title: %s", buffer); | ||
793 | free(escaped_title); | ||
794 | return buffer; | ||
795 | } | ||
796 | free(buffer); | 785 | free(buffer); |
797 | return escaped_title; | 786 | return escaped_title; |
798 | } | 787 | } |
@@ -1000,12 +989,16 @@ bool view_is_visible(struct sway_view *view) { | |||
1000 | floater = floater->parent; | 989 | floater = floater->parent; |
1001 | } | 990 | } |
1002 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; | 991 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; |
992 | if (!is_sticky && !workspace_is_visible(workspace)) { | ||
993 | return false; | ||
994 | } | ||
1003 | // Check view isn't in a tabbed or stacked container on an inactive tab | 995 | // Check view isn't in a tabbed or stacked container on an inactive tab |
1004 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 996 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1005 | struct sway_container *con = view->container; | 997 | struct sway_container *con = view->container; |
1006 | while (con) { | 998 | while (con) { |
1007 | enum sway_container_layout layout = container_parent_layout(con); | 999 | enum sway_container_layout layout = container_parent_layout(con); |
1008 | if (layout == L_TABBED || layout == L_STACKED) { | 1000 | if ((layout == L_TABBED || layout == L_STACKED) |
1001 | && !container_is_floating(con)) { | ||
1009 | struct sway_node *parent = con->parent ? | 1002 | struct sway_node *parent = con->parent ? |
1010 | &con->parent->node : &con->workspace->node; | 1003 | &con->parent->node : &con->workspace->node; |
1011 | if (seat_get_active_tiling_child(seat, parent) != &con->node) { | 1004 | if (seat_get_active_tiling_child(seat, parent) != &con->node) { |
@@ -1019,10 +1012,6 @@ bool view_is_visible(struct sway_view *view) { | |||
1019 | !container_is_fullscreen_or_child(view->container)) { | 1012 | !container_is_fullscreen_or_child(view->container)) { |
1020 | return false; | 1013 | return false; |
1021 | } | 1014 | } |
1022 | // Check the workspace is visible | ||
1023 | if (!is_sticky) { | ||
1024 | return workspace_is_visible(workspace); | ||
1025 | } | ||
1026 | return true; | 1015 | return true; |
1027 | } | 1016 | } |
1028 | 1017 | ||
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 18746430..9dd5c815 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -20,17 +20,23 @@ | |||
20 | #include "log.h" | 20 | #include "log.h" |
21 | #include "util.h" | 21 | #include "util.h" |
22 | 22 | ||
23 | struct workspace_config *workspace_find_config(const char *ws_name) { | ||
24 | for (int i = 0; i < config->workspace_configs->length; ++i) { | ||
25 | struct workspace_config *wsc = config->workspace_configs->items[i]; | ||
26 | if (strcmp(wsc->workspace, ws_name) == 0) { | ||
27 | return wsc; | ||
28 | } | ||
29 | } | ||
30 | return NULL; | ||
31 | } | ||
32 | |||
23 | struct sway_output *workspace_get_initial_output(const char *name) { | 33 | struct sway_output *workspace_get_initial_output(const char *name) { |
24 | // Search for workspace<->output pair | 34 | // Check workspace configs for a workspace<->output pair |
25 | for (int i = 0; i < config->workspace_outputs->length; ++i) { | 35 | struct workspace_config *wsc = workspace_find_config(name); |
26 | struct workspace_output *wso = config->workspace_outputs->items[i]; | 36 | if (wsc && wsc->output) { |
27 | if (strcasecmp(wso->workspace, name) == 0) { | 37 | struct sway_output *output = output_by_name(wsc->output); |
28 | // Find output to use if it exists | 38 | if (output) { |
29 | struct sway_output *output = output_by_name(wso->output); | 39 | return output; |
30 | if (output) { | ||
31 | return output; | ||
32 | } | ||
33 | break; | ||
34 | } | 40 | } |
35 | } | 41 | } |
36 | // Otherwise put it on the focused output | 42 | // Otherwise put it on the focused output |
@@ -54,10 +60,6 @@ struct sway_workspace *workspace_create(struct sway_output *output, | |||
54 | return NULL; | 60 | return NULL; |
55 | } | 61 | } |
56 | node_init(&ws->node, N_WORKSPACE, ws); | 62 | node_init(&ws->node, N_WORKSPACE, ws); |
57 | ws->x = output->lx; | ||
58 | ws->y = output->ly; | ||
59 | ws->width = output->width; | ||
60 | ws->height = output->height; | ||
61 | ws->name = name ? strdup(name) : NULL; | 63 | ws->name = name ? strdup(name) : NULL; |
62 | ws->prev_split_layout = L_NONE; | 64 | ws->prev_split_layout = L_NONE; |
63 | ws->layout = output_get_default_layout(output); | 65 | ws->layout = output_get_default_layout(output); |
@@ -66,6 +68,20 @@ struct sway_workspace *workspace_create(struct sway_output *output, | |||
66 | ws->output_priority = create_list(); | 68 | ws->output_priority = create_list(); |
67 | workspace_output_add_priority(ws, output); | 69 | workspace_output_add_priority(ws, output); |
68 | 70 | ||
71 | ws->gaps_outer = config->gaps_outer; | ||
72 | ws->gaps_inner = config->gaps_inner; | ||
73 | if (name) { | ||
74 | struct workspace_config *wsc = workspace_find_config(name); | ||
75 | if (wsc) { | ||
76 | if (wsc->gaps_outer != -1) { | ||
77 | ws->gaps_outer = wsc->gaps_outer; | ||
78 | } | ||
79 | if (wsc->gaps_inner != -1) { | ||
80 | ws->gaps_inner = wsc->gaps_inner; | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
69 | output_add_workspace(output, ws); | 85 | output_add_workspace(output, ws); |
70 | output_sort_workspaces(output); | 86 | output_sort_workspaces(output); |
71 | 87 | ||
@@ -125,17 +141,8 @@ void next_name_map(struct sway_container *ws, void *data) { | |||
125 | 141 | ||
126 | static bool workspace_valid_on_output(const char *output_name, | 142 | static bool workspace_valid_on_output(const char *output_name, |
127 | const char *ws_name) { | 143 | const char *ws_name) { |
128 | int i; | 144 | struct workspace_config *wsc = workspace_find_config(ws_name); |
129 | for (i = 0; i < config->workspace_outputs->length; ++i) { | 145 | return !wsc || !wsc->output || strcmp(wsc->output, output_name) == 0; |
130 | struct workspace_output *wso = config->workspace_outputs->items[i]; | ||
131 | if (strcasecmp(wso->workspace, ws_name) == 0) { | ||
132 | if (strcasecmp(wso->output, output_name) != 0) { | ||
133 | return false; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return true; | ||
139 | } | 146 | } |
140 | 147 | ||
141 | static void workspace_name_from_binding(const struct sway_binding * binding, | 148 | static void workspace_name_from_binding(const struct sway_binding * binding, |
@@ -235,13 +242,13 @@ char *workspace_next_name(const char *output_name) { | |||
235 | workspace_name_from_binding(mode->keycode_bindings->items[i], | 242 | workspace_name_from_binding(mode->keycode_bindings->items[i], |
236 | output_name, &order, &target); | 243 | output_name, &order, &target); |
237 | } | 244 | } |
238 | for (int i = 0; i < config->workspace_outputs->length; ++i) { | 245 | for (int i = 0; i < config->workspace_configs->length; ++i) { |
239 | // Unlike with bindings, this does not guarantee order | 246 | // Unlike with bindings, this does not guarantee order |
240 | const struct workspace_output *wso = config->workspace_outputs->items[i]; | 247 | const struct workspace_config *wsc = config->workspace_configs->items[i]; |
241 | if (strcmp(wso->output, output_name) == 0 | 248 | if (wsc->output && strcmp(wsc->output, output_name) == 0 |
242 | && workspace_by_name(wso->workspace) == NULL) { | 249 | && workspace_by_name(wsc->workspace) == NULL) { |
243 | free(target); | 250 | free(target); |
244 | target = strdup(wso->workspace); | 251 | target = strdup(wsc->workspace); |
245 | break; | 252 | break; |
246 | } | 253 | } |
247 | } | 254 | } |
@@ -389,13 +396,11 @@ bool workspace_switch(struct sway_workspace *workspace, | |||
389 | struct sway_output *next_output = workspace->output; | 396 | struct sway_output *next_output = workspace->output; |
390 | struct sway_workspace *next_output_prev_ws = | 397 | struct sway_workspace *next_output_prev_ws = |
391 | output_get_active_workspace(next_output); | 398 | output_get_active_workspace(next_output); |
392 | bool has_sticky = false; | ||
393 | if (workspace != next_output_prev_ws) { | 399 | if (workspace != next_output_prev_ws) { |
394 | for (int i = 0; i < next_output_prev_ws->floating->length; ++i) { | 400 | for (int i = 0; i < next_output_prev_ws->floating->length; ++i) { |
395 | struct sway_container *floater = | 401 | struct sway_container *floater = |
396 | next_output_prev_ws->floating->items[i]; | 402 | next_output_prev_ws->floating->items[i]; |
397 | if (floater->is_sticky) { | 403 | if (floater->is_sticky) { |
398 | has_sticky = true; | ||
399 | container_detach(floater); | 404 | container_detach(floater); |
400 | workspace_add_floating(workspace, floater); | 405 | workspace_add_floating(workspace, floater); |
401 | if (&floater->node == focus) { | 406 | if (&floater->node == focus) { |
@@ -414,14 +419,6 @@ bool workspace_switch(struct sway_workspace *workspace, | |||
414 | if (next == NULL) { | 419 | if (next == NULL) { |
415 | next = &workspace->node; | 420 | next = &workspace->node; |
416 | } | 421 | } |
417 | if (has_sticky) { | ||
418 | // If there's a sticky container, we might be setting focus to the same | ||
419 | // container that's already focused, so seat_set_focus is effectively a | ||
420 | // no op. We therefore need to send the IPC event and clean up the old | ||
421 | // workspace here. | ||
422 | ipc_event_workspace(active_ws, workspace, "focus"); | ||
423 | workspace_consider_destroy(active_ws); | ||
424 | } | ||
425 | seat_set_focus(seat, next); | 422 | seat_set_focus(seat, next); |
426 | arrange_workspace(workspace); | 423 | arrange_workspace(workspace); |
427 | cursor_send_pointer_motion(seat->cursor, 0, true); | 424 | cursor_send_pointer_motion(seat->cursor, 0, true); |
@@ -649,13 +646,13 @@ void workspace_add_gaps(struct sway_workspace *ws) { | |||
649 | return; | 646 | return; |
650 | } | 647 | } |
651 | 648 | ||
652 | ws->current_gaps = ws->has_gaps ? ws->gaps_outer : config->gaps_outer; | 649 | ws->current_gaps = ws->gaps_outer; |
653 | 650 | ||
654 | if (ws->layout == L_TABBED || ws->layout == L_STACKED) { | 651 | if (ws->layout == L_TABBED || ws->layout == L_STACKED) { |
655 | // We have to add inner gaps for this, because children of tabbed and | 652 | // We have to add inner gaps for this, because children of tabbed and |
656 | // stacked containers don't apply their own gaps - they assume the | 653 | // stacked containers don't apply their own gaps - they assume the |
657 | // tabbed/stacked container is using gaps. | 654 | // tabbed/stacked container is using gaps. |
658 | ws->current_gaps += ws->has_gaps ? ws->gaps_inner : config->gaps_inner; | 655 | ws->current_gaps += ws->gaps_inner; |
659 | } | 656 | } |
660 | 657 | ||
661 | ws->x += ws->current_gaps; | 658 | ws->x += ws->current_gaps; |