summaryrefslogtreecommitdiffstats
path: root/sway/commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands.c')
-rw-r--r--sway/commands.c480
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
39struct cmd_handler { 18struct cmd_handler {
@@ -41,10 +20,6 @@ struct cmd_handler {
41 sway_cmd *handle; 20 sway_cmd *handle;
42}; 21};
43 22
44int sp_index = 0;
45
46swayc_t *current_container = NULL;
47
48// Returns error object, or NULL if check succeeds. 23// Returns error object, or NULL if check succeeds.
49struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { 24struct 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
87void hide_view_in_scratchpad(swayc_t *sp_view) { 62void 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
104void 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
140void remove_view_from_scratchpad(swayc_t *view) { 78void 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 */
156static struct cmd_handler handlers[] = { 95static 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
224static struct cmd_handler bar_handlers[] = { 112static 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 */
256struct 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
285static 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
299static struct cmd_handler bar_colors_handlers[] = { 139static 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
313static struct cmd_handler ipc_handlers[] = { 153/* Config-time only commands. Keep alphabetized */
314 { "*", cmd_ipc_cmd }, 154static 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
325static struct cmd_handler ipc_event_handlers[] = { 160/* Runtime-only commands. Keep alphabetized */
326 { "*", cmd_ipc_event_cmd }, 161static 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
335static int handler_compare(const void *_a, const void *_b) { 176static 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
183static 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
204static struct cmd_handler seat_handlers[] = {
205 { "attach", seat_cmd_attach },
206 { "cursor", seat_cmd_cursor },
207 { "fallback", seat_cmd_fallback },
208};
209
341static struct cmd_handler *find_handler(char *line, enum cmd_status block) { 210static 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
373struct cmd_results *handle_command(char *_exec, enum command_context context) { 262struct 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: 386cleanup:
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)
510struct cmd_results *config_command(char *exec, enum cmd_status block) { 401struct 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
632struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, const char *format, ...) { 524struct 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) {
669const char *cmd_results_to_json(struct cmd_results *results) { 562const 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 */
587struct 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}