diff options
Diffstat (limited to 'sway/commands.c')
-rw-r--r-- | sway/commands.c | 480 |
1 files changed, 204 insertions, 276 deletions
diff --git a/sway/commands.c b/sway/commands.c index c7dbf731..54d84450 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -1,39 +1,18 @@ | |||
1 | #define _XOPEN_SOURCE 700 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <xkbcommon/xkbcommon.h> | 2 | #include <ctype.h> |
3 | #include <xkbcommon/xkbcommon-names.h> | 3 | #include <stdarg.h> |
4 | #include <wlc/wlc.h> | ||
5 | #include <wlc/wlc-render.h> | ||
6 | #include <stdio.h> | ||
7 | #include <stdlib.h> | 4 | #include <stdlib.h> |
8 | #include <errno.h> | ||
9 | #include <string.h> | 5 | #include <string.h> |
10 | #include <strings.h> | 6 | #include <strings.h> |
11 | #include <unistd.h> | 7 | #include <stdio.h> |
12 | #include <ctype.h> | 8 | #include <json-c/json.h> |
13 | #include <wordexp.h> | ||
14 | #include <libgen.h> | ||
15 | #include <sys/types.h> | ||
16 | #include <sys/wait.h> | ||
17 | #include <limits.h> | ||
18 | #include <float.h> | ||
19 | #include <libinput.h> | ||
20 | #include "sway/layout.h" | ||
21 | #include "sway/focus.h" | ||
22 | #include "sway/workspace.h" | ||
23 | #include "sway/commands.h" | 9 | #include "sway/commands.h" |
24 | #include "sway/container.h" | 10 | #include "sway/config.h" |
25 | #include "sway/output.h" | ||
26 | #include "sway/handlers.h" | ||
27 | #include "sway/input_state.h" | ||
28 | #include "sway/criteria.h" | 11 | #include "sway/criteria.h" |
29 | #include "sway/ipc-server.h" | ||
30 | #include "sway/security.h" | 12 | #include "sway/security.h" |
31 | #include "sway/input.h" | 13 | #include "sway/input/input-manager.h" |
32 | #include "sway/border.h" | 14 | #include "sway/input/seat.h" |
33 | #include "stringop.h" | 15 | #include "stringop.h" |
34 | #include "sway.h" | ||
35 | #include "util.h" | ||
36 | #include "list.h" | ||
37 | #include "log.h" | 16 | #include "log.h" |
38 | 17 | ||
39 | struct cmd_handler { | 18 | struct cmd_handler { |
@@ -41,10 +20,6 @@ struct cmd_handler { | |||
41 | sway_cmd *handle; | 20 | sway_cmd *handle; |
42 | }; | 21 | }; |
43 | 22 | ||
44 | int sp_index = 0; | ||
45 | |||
46 | swayc_t *current_container = NULL; | ||
47 | |||
48 | // Returns error object, or NULL if check succeeds. | 23 | // Returns error object, or NULL if check succeeds. |
49 | struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { | 24 | struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { |
50 | struct cmd_results *error = NULL; | 25 | struct cmd_results *error = NULL; |
@@ -84,24 +59,7 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type | |||
84 | return error; | 59 | return error; |
85 | } | 60 | } |
86 | 61 | ||
87 | void hide_view_in_scratchpad(swayc_t *sp_view) { | 62 | void apply_input_config(struct input_config *input) { |
88 | if (sp_view == NULL) { | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | wlc_view_set_mask(sp_view->handle, 0); | ||
93 | sp_view->visible = false; | ||
94 | swayc_t *ws = sp_view->parent; | ||
95 | remove_child(sp_view); | ||
96 | if (swayc_active_workspace() != ws && ws->floating->length == 0 && ws->children->length == 0) { | ||
97 | destroy_workspace(ws); | ||
98 | } else { | ||
99 | arrange_windows(ws, -1, -1); | ||
100 | } | ||
101 | set_focused_container(container_under_pointer()); | ||
102 | } | ||
103 | |||
104 | void input_cmd_apply(struct input_config *input) { | ||
105 | int i; | 63 | int i; |
106 | i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); | 64 | i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); |
107 | if (i >= 0) { | 65 | if (i >= 0) { |
@@ -114,111 +72,41 @@ void input_cmd_apply(struct input_config *input) { | |||
114 | list_add(config->input_configs, input); | 72 | list_add(config->input_configs, input); |
115 | } | 73 | } |
116 | 74 | ||
117 | current_input_config = input; | 75 | input_manager_apply_input_config(input_manager, input); |
118 | |||
119 | if (input->identifier) { | ||
120 | // Try to find the input device and apply configuration now. If | ||
121 | // this is during startup then there will be no container and config | ||
122 | // will be applied during normal "new input" event from wlc. | ||
123 | struct libinput_device *device = NULL; | ||
124 | for (int i = 0; i < input_devices->length; ++i) { | ||
125 | device = input_devices->items[i]; | ||
126 | char* dev_identifier = libinput_dev_unique_id(device); | ||
127 | if (!dev_identifier) { | ||
128 | break; | ||
129 | } | ||
130 | int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0; | ||
131 | free(dev_identifier); | ||
132 | if (match) { | ||
133 | apply_input_config(input, device); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | } | 76 | } |
139 | 77 | ||
140 | void remove_view_from_scratchpad(swayc_t *view) { | 78 | void apply_seat_config(struct seat_config *seat_config) { |
141 | int i; | 79 | int i; |
142 | for (i = 0; i < scratchpad->length; i++) { | 80 | i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name); |
143 | if (scratchpad->items[i] == view) { | 81 | if (i >= 0) { |
144 | if (sp_index == 0) { | 82 | // merge existing config |
145 | sp_index = scratchpad->length - 1; | 83 | struct seat_config *sc = config->seat_configs->items[i]; |
146 | } else { | 84 | merge_seat_config(sc, seat_config); |
147 | sp_index--; | 85 | free_seat_config(seat_config); |
148 | } | 86 | seat_config = sc; |
149 | list_del(scratchpad, sp_index); | 87 | } else { |
150 | sp_view = NULL; | 88 | list_add(config->seat_configs, seat_config); |
151 | } | ||
152 | } | 89 | } |
90 | |||
91 | input_manager_apply_seat_config(input_manager, seat_config); | ||
153 | } | 92 | } |
154 | 93 | ||
155 | /* Keep alphabetized */ | 94 | /* Keep alphabetized */ |
156 | static struct cmd_handler handlers[] = { | 95 | static struct cmd_handler handlers[] = { |
157 | { "assign", cmd_assign }, | ||
158 | { "bar", cmd_bar }, | 96 | { "bar", cmd_bar }, |
159 | { "bindcode", cmd_bindcode }, | 97 | { "bindcode", cmd_bindcode }, |
160 | { "bindsym", cmd_bindsym }, | 98 | { "bindsym", cmd_bindsym }, |
161 | { "border", cmd_border }, | ||
162 | { "client.background", cmd_client_background }, | ||
163 | { "client.focused", cmd_client_focused }, | ||
164 | { "client.focused_inactive", cmd_client_focused_inactive }, | ||
165 | { "client.placeholder", cmd_client_placeholder }, | ||
166 | { "client.unfocused", cmd_client_unfocused }, | ||
167 | { "client.urgent", cmd_client_urgent }, | ||
168 | { "clipboard", cmd_clipboard }, | ||
169 | { "commands", cmd_commands }, | ||
170 | { "debuglog", cmd_debuglog }, | ||
171 | { "default_border", cmd_default_border }, | ||
172 | { "default_floating_border", cmd_default_floating_border }, | ||
173 | { "default_orientation", cmd_orientation }, | ||
174 | { "exec", cmd_exec }, | 99 | { "exec", cmd_exec }, |
175 | { "exec_always", cmd_exec_always }, | 100 | { "exec_always", cmd_exec_always }, |
176 | { "exit", cmd_exit }, | ||
177 | { "floating", cmd_floating }, | ||
178 | { "floating_maximum_size", cmd_floating_maximum_size }, | ||
179 | { "floating_minimum_size", cmd_floating_minimum_size }, | ||
180 | { "floating_modifier", cmd_floating_mod }, | ||
181 | { "floating_scroll", cmd_floating_scroll }, | ||
182 | { "focus", cmd_focus }, | ||
183 | { "focus_follows_mouse", cmd_focus_follows_mouse }, | 101 | { "focus_follows_mouse", cmd_focus_follows_mouse }, |
184 | { "font", cmd_font }, | ||
185 | { "for_window", cmd_for_window }, | ||
186 | { "force_focus_wrapping", cmd_force_focus_wrapping }, | ||
187 | { "fullscreen", cmd_fullscreen }, | ||
188 | { "gaps", cmd_gaps }, | ||
189 | { "hide_edge_borders", cmd_hide_edge_borders }, | ||
190 | { "include", cmd_include }, | 102 | { "include", cmd_include }, |
191 | { "input", cmd_input }, | 103 | { "input", cmd_input }, |
192 | { "ipc", cmd_ipc }, | ||
193 | { "kill", cmd_kill }, | ||
194 | { "layout", cmd_layout }, | ||
195 | { "log_colors", cmd_log_colors }, | ||
196 | { "mark", cmd_mark }, | ||
197 | { "mode", cmd_mode }, | 104 | { "mode", cmd_mode }, |
198 | { "mouse_warping", cmd_mouse_warping }, | 105 | { "mouse_warping", cmd_mouse_warping }, |
199 | { "move", cmd_move }, | ||
200 | { "new_float", cmd_new_float }, | ||
201 | { "new_window", cmd_new_window }, | ||
202 | { "no_focus", cmd_no_focus }, | ||
203 | { "output", cmd_output }, | 106 | { "output", cmd_output }, |
204 | { "permit", cmd_permit }, | 107 | { "seat", cmd_seat }, |
205 | { "reject", cmd_reject }, | ||
206 | { "reload", cmd_reload }, | ||
207 | { "resize", cmd_resize }, | ||
208 | { "scratchpad", cmd_scratchpad }, | ||
209 | { "seamless_mouse", cmd_seamless_mouse }, | ||
210 | { "set", cmd_set }, | ||
211 | { "show_marks", cmd_show_marks }, | ||
212 | { "smart_gaps", cmd_smart_gaps }, | ||
213 | { "split", cmd_split }, | ||
214 | { "splith", cmd_splith }, | ||
215 | { "splitt", cmd_splitt }, | ||
216 | { "splitv", cmd_splitv }, | ||
217 | { "sticky", cmd_sticky }, | ||
218 | { "unmark", cmd_unmark }, | ||
219 | { "workspace", cmd_workspace }, | 108 | { "workspace", cmd_workspace }, |
220 | { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, | 109 | { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, |
221 | { "workspace_layout", cmd_workspace_layout }, | ||
222 | }; | 110 | }; |
223 | 111 | ||
224 | static struct cmd_handler bar_handlers[] = { | 112 | static struct cmd_handler bar_handlers[] = { |
@@ -248,54 +136,6 @@ static struct cmd_handler bar_handlers[] = { | |||
248 | { "wrap_scroll", bar_cmd_wrap_scroll }, | 136 | { "wrap_scroll", bar_cmd_wrap_scroll }, |
249 | }; | 137 | }; |
250 | 138 | ||
251 | /** | ||
252 | * Check and add color to buffer. | ||
253 | * | ||
254 | * return error object, or NULL if color is valid. | ||
255 | */ | ||
256 | struct cmd_results *add_color(const char *name, char *buffer, const char *color) { | ||
257 | int len = strlen(color); | ||
258 | if (len != 7 && len != 9) { | ||
259 | return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); | ||
260 | } | ||
261 | |||
262 | if (color[0] != '#') { | ||
263 | return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); | ||
264 | } | ||
265 | |||
266 | int i; | ||
267 | for (i = 1; i < len; ++i) { | ||
268 | if (!isxdigit(color[i])) { | ||
269 | return cmd_results_new(CMD_INVALID, name, "Invalid color definition %s", color); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | // copy color to buffer | ||
274 | strncpy(buffer, color, len); | ||
275 | // add default alpha channel if color was defined without it | ||
276 | if (len == 7) { | ||
277 | buffer[7] = 'f'; | ||
278 | buffer[8] = 'f'; | ||
279 | } | ||
280 | buffer[9] = '\0'; | ||
281 | |||
282 | return NULL; | ||
283 | } | ||
284 | |||
285 | static struct cmd_handler input_handlers[] = { | ||
286 | { "accel_profile", input_cmd_accel_profile }, | ||
287 | { "click_method", input_cmd_click_method }, | ||
288 | { "drag_lock", input_cmd_drag_lock }, | ||
289 | { "dwt", input_cmd_dwt }, | ||
290 | { "events", input_cmd_events }, | ||
291 | { "left_handed", input_cmd_left_handed }, | ||
292 | { "middle_emulation", input_cmd_middle_emulation }, | ||
293 | { "natural_scroll", input_cmd_natural_scroll }, | ||
294 | { "pointer_accel", input_cmd_pointer_accel }, | ||
295 | { "scroll_method", input_cmd_scroll_method }, | ||
296 | { "tap", input_cmd_tap }, | ||
297 | }; | ||
298 | |||
299 | static struct cmd_handler bar_colors_handlers[] = { | 139 | static struct cmd_handler bar_colors_handlers[] = { |
300 | { "active_workspace", bar_colors_cmd_active_workspace }, | 140 | { "active_workspace", bar_colors_cmd_active_workspace }, |
301 | { "background", bar_colors_cmd_background }, | 141 | { "background", bar_colors_cmd_background }, |
@@ -310,26 +150,27 @@ static struct cmd_handler bar_colors_handlers[] = { | |||
310 | { "urgent_workspace", bar_colors_cmd_urgent_workspace }, | 150 | { "urgent_workspace", bar_colors_cmd_urgent_workspace }, |
311 | }; | 151 | }; |
312 | 152 | ||
313 | static struct cmd_handler ipc_handlers[] = { | 153 | /* Config-time only commands. Keep alphabetized */ |
314 | { "*", cmd_ipc_cmd }, | 154 | static struct cmd_handler config_handlers[] = { |
315 | { "bar-config", cmd_ipc_cmd }, | 155 | { "default_orientation", cmd_default_orientation }, |
316 | { "command", cmd_ipc_cmd }, | 156 | { "set", cmd_set }, |
317 | { "events", cmd_ipc_events }, | 157 | { "swaybg_command", cmd_swaybg_command }, |
318 | { "inputs", cmd_ipc_cmd }, | ||
319 | { "marks", cmd_ipc_cmd }, | ||
320 | { "outputs", cmd_ipc_cmd }, | ||
321 | { "tree", cmd_ipc_cmd }, | ||
322 | { "workspaces", cmd_ipc_cmd }, | ||
323 | }; | 158 | }; |
324 | 159 | ||
325 | static struct cmd_handler ipc_event_handlers[] = { | 160 | /* Runtime-only commands. Keep alphabetized */ |
326 | { "*", cmd_ipc_event_cmd }, | 161 | static struct cmd_handler command_handlers[] = { |
327 | { "binding", cmd_ipc_event_cmd }, | 162 | { "exit", cmd_exit }, |
328 | { "input", cmd_ipc_event_cmd }, | 163 | { "focus", cmd_focus }, |
329 | { "mode", cmd_ipc_event_cmd }, | 164 | { "kill", cmd_kill }, |
330 | { "output", cmd_ipc_event_cmd }, | 165 | { "layout", cmd_layout }, |
331 | { "window", cmd_ipc_event_cmd }, | 166 | { "move", cmd_move }, |
332 | { "workspace", cmd_ipc_event_cmd }, | 167 | { "opacity", cmd_opacity }, |
168 | { "reload", cmd_reload }, | ||
169 | { "resize", cmd_resize }, | ||
170 | { "split", cmd_split }, | ||
171 | { "splith", cmd_splith }, | ||
172 | { "splitt", cmd_splitt }, | ||
173 | { "splitv", cmd_splitv }, | ||
333 | }; | 174 | }; |
334 | 175 | ||
335 | static int handler_compare(const void *_a, const void *_b) { | 176 | static int handler_compare(const void *_a, const void *_b) { |
@@ -338,42 +179,90 @@ static int handler_compare(const void *_a, const void *_b) { | |||
338 | return strcasecmp(a->command, b->command); | 179 | return strcasecmp(a->command, b->command); |
339 | } | 180 | } |
340 | 181 | ||
182 | // must be in order for the bsearch | ||
183 | static struct cmd_handler input_handlers[] = { | ||
184 | { "accel_profile", input_cmd_accel_profile }, | ||
185 | { "click_method", input_cmd_click_method }, | ||
186 | { "drag_lock", input_cmd_drag_lock }, | ||
187 | { "dwt", input_cmd_dwt }, | ||
188 | { "events", input_cmd_events }, | ||
189 | { "left_handed", input_cmd_left_handed }, | ||
190 | { "map_to_output", input_cmd_map_to_output }, | ||
191 | { "middle_emulation", input_cmd_middle_emulation }, | ||
192 | { "natural_scroll", input_cmd_natural_scroll }, | ||
193 | { "pointer_accel", input_cmd_pointer_accel }, | ||
194 | { "scroll_method", input_cmd_scroll_method }, | ||
195 | { "tap", input_cmd_tap }, | ||
196 | { "xkb_layout", input_cmd_xkb_layout }, | ||
197 | { "xkb_model", input_cmd_xkb_model }, | ||
198 | { "xkb_options", input_cmd_xkb_options }, | ||
199 | { "xkb_rules", input_cmd_xkb_rules }, | ||
200 | { "xkb_variant", input_cmd_xkb_variant }, | ||
201 | }; | ||
202 | |||
203 | // must be in order for the bsearch | ||
204 | static struct cmd_handler seat_handlers[] = { | ||
205 | { "attach", seat_cmd_attach }, | ||
206 | { "cursor", seat_cmd_cursor }, | ||
207 | { "fallback", seat_cmd_fallback }, | ||
208 | }; | ||
209 | |||
341 | static struct cmd_handler *find_handler(char *line, enum cmd_status block) { | 210 | static struct cmd_handler *find_handler(char *line, enum cmd_status block) { |
342 | struct cmd_handler d = { .command=line }; | 211 | struct cmd_handler d = { .command=line }; |
343 | struct cmd_handler *res = NULL; | 212 | struct cmd_handler *res = NULL; |
344 | sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); | 213 | wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); |
214 | |||
215 | bool config_loading = config->reading || !config->active; | ||
216 | |||
345 | if (block == CMD_BLOCK_BAR) { | 217 | if (block == CMD_BLOCK_BAR) { |
346 | res = bsearch(&d, bar_handlers, | 218 | return bsearch(&d, bar_handlers, |
347 | sizeof(bar_handlers) / sizeof(struct cmd_handler), | 219 | sizeof(bar_handlers) / sizeof(struct cmd_handler), |
348 | sizeof(struct cmd_handler), handler_compare); | 220 | sizeof(struct cmd_handler), handler_compare); |
349 | } else if (block == CMD_BLOCK_BAR_COLORS){ | 221 | } else if (block == CMD_BLOCK_BAR_COLORS) { |
350 | res = bsearch(&d, bar_colors_handlers, | 222 | return bsearch(&d, bar_colors_handlers, |
351 | sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), | 223 | sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), |
352 | sizeof(struct cmd_handler), handler_compare); | 224 | sizeof(struct cmd_handler), handler_compare); |
353 | } else if (block == CMD_BLOCK_INPUT) { | 225 | } else if (block == CMD_BLOCK_INPUT) { |
354 | res = bsearch(&d, input_handlers, | 226 | return bsearch(&d, input_handlers, |
355 | sizeof(input_handlers) / sizeof(struct cmd_handler), | 227 | sizeof(input_handlers) / sizeof(struct cmd_handler), |
356 | sizeof(struct cmd_handler), handler_compare); | 228 | sizeof(struct cmd_handler), handler_compare); |
357 | } else if (block == CMD_BLOCK_IPC) { | 229 | } else if (block == CMD_BLOCK_SEAT) { |
358 | res = bsearch(&d, ipc_handlers, | 230 | return bsearch(&d, seat_handlers, |
359 | sizeof(ipc_handlers) / sizeof(struct cmd_handler), | 231 | sizeof(seat_handlers) / sizeof(struct cmd_handler), |
360 | sizeof(struct cmd_handler), handler_compare); | 232 | sizeof(struct cmd_handler), handler_compare); |
361 | } else if (block == CMD_BLOCK_IPC_EVENTS) { | 233 | } |
362 | res = bsearch(&d, ipc_event_handlers, | 234 | |
363 | sizeof(ipc_event_handlers) / sizeof(struct cmd_handler), | 235 | if (!config_loading) { |
364 | sizeof(struct cmd_handler), handler_compare); | 236 | res = bsearch(&d, command_handlers, |
365 | } else { | 237 | sizeof(command_handlers) / sizeof(struct cmd_handler), |
366 | res = bsearch(&d, handlers, | 238 | sizeof(struct cmd_handler), handler_compare); |
239 | |||
240 | if (res) { | ||
241 | return res; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | if (config->reading) { | ||
246 | res = bsearch(&d, config_handlers, | ||
247 | sizeof(config_handlers) / sizeof(struct cmd_handler), | ||
248 | sizeof(struct cmd_handler), handler_compare); | ||
249 | |||
250 | if (res) { | ||
251 | return res; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | res = bsearch(&d, handlers, | ||
367 | sizeof(handlers) / sizeof(struct cmd_handler), | 256 | sizeof(handlers) / sizeof(struct cmd_handler), |
368 | sizeof(struct cmd_handler), handler_compare); | 257 | sizeof(struct cmd_handler), handler_compare); |
369 | } | 258 | |
370 | return res; | 259 | return res; |
371 | } | 260 | } |
372 | 261 | ||
373 | struct cmd_results *handle_command(char *_exec, enum command_context context) { | 262 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { |
374 | // Even though this function will process multiple commands we will only | 263 | // Even though this function will process multiple commands we will only |
375 | // return the last error, if any (for now). (Since we have access to an | 264 | // return the last error, if any (for now). (Since we have access to an |
376 | // error string we could e.g. concatonate all errors there.) | 265 | // error string we could e.g. concatenate all errors there.) |
377 | struct cmd_results *results = NULL; | 266 | struct cmd_results *results = NULL; |
378 | char *exec = strdup(_exec); | 267 | char *exec = strdup(_exec); |
379 | char *head = exec; | 268 | char *head = exec; |
@@ -381,10 +270,22 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
381 | char *cmd; | 270 | char *cmd; |
382 | list_t *containers = NULL; | 271 | list_t *containers = NULL; |
383 | 272 | ||
273 | if (seat == NULL) { | ||
274 | // passing a NULL seat means we just pick the default seat | ||
275 | seat = input_manager_get_default_seat(input_manager); | ||
276 | if (!sway_assert(seat, "could not find a seat to run the command on")) { | ||
277 | return NULL; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | config->handler_context.seat = seat; | ||
282 | |||
384 | head = exec; | 283 | head = exec; |
385 | do { | 284 | do { |
386 | // Extract criteria (valid for this command list only). | 285 | // Extract criteria (valid for this command list only). |
286 | bool has_criteria = false; | ||
387 | if (*head == '[') { | 287 | if (*head == '[') { |
288 | has_criteria = true; | ||
388 | ++head; | 289 | ++head; |
389 | char *criteria_string = argsep(&head, "]"); | 290 | char *criteria_string = argsep(&head, "]"); |
390 | if (head) { | 291 | if (head) { |
@@ -393,13 +294,14 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
393 | char *error; | 294 | char *error; |
394 | 295 | ||
395 | if ((error = extract_crit_tokens(tokens, criteria_string))) { | 296 | if ((error = extract_crit_tokens(tokens, criteria_string))) { |
297 | wlr_log(L_DEBUG, "criteria string parse error: %s", error); | ||
396 | results = cmd_results_new(CMD_INVALID, criteria_string, | 298 | results = cmd_results_new(CMD_INVALID, criteria_string, |
397 | "Can't parse criteria string: %s", error); | 299 | "Can't parse criteria string: %s", error); |
398 | free(error); | 300 | free(error); |
399 | free(tokens); | 301 | free(tokens); |
400 | goto cleanup; | 302 | goto cleanup; |
401 | } | 303 | } |
402 | containers = container_for(tokens); | 304 | containers = container_for_crit_tokens(tokens); |
403 | 305 | ||
404 | free(tokens); | 306 | free(tokens); |
405 | } else { | 307 | } else { |
@@ -419,10 +321,10 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
419 | cmd = argsep(&cmdlist, ","); | 321 | cmd = argsep(&cmdlist, ","); |
420 | cmd += strspn(cmd, whitespace); | 322 | cmd += strspn(cmd, whitespace); |
421 | if (strcmp(cmd, "") == 0) { | 323 | if (strcmp(cmd, "") == 0) { |
422 | sway_log(L_INFO, "Ignoring empty command."); | 324 | wlr_log(L_INFO, "Ignoring empty command."); |
423 | continue; | 325 | continue; |
424 | } | 326 | } |
425 | sway_log(L_INFO, "Handling command '%s'", cmd); | 327 | wlr_log(L_INFO, "Handling command '%s'", cmd); |
426 | //TODO better handling of argv | 328 | //TODO better handling of argv |
427 | int argc; | 329 | int argc; |
428 | char **argv = split_args(cmd, &argc); | 330 | char **argv = split_args(cmd, &argc); |
@@ -443,31 +345,16 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
443 | free_argv(argc, argv); | 345 | free_argv(argc, argv); |
444 | goto cleanup; | 346 | goto cleanup; |
445 | } | 347 | } |
446 | if (!(get_command_policy_mask(argv[0]) & context)) { | ||
447 | if (results) { | ||
448 | free_cmd_results(results); | ||
449 | } | ||
450 | results = cmd_results_new(CMD_INVALID, cmd, | ||
451 | "Permission denied for %s via %s", cmd, | ||
452 | command_policy_str(context)); | ||
453 | free_argv(argc, argv); | ||
454 | goto cleanup; | ||
455 | } | ||
456 | int i = 0; | ||
457 | do { | ||
458 | if (!containers) { | ||
459 | current_container = get_focused_container(&root_container); | ||
460 | } else if (containers->length == 0) { | ||
461 | if (results) { | ||
462 | free_cmd_results(results); | ||
463 | } | ||
464 | results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container"); | ||
465 | goto cleanup; | ||
466 | } else { | ||
467 | current_container = (swayc_t *)containers->items[i]; | ||
468 | } | ||
469 | sway_log(L_INFO, "Running on container '%s'", current_container->name); | ||
470 | 348 | ||
349 | if (!has_criteria) { | ||
350 | // without criteria, the command acts upon the focused | ||
351 | // container | ||
352 | config->handler_context.current_container = | ||
353 | seat_get_focus_inactive(seat, &root_container); | ||
354 | if (!sway_assert(config->handler_context.current_container, | ||
355 | "could not get focus-inactive for root container")) { | ||
356 | return NULL; | ||
357 | } | ||
471 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 358 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
472 | if (res->status != CMD_SUCCESS) { | 359 | if (res->status != CMD_SUCCESS) { |
473 | free_argv(argc, argv); | 360 | free_argv(argc, argv); |
@@ -478,35 +365,39 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
478 | goto cleanup; | 365 | goto cleanup; |
479 | } | 366 | } |
480 | free_cmd_results(res); | 367 | free_cmd_results(res); |
481 | ++i; | 368 | } else { |
482 | } while(containers && i < containers->length); | 369 | for (int i = 0; i < containers->length; ++i) { |
483 | 370 | config->handler_context.current_container = containers->items[i]; | |
371 | struct cmd_results *res = handler->handle(argc-1, argv+1); | ||
372 | if (res->status != CMD_SUCCESS) { | ||
373 | free_argv(argc, argv); | ||
374 | if (results) { | ||
375 | free_cmd_results(results); | ||
376 | } | ||
377 | results = res; | ||
378 | goto cleanup; | ||
379 | } | ||
380 | free_cmd_results(res); | ||
381 | } | ||
382 | } | ||
484 | free_argv(argc, argv); | 383 | free_argv(argc, argv); |
485 | } while(cmdlist); | 384 | } while(cmdlist); |
486 | |||
487 | if (containers) { | ||
488 | list_free(containers); | ||
489 | containers = NULL; | ||
490 | } | ||
491 | } while(head); | 385 | } while(head); |
492 | cleanup: | 386 | cleanup: |
493 | free(exec); | 387 | free(exec); |
494 | if (containers) { | ||
495 | free(containers); | ||
496 | } | ||
497 | if (!results) { | 388 | if (!results) { |
498 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | 389 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); |
499 | } | 390 | } |
500 | return results; | 391 | return results; |
501 | } | 392 | } |
502 | 393 | ||
503 | // this is like handle_command above, except: | 394 | // this is like execute_command above, except: |
504 | // 1) it ignores empty commands (empty lines) | 395 | // 1) it ignores empty commands (empty lines) |
505 | // 2) it does variable substitution | 396 | // 2) it does variable substitution |
506 | // 3) it doesn't split commands (because the multiple commands are supposed to | 397 | // 3) it doesn't split commands (because the multiple commands are supposed to |
507 | // be chained together) | 398 | // be chained together) |
508 | // 4) handle_command handles all state internally while config_command has some | 399 | // 4) execute_command handles all state internally while config_command has |
509 | // state handled outside (notably the block mode, in read_config) | 400 | // some state handled outside (notably the block mode, in read_config) |
510 | struct cmd_results *config_command(char *exec, enum cmd_status block) { | 401 | struct cmd_results *config_command(char *exec, enum cmd_status block) { |
511 | struct cmd_results *results = NULL; | 402 | struct cmd_results *results = NULL; |
512 | int argc; | 403 | int argc; |
@@ -516,7 +407,7 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) { | |||
516 | goto cleanup; | 407 | goto cleanup; |
517 | } | 408 | } |
518 | 409 | ||
519 | sway_log(L_INFO, "handling config command '%s'", exec); | 410 | wlr_log(L_INFO, "handling config command '%s'", exec); |
520 | // Endblock | 411 | // Endblock |
521 | if (**argv == '}') { | 412 | if (**argv == '}') { |
522 | results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); | 413 | results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); |
@@ -530,12 +421,13 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) { | |||
530 | } | 421 | } |
531 | int i; | 422 | int i; |
532 | // Var replacement, for all but first argument of set | 423 | // Var replacement, for all but first argument of set |
424 | // TODO commands | ||
533 | for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { | 425 | for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { |
534 | argv[i] = do_var_replacement(argv[i]); | 426 | argv[i] = do_var_replacement(argv[i]); |
535 | unescape_string(argv[i]); | 427 | unescape_string(argv[i]); |
536 | } | 428 | } |
537 | /* Strip quotes for first argument. | 429 | // Strip quotes for first argument. |
538 | * TODO This part needs to be handled much better */ | 430 | // TODO This part needs to be handled much better |
539 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { | 431 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { |
540 | strip_quotes(argv[1]); | 432 | strip_quotes(argv[1]); |
541 | } | 433 | } |
@@ -619,7 +511,7 @@ struct cmd_results *config_commands_command(char *exec) { | |||
619 | } | 511 | } |
620 | policy->context = context; | 512 | policy->context = context; |
621 | 513 | ||
622 | sway_log(L_INFO, "Set command policy for %s to %d", | 514 | wlr_log(L_INFO, "Set command policy for %s to %d", |
623 | policy->command, policy->context); | 515 | policy->command, policy->context); |
624 | 516 | ||
625 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | 517 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); |
@@ -629,10 +521,11 @@ cleanup: | |||
629 | return results; | 521 | return results; |
630 | } | 522 | } |
631 | 523 | ||
632 | struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *format, ...) { | 524 | struct cmd_results *cmd_results_new(enum cmd_status status, |
525 | const char *input, const char *format, ...) { | ||
633 | struct cmd_results *results = malloc(sizeof(struct cmd_results)); | 526 | struct cmd_results *results = malloc(sizeof(struct cmd_results)); |
634 | if (!results) { | 527 | if (!results) { |
635 | sway_log(L_ERROR, "Unable to allocate command results"); | 528 | wlr_log(L_ERROR, "Unable to allocate command results"); |
636 | return NULL; | 529 | return NULL; |
637 | } | 530 | } |
638 | results->status = status; | 531 | results->status = status; |
@@ -669,12 +562,15 @@ void free_cmd_results(struct cmd_results *results) { | |||
669 | const char *cmd_results_to_json(struct cmd_results *results) { | 562 | const char *cmd_results_to_json(struct cmd_results *results) { |
670 | json_object *result_array = json_object_new_array(); | 563 | json_object *result_array = json_object_new_array(); |
671 | json_object *root = json_object_new_object(); | 564 | json_object *root = json_object_new_object(); |
672 | json_object_object_add(root, "success", json_object_new_boolean(results->status == CMD_SUCCESS)); | 565 | json_object_object_add(root, "success", |
566 | json_object_new_boolean(results->status == CMD_SUCCESS)); | ||
673 | if (results->input) { | 567 | if (results->input) { |
674 | json_object_object_add(root, "input", json_object_new_string(results->input)); | 568 | json_object_object_add( |
569 | root, "input", json_object_new_string(results->input)); | ||
675 | } | 570 | } |
676 | if (results->error) { | 571 | if (results->error) { |
677 | json_object_object_add(root, "error", json_object_new_string(results->error)); | 572 | json_object_object_add( |
573 | root, "error", json_object_new_string(results->error)); | ||
678 | } | 574 | } |
679 | json_object_array_add(result_array, root); | 575 | json_object_array_add(result_array, root); |
680 | const char *json = json_object_to_json_string(result_array); | 576 | const char *json = json_object_to_json_string(result_array); |
@@ -682,3 +578,35 @@ const char *cmd_results_to_json(struct cmd_results *results) { | |||
682 | free(root); | 578 | free(root); |
683 | return json; | 579 | return json; |
684 | } | 580 | } |
581 | |||
582 | /** | ||
583 | * Check and add color to buffer. | ||
584 | * | ||
585 | * return error object, or NULL if color is valid. | ||
586 | */ | ||
587 | struct cmd_results *add_color(const char *name, | ||
588 | char *buffer, const char *color) { | ||
589 | int len = strlen(color); | ||
590 | if (len != 7 && len != 9) { | ||
591 | return cmd_results_new(CMD_INVALID, name, | ||
592 | "Invalid color definition %s", color); | ||
593 | } | ||
594 | if (color[0] != '#') { | ||
595 | return cmd_results_new(CMD_INVALID, name, | ||
596 | "Invalid color definition %s", color); | ||
597 | } | ||
598 | for (int i = 1; i < len; ++i) { | ||
599 | if (!isxdigit(color[i])) { | ||
600 | return cmd_results_new(CMD_INVALID, name, | ||
601 | "Invalid color definition %s", color); | ||
602 | } | ||
603 | } | ||
604 | strncpy(buffer, color, len); | ||
605 | // add default alpha channel if color was defined without it | ||
606 | if (len == 7) { | ||
607 | buffer[7] = 'f'; | ||
608 | buffer[8] = 'f'; | ||
609 | } | ||
610 | buffer[9] = '\0'; | ||
611 | return NULL; | ||
612 | } | ||