aboutsummaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-01-22 01:16:23 +0100
committerLibravatar GitHub <noreply@github.com>2018-01-22 01:16:23 +0100
commit0c58673c6a108ba241419a0f1d5fecd47f22370e (patch)
treec3e19af6dd70f04fc5c617e932b4afcc7a1b41d9 /sway
parentRemove sway/old/ (diff)
parentdont allow kill command in config (diff)
downloadsway-0c58673c6a108ba241419a0f1d5fecd47f22370e.tar.gz
sway-0c58673c6a108ba241419a0f1d5fecd47f22370e.tar.zst
sway-0c58673c6a108ba241419a0f1d5fecd47f22370e.zip
Merge pull request #1574 from acrisci/config-refactor
Command criteria
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c81
-rw-r--r--sway/commands/input.c31
-rw-r--r--sway/commands/input/accel_profile.c2
-rw-r--r--sway/commands/input/click_method.c4
-rw-r--r--sway/commands/input/drag_lock.c2
-rw-r--r--sway/commands/input/dwt.c2
-rw-r--r--sway/commands/input/events.c6
-rw-r--r--sway/commands/input/left_handed.c2
-rw-r--r--sway/commands/input/middle_emulation.c2
-rw-r--r--sway/commands/input/natural_scroll.c2
-rw-r--r--sway/commands/input/pointer_accel.c2
-rw-r--r--sway/commands/input/scroll_method.c2
-rw-r--r--sway/commands/input/tap.c3
-rw-r--r--sway/commands/input/xkb_layout.c3
-rw-r--r--sway/commands/input/xkb_model.c3
-rw-r--r--sway/commands/input/xkb_options.c3
-rw-r--r--sway/commands/input/xkb_rules.c3
-rw-r--r--sway/commands/input/xkb_variant.c3
-rw-r--r--sway/commands/kill.c28
-rw-r--r--sway/commands/seat.c25
-rw-r--r--sway/commands/seat/attach.c2
-rw-r--r--sway/commands/seat/fallback.c3
-rw-r--r--sway/config.c12
-rw-r--r--sway/criteria.c445
-rw-r--r--sway/desktop/wl_shell.c9
-rw-r--r--sway/desktop/xdg_shell_v6.c11
-rw-r--r--sway/desktop/xwayland.c8
-rw-r--r--sway/input/input-manager.c11
-rw-r--r--sway/input/keyboard.c9
-rw-r--r--sway/input/seat.c5
-rw-r--r--sway/ipc-server.c1
-rw-r--r--sway/meson.build4
-rw-r--r--sway/tree/container.c24
-rw-r--r--sway/tree/layout.c8
-rw-r--r--sway/tree/view.c53
35 files changed, 765 insertions, 49 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 1005cf68..a77ff791 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -8,8 +8,10 @@
8#include <json-c/json.h> 8#include <json-c/json.h>
9#include "sway/commands.h" 9#include "sway/commands.h"
10#include "sway/config.h" 10#include "sway/config.h"
11#include "sway/criteria.h"
11#include "sway/security.h" 12#include "sway/security.h"
12#include "sway/input/input-manager.h" 13#include "sway/input/input-manager.h"
14#include "sway/input/seat.h"
13#include "stringop.h" 15#include "stringop.h"
14#include "log.h" 16#include "log.h"
15 17
@@ -70,10 +72,7 @@ void apply_input_config(struct input_config *input) {
70 list_add(config->input_configs, input); 72 list_add(config->input_configs, input);
71 } 73 }
72 74
73 struct input_config *old_input_config = current_input_config;
74 current_input_config = input;
75 sway_input_manager_apply_input_config(input_manager, input); 75 sway_input_manager_apply_input_config(input_manager, input);
76 current_input_config = old_input_config;
77} 76}
78 77
79void apply_seat_config(struct seat_config *seat) { 78void apply_seat_config(struct seat_config *seat) {
@@ -89,7 +88,6 @@ void apply_seat_config(struct seat_config *seat) {
89 list_add(config->seat_configs, seat); 88 list_add(config->seat_configs, seat);
90 } 89 }
91 90
92 current_seat_config = seat;
93 sway_input_manager_apply_seat_config(input_manager, seat); 91 sway_input_manager_apply_seat_config(input_manager, seat);
94} 92}
95 93
@@ -136,6 +134,7 @@ static struct cmd_handler handlers[] = {
136 { "exit", cmd_exit }, 134 { "exit", cmd_exit },
137 { "include", cmd_include }, 135 { "include", cmd_include },
138 { "input", cmd_input }, 136 { "input", cmd_input },
137 { "kill", cmd_kill },
139 { "output", cmd_output }, 138 { "output", cmd_output },
140 { "seat", cmd_seat }, 139 { "seat", cmd_seat },
141 { "set", cmd_set }, 140 { "set", cmd_set },
@@ -204,9 +203,41 @@ struct cmd_results *handle_command(char *_exec) {
204 char *head = exec; 203 char *head = exec;
205 char *cmdlist; 204 char *cmdlist;
206 char *cmd; 205 char *cmd;
206 list_t *containers = NULL;
207 207
208 head = exec; 208 head = exec;
209 do { 209 do {
210 // Extract criteria (valid for this command list only).
211 bool has_criteria = false;
212 if (*head == '[') {
213 has_criteria = true;
214 ++head;
215 char *criteria_string = argsep(&head, "]");
216 if (head) {
217 ++head;
218 list_t *tokens = create_list();
219 char *error;
220
221 if ((error = extract_crit_tokens(tokens, criteria_string))) {
222 wlr_log(L_DEBUG, "criteria string parse error: %s", error);
223 results = cmd_results_new(CMD_INVALID, criteria_string,
224 "Can't parse criteria string: %s", error);
225 free(error);
226 free(tokens);
227 goto cleanup;
228 }
229 containers = container_for_crit_tokens(tokens);
230
231 free(tokens);
232 } else {
233 if (!results) {
234 results = cmd_results_new(CMD_INVALID, criteria_string, "Unmatched [");
235 }
236 goto cleanup;
237 }
238 // Skip leading whitespace
239 head += strspn(head, whitespace);
240 }
210 // Split command list 241 // Split command list
211 cmdlist = argsep(&head, ";"); 242 cmdlist = argsep(&head, ";");
212 cmdlist += strspn(cmdlist, whitespace); 243 cmdlist += strspn(cmdlist, whitespace);
@@ -239,16 +270,42 @@ struct cmd_results *handle_command(char *_exec) {
239 free_argv(argc, argv); 270 free_argv(argc, argv);
240 goto cleanup; 271 goto cleanup;
241 } 272 }
242 struct cmd_results *res = handler->handle(argc-1, argv+1); 273
243 if (res->status != CMD_SUCCESS) { 274 if (!has_criteria) {
244 free_argv(argc, argv); 275 // without criteria, the command acts upon the focused
245 if (results) { 276 // container
246 free_cmd_results(results); 277 struct sway_seat *seat = config->handler_context.seat;
278 if (!seat) {
279 seat = sway_input_manager_get_default_seat(input_manager);
280 }
281 if (seat) {
282 config->handler_context.current_container = seat->focus;
283 struct cmd_results *res = handler->handle(argc-1, argv+1);
284 if (res->status != CMD_SUCCESS) {
285 free_argv(argc, argv);
286 if (results) {
287 free_cmd_results(results);
288 }
289 results = res;
290 goto cleanup;
291 }
292 free_cmd_results(res);
293 }
294 } else {
295 for (int i = 0; i < containers->length; ++i) {
296 config->handler_context.current_container = containers->items[i];
297 struct cmd_results *res = handler->handle(argc-1, argv+1);
298 if (res->status != CMD_SUCCESS) {
299 free_argv(argc, argv);
300 if (results) {
301 free_cmd_results(results);
302 }
303 results = res;
304 goto cleanup;
305 }
306 free_cmd_results(res);
247 } 307 }
248 results = res;
249 goto cleanup;
250 } 308 }
251 free_cmd_results(res);
252 free_argv(argc, argv); 309 free_argv(argc, argv);
253 } while(cmdlist); 310 } while(cmdlist);
254 } while(head); 311 } while(head);
diff --git a/sway/commands/input.c b/sway/commands/input.c
index 5ea39f62..fa9cf05a 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -11,8 +11,12 @@ struct cmd_results *cmd_input(int argc, char **argv) {
11 } 11 }
12 12
13 if (config->reading && strcmp("{", argv[1]) == 0) { 13 if (config->reading && strcmp("{", argv[1]) == 0) {
14 current_input_config = new_input_config(argv[0]); 14 free_input_config(config->handler_context.input_config);
15 wlr_log(L_DEBUG, "entering input block: %s", current_input_config->identifier); 15 config->handler_context.input_config = new_input_config(argv[0]);
16 if (!config->handler_context.input_config) {
17 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
18 }
19 wlr_log(L_DEBUG, "entering input block: %s", argv[0]);
16 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); 20 return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL);
17 } 21 }
18 22
@@ -20,15 +24,19 @@ struct cmd_results *cmd_input(int argc, char **argv) {
20 return error; 24 return error;
21 } 25 }
22 26
27 bool has_context = (config->handler_context.input_config != NULL);
28 if (!has_context) {
29 // caller did not give a context so create one just for this command
30 config->handler_context.input_config = new_input_config(argv[0]);
31 if (!config->handler_context.input_config) {
32 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
33 }
34 }
35
23 int argc_new = argc-2; 36 int argc_new = argc-2;
24 char **argv_new = argv+2; 37 char **argv_new = argv+2;
25 38
26 struct cmd_results *res; 39 struct cmd_results *res;
27 struct input_config *old_input_config = current_input_config;
28 current_input_config = new_input_config(argv[0]);
29 if (!current_input_config) {
30 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
31 }
32 if (strcasecmp("accel_profile", argv[1]) == 0) { 40 if (strcasecmp("accel_profile", argv[1]) == 0) {
33 res = input_cmd_accel_profile(argc_new, argv_new); 41 res = input_cmd_accel_profile(argc_new, argv_new);
34 } else if (strcasecmp("click_method", argv[1]) == 0) { 42 } else if (strcasecmp("click_method", argv[1]) == 0) {
@@ -64,7 +72,12 @@ struct cmd_results *cmd_input(int argc, char **argv) {
64 } else { 72 } else {
65 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]); 73 res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]);
66 } 74 }
67 free_input_config(current_input_config); 75
68 current_input_config = old_input_config; 76 if (!has_context) {
77 // clean up the context we created earlier
78 free_input_config(config->handler_context.input_config);
79 config->handler_context.input_config = NULL;
80 }
81
69 return res; 82 return res;
70} 83}
diff --git a/sway/commands/input/accel_profile.c b/sway/commands/input/accel_profile.c
index f72b7d48..37d6e133 100644
--- a/sway/commands/input/accel_profile.c
+++ b/sway/commands/input/accel_profile.c
@@ -9,6 +9,8 @@ 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 =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "accel_profile", 15 return cmd_results_new(CMD_FAILURE, "accel_profile",
14 "No input device defined."); 16 "No input device defined.");
diff --git a/sway/commands/input/click_method.c b/sway/commands/input/click_method.c
index 22eb15f7..8f1f0aa7 100644
--- a/sway/commands/input/click_method.c
+++ b/sway/commands/input/click_method.c
@@ -6,12 +6,12 @@
6#include "log.h" 6#include "log.h"
7 7
8struct cmd_results *input_cmd_click_method(int argc, char **argv) { 8struct cmd_results *input_cmd_click_method(int argc, char **argv) {
9 wlr_log(L_DEBUG, "click_method for device: %d %s",
10 current_input_config==NULL, current_input_config->identifier);
11 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
12 if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { 10 if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) {
13 return error; 11 return error;
14 } 12 }
13 struct input_config *current_input_config =
14 config->handler_context.input_config;
15 if (!current_input_config) { 15 if (!current_input_config) {
16 return cmd_results_new(CMD_FAILURE, "click_method", 16 return cmd_results_new(CMD_FAILURE, "click_method",
17 "No input device defined."); 17 "No input device defined.");
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c
index 1783978a..8273a7d4 100644
--- a/sway/commands/input/drag_lock.c
+++ b/sway/commands/input/drag_lock.c
@@ -9,6 +9,8 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
9 if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { 9 if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) {
10 return error; 10 return error;
11 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, 15 return cmd_results_new(CMD_FAILURE,
14 "drag_lock", "No input device defined."); 16 "drag_lock", "No input device defined.");
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c
index 8108a110..995a2f47 100644
--- a/sway/commands/input/dwt.c
+++ b/sway/commands/input/dwt.c
@@ -9,6 +9,8 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) {
9 if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { 9 if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) {
10 return error; 10 return error;
11 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); 15 return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined.");
14 } 16 }
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c
index a1bfbacd..2217f5ce 100644
--- a/sway/commands/input/events.c
+++ b/sway/commands/input/events.c
@@ -6,16 +6,18 @@
6#include "log.h" 6#include "log.h"
7 7
8struct cmd_results *input_cmd_events(int argc, char **argv) { 8struct cmd_results *input_cmd_events(int argc, char **argv) {
9 wlr_log(L_DEBUG, "events for device: %s",
10 current_input_config->identifier);
11 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
12 if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { 10 if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
13 return error; 11 return error;
14 } 12 }
13 struct input_config *current_input_config =
14 config->handler_context.input_config;
15 if (!current_input_config) { 15 if (!current_input_config) {
16 return cmd_results_new(CMD_FAILURE, "events", 16 return cmd_results_new(CMD_FAILURE, "events",
17 "No input device defined."); 17 "No input device defined.");
18 } 18 }
19 wlr_log(L_DEBUG, "events for device: %s",
20 current_input_config->identifier);
19 struct input_config *new_config = 21 struct input_config *new_config =
20 new_input_config(current_input_config->identifier); 22 new_input_config(current_input_config->identifier);
21 23
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c
index 35740df3..94b8e03e 100644
--- a/sway/commands/input/left_handed.c
+++ b/sway/commands/input/left_handed.c
@@ -9,6 +9,8 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) {
9 if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) { 9 if ((error = checkarg(argc, "left_handed", EXPECTED_AT_LEAST, 1))) {
10 return error; 10 return error;
11 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "left_handed", 15 return cmd_results_new(CMD_FAILURE, "left_handed",
14 "No input device defined."); 16 "No input device defined.");
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c
index 7bc08ae6..a551fd51 100644
--- a/sway/commands/input/middle_emulation.c
+++ b/sway/commands/input/middle_emulation.c
@@ -9,6 +9,8 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) {
9 if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { 9 if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) {
10 return error; 10 return error;
11 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "middle_emulation", 15 return cmd_results_new(CMD_FAILURE, "middle_emulation",
14 "No input device defined."); 16 "No input device defined.");
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c
index a7dcdc2c..c4e19b78 100644
--- a/sway/commands/input/natural_scroll.c
+++ b/sway/commands/input/natural_scroll.c
@@ -9,6 +9,8 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) {
9 if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { 9 if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) {
10 return error; 10 return error;
11 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "natural_scoll", 15 return cmd_results_new(CMD_FAILURE, "natural_scoll",
14 "No input device defined."); 16 "No input device defined.");
diff --git a/sway/commands/input/pointer_accel.c b/sway/commands/input/pointer_accel.c
index d2261a63..171063aa 100644
--- a/sway/commands/input/pointer_accel.c
+++ b/sway/commands/input/pointer_accel.c
@@ -9,6 +9,8 @@ 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 =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, 15 return cmd_results_new(CMD_FAILURE,
14 "pointer_accel", "No input device defined."); 16 "pointer_accel", "No input device defined.");
diff --git a/sway/commands/input/scroll_method.c b/sway/commands/input/scroll_method.c
index 035262cf..0a1c57ac 100644
--- a/sway/commands/input/scroll_method.c
+++ b/sway/commands/input/scroll_method.c
@@ -9,6 +9,8 @@ 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 =
13 config->handler_context.input_config;
12 if (!current_input_config) { 14 if (!current_input_config) {
13 return cmd_results_new(CMD_FAILURE, "scroll_method", 15 return cmd_results_new(CMD_FAILURE, "scroll_method",
14 "No input device defined."); 16 "No input device defined.");
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c
index ecab9a5b..e7f03058 100644
--- a/sway/commands/input/tap.c
+++ b/sway/commands/input/tap.c
@@ -6,11 +6,12 @@
6#include "log.h" 6#include "log.h"
7 7
8struct cmd_results *input_cmd_tap(int argc, char **argv) { 8struct cmd_results *input_cmd_tap(int argc, char **argv) {
9 wlr_log(L_DEBUG, "tap for device: %s", current_input_config->identifier);
10 struct cmd_results *error = NULL; 9 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { 10 if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) {
12 return error; 11 return error;
13 } 12 }
13 struct input_config *current_input_config =
14 config->handler_context.input_config;
14 if (!current_input_config) { 15 if (!current_input_config) {
15 return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); 16 return cmd_results_new(CMD_FAILURE, "tap", "No input device defined.");
16 } 17 }
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c
index 25db1a33..867e65d3 100644
--- a/sway/commands/input/xkb_layout.c
+++ b/sway/commands/input/xkb_layout.c
@@ -5,11 +5,12 @@
5#include "log.h" 5#include "log.h"
6 6
7struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) { 7struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) {
8 wlr_log(L_DEBUG, "xkb layout for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL; 8 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) { 9 if ((error = checkarg(argc, "xkb_layout", EXPECTED_EQUAL_TO, 1))) {
11 return error; 10 return error;
12 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
13 if (!current_input_config) { 14 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined."); 15 return cmd_results_new(CMD_FAILURE, "xkb_layout", "No input device defined.");
15 } 16 }
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c
index 819b796b..e8c8e04e 100644
--- a/sway/commands/input/xkb_model.c
+++ b/sway/commands/input/xkb_model.c
@@ -5,11 +5,12 @@
5#include "log.h" 5#include "log.h"
6 6
7struct cmd_results *input_cmd_xkb_model(int argc, char **argv) { 7struct cmd_results *input_cmd_xkb_model(int argc, char **argv) {
8 wlr_log(L_DEBUG, "xkb model for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL; 8 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) { 9 if ((error = checkarg(argc, "xkb_model", EXPECTED_EQUAL_TO, 1))) {
11 return error; 10 return error;
12 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
13 if (!current_input_config) { 14 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined."); 15 return cmd_results_new(CMD_FAILURE, "xkb_model", "No input device defined.");
15 } 16 }
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c
index ff5f83ec..e9ddd6e3 100644
--- a/sway/commands/input/xkb_options.c
+++ b/sway/commands/input/xkb_options.c
@@ -5,11 +5,12 @@
5#include "log.h" 5#include "log.h"
6 6
7struct cmd_results *input_cmd_xkb_options(int argc, char **argv) { 7struct cmd_results *input_cmd_xkb_options(int argc, char **argv) {
8 wlr_log(L_DEBUG, "xkb options for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL; 8 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) { 9 if ((error = checkarg(argc, "xkb_options", EXPECTED_EQUAL_TO, 1))) {
11 return error; 10 return error;
12 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
13 if (!current_input_config) { 14 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined."); 15 return cmd_results_new(CMD_FAILURE, "xkb_options", "No input device defined.");
15 } 16 }
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c
index aafe0003..926d0ac1 100644
--- a/sway/commands/input/xkb_rules.c
+++ b/sway/commands/input/xkb_rules.c
@@ -5,11 +5,12 @@
5#include "log.h" 5#include "log.h"
6 6
7struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) { 7struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) {
8 wlr_log(L_DEBUG, "xkb rules for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL; 8 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) { 9 if ((error = checkarg(argc, "xkb_rules", EXPECTED_EQUAL_TO, 1))) {
11 return error; 10 return error;
12 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
13 if (!current_input_config) { 14 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined."); 15 return cmd_results_new(CMD_FAILURE, "xkb_rules", "No input device defined.");
15 } 16 }
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c
index 89a61fdc..0e3ffd41 100644
--- a/sway/commands/input/xkb_variant.c
+++ b/sway/commands/input/xkb_variant.c
@@ -5,11 +5,12 @@
5#include "log.h" 5#include "log.h"
6 6
7struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) { 7struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) {
8 wlr_log(L_DEBUG, "xkb variant for device: %s", current_input_config->identifier);
9 struct cmd_results *error = NULL; 8 struct cmd_results *error = NULL;
10 if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) { 9 if ((error = checkarg(argc, "xkb_variant", EXPECTED_EQUAL_TO, 1))) {
11 return error; 10 return error;
12 } 11 }
12 struct input_config *current_input_config =
13 config->handler_context.input_config;
13 if (!current_input_config) { 14 if (!current_input_config) {
14 return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined."); 15 return cmd_results_new(CMD_FAILURE, "xkb_variant", "No input device defined.");
15 } 16 }
diff --git a/sway/commands/kill.c b/sway/commands/kill.c
new file mode 100644
index 00000000..3804f0b0
--- /dev/null
+++ b/sway/commands/kill.c
@@ -0,0 +1,28 @@
1#include <wlr/util/log.h>
2#include "log.h"
3#include "sway/input/input-manager.h"
4#include "sway/input/seat.h"
5#include "sway/view.h"
6#include "sway/commands.h"
7
8struct cmd_results *cmd_kill(int argc, char **argv) {
9 if (config->reading) {
10 return cmd_results_new(CMD_FAILURE, "kill",
11 "Command 'kill' cannot be used in the config file");
12 }
13 if (!sway_assert(config->handler_context.current_container,
14 "cmd_kill called without container context")) {
15 return cmd_results_new(CMD_INVALID, NULL,
16 "cmd_kill called without container context "
17 "(this is a bug in sway)");
18 }
19 // TODO close arbitrary containers without a view
20 struct sway_view *view =
21 config->handler_context.current_container->sway_view;
22
23 if (view) {
24 view_close(view);
25 }
26
27 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
28}
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
index 6284002b..45079616 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -11,8 +11,12 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
11 } 11 }
12 12
13 if (config->reading && strcmp("{", argv[1]) == 0) { 13 if (config->reading && strcmp("{", argv[1]) == 0) {
14 current_seat_config = new_seat_config(argv[0]); 14 free_seat_config(config->handler_context.seat_config);
15 wlr_log(L_DEBUG, "entering seat block: %s", current_seat_config->name); 15 config->handler_context.seat_config = new_seat_config(argv[0]);
16 if (!config->handler_context.seat_config) {
17 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
18 }
19 wlr_log(L_DEBUG, "entering seat block: %s", argv[0]);
16 return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL); 20 return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL);
17 } 21 }
18 22
@@ -20,11 +24,18 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
20 return error; 24 return error;
21 } 25 }
22 26
27 bool has_context = (config->handler_context.seat_config != NULL);
28 if (!has_context) {
29 config->handler_context.seat_config = new_seat_config(argv[0]);
30 if (!config->handler_context.seat_config) {
31 return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config");
32 }
33 }
34
23 int argc_new = argc-2; 35 int argc_new = argc-2;
24 char **argv_new = argv+2; 36 char **argv_new = argv+2;
25 37
26 struct cmd_results *res; 38 struct cmd_results *res;
27 current_seat_config = new_seat_config(argv[0]);
28 if (strcasecmp("attach", argv[1]) == 0) { 39 if (strcasecmp("attach", argv[1]) == 0) {
29 res = seat_cmd_attach(argc_new, argv_new); 40 res = seat_cmd_attach(argc_new, argv_new);
30 } else if (strcasecmp("fallback", argv[1]) == 0) { 41 } else if (strcasecmp("fallback", argv[1]) == 0) {
@@ -32,6 +43,12 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
32 } else { 43 } else {
33 res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]); 44 res = cmd_results_new(CMD_INVALID, "seat <name>", "Unknown command %s", argv[1]);
34 } 45 }
35 current_seat_config = NULL; 46
47 if (!has_context) {
48 // clean up the context we created earlier
49 free_seat_config(config->handler_context.seat_config);
50 config->handler_context.seat_config = NULL;
51 }
52
36 return res; 53 return res;
37} 54}
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c
index 80ec63ce..3e771c00 100644
--- a/sway/commands/seat/attach.c
+++ b/sway/commands/seat/attach.c
@@ -12,6 +12,8 @@ struct cmd_results *seat_cmd_attach(int argc, char **argv) {
12 if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) { 12 if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) {
13 return error; 13 return error;
14 } 14 }
15 struct seat_config *current_seat_config =
16 config->handler_context.seat_config;
15 if (!current_seat_config) { 17 if (!current_seat_config) {
16 return cmd_results_new(CMD_FAILURE, "attach", "No seat defined"); 18 return cmd_results_new(CMD_FAILURE, "attach", "No seat defined");
17 } 19 }
diff --git a/sway/commands/seat/fallback.c b/sway/commands/seat/fallback.c
index 7c129aae..56feaab5 100644
--- a/sway/commands/seat/fallback.c
+++ b/sway/commands/seat/fallback.c
@@ -9,6 +9,8 @@ struct cmd_results *seat_cmd_fallback(int argc, char **argv) {
9 if ((error = checkarg(argc, "fallback", EXPECTED_AT_LEAST, 1))) { 9 if ((error = checkarg(argc, "fallback", EXPECTED_AT_LEAST, 1))) {
10 return error; 10 return error;
11 } 11 }
12 struct seat_config *current_seat_config =
13 config->handler_context.seat_config;
12 if (!current_seat_config) { 14 if (!current_seat_config) {
13 return cmd_results_new(CMD_FAILURE, "fallback", "No seat defined"); 15 return cmd_results_new(CMD_FAILURE, "fallback", "No seat defined");
14 } 16 }
@@ -20,6 +22,7 @@ struct cmd_results *seat_cmd_fallback(int argc, char **argv) {
20 } else if (strcasecmp(argv[0], "false") == 0) { 22 } else if (strcasecmp(argv[0], "false") == 0) {
21 new_config->fallback = 0; 23 new_config->fallback = 0;
22 } else { 24 } else {
25 free_seat_config(new_config);
23 return cmd_results_new(CMD_INVALID, "fallback", 26 return cmd_results_new(CMD_INVALID, "fallback",
24 "Expected 'fallback <true|false>'"); 27 "Expected 'fallback <true|false>'");
25 } 28 }
diff --git a/sway/config.c b/sway/config.c
index cbd9a8b2..1fd123b7 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -54,6 +54,8 @@ static void free_mode(struct sway_mode *mode) {
54} 54}
55 55
56void free_config(struct sway_config *config) { 56void free_config(struct sway_config *config) {
57 config_clear_handler_context(config);
58
57 int i; 59 int i;
58 60
59 if (!config) { 61 if (!config) {
@@ -485,6 +487,12 @@ bool load_include_configs(const char *path, struct sway_config *config) {
485 return true; 487 return true;
486} 488}
487 489
490void config_clear_handler_context(struct sway_config *config) {
491 free_input_config(config->handler_context.input_config);
492 free_seat_config(config->handler_context.seat_config);
493
494 memset(&config->handler_context, 0, sizeof(config->handler_context));
495}
488 496
489bool read_config(FILE *file, struct sway_config *config) { 497bool read_config(FILE *file, struct sway_config *config) {
490 bool success = true; 498 bool success = true;
@@ -597,14 +605,11 @@ bool read_config(FILE *file, struct sway_config *config) {
597 605
598 case CMD_BLOCK_INPUT: 606 case CMD_BLOCK_INPUT:
599 wlr_log(L_DEBUG, "End of input block"); 607 wlr_log(L_DEBUG, "End of input block");
600 free_input_config(current_input_config);
601 current_input_config = NULL;
602 block = CMD_BLOCK_END; 608 block = CMD_BLOCK_END;
603 break; 609 break;
604 610
605 case CMD_BLOCK_SEAT: 611 case CMD_BLOCK_SEAT:
606 wlr_log(L_DEBUG, "End of seat block"); 612 wlr_log(L_DEBUG, "End of seat block");
607 current_seat_config = NULL;
608 block = CMD_BLOCK_END; 613 block = CMD_BLOCK_END;
609 break; 614 break;
610 615
@@ -640,6 +645,7 @@ bool read_config(FILE *file, struct sway_config *config) {
640 645
641 default:; 646 default:;
642 } 647 }
648 config_clear_handler_context(config);
643 default:; 649 default:;
644 } 650 }
645 free(line); 651 free(line);
diff --git a/sway/criteria.c b/sway/criteria.c
new file mode 100644
index 00000000..2eee331c
--- /dev/null
+++ b/sway/criteria.c
@@ -0,0 +1,445 @@
1#define _XOPEN_SOURCE 700
2#include <stdlib.h>
3#include <stdio.h>
4#include <stdbool.h>
5#include <pcre.h>
6#include "sway/criteria.h"
7#include "sway/container.h"
8#include "sway/config.h"
9#include "sway/view.h"
10#include "stringop.h"
11#include "list.h"
12#include "log.h"
13
14enum criteria_type { // *must* keep in sync with criteria_strings[]
15 CRIT_APP_ID,
16 CRIT_CLASS,
17 CRIT_CON_ID,
18 CRIT_CON_MARK,
19 CRIT_FLOATING,
20 CRIT_ID,
21 CRIT_INSTANCE,
22 CRIT_TILING,
23 CRIT_TITLE,
24 CRIT_URGENT,
25 CRIT_WINDOW_ROLE,
26 CRIT_WINDOW_TYPE,
27 CRIT_WORKSPACE,
28 CRIT_LAST
29};
30
31static const char * const criteria_strings[CRIT_LAST] = {
32 [CRIT_APP_ID] = "app_id",
33 [CRIT_CLASS] = "class",
34 [CRIT_CON_ID] = "con_id",
35 [CRIT_CON_MARK] = "con_mark",
36 [CRIT_FLOATING] = "floating",
37 [CRIT_ID] = "id",
38 [CRIT_INSTANCE] = "instance",
39 [CRIT_TILING] = "tiling",
40 [CRIT_TITLE] = "title",
41 [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ...
42 [CRIT_WINDOW_ROLE] = "window_role",
43 [CRIT_WINDOW_TYPE] = "window_type",
44 [CRIT_WORKSPACE] = "workspace"
45};
46
47/**
48 * A single criteria token (ie. value/regex pair),
49 * e.g. 'class="some class regex"'.
50 */
51struct crit_token {
52 enum criteria_type type;
53 pcre *regex;
54 char *raw;
55};
56
57static void free_crit_token(struct crit_token *crit) {
58 pcre_free(crit->regex);
59 free(crit->raw);
60 free(crit);
61}
62
63static void free_crit_tokens(list_t *crit_tokens) {
64 for (int i = 0; i < crit_tokens->length; i++) {
65 free_crit_token(crit_tokens->items[i]);
66 }
67 list_free(crit_tokens);
68}
69
70// Extracts criteria string from its brackets. Returns new (duplicate)
71// substring.
72static char *criteria_from(const char *arg) {
73 char *criteria = NULL;
74 if (*arg == '[') {
75 criteria = strdup(arg + 1);
76 } else {
77 criteria = strdup(arg);
78 }
79
80 int last = strlen(criteria) - 1;
81 if (criteria[last] == ']') {
82 criteria[last] = '\0';
83 }
84 return criteria;
85}
86
87// Return instances of c found in str.
88static int countchr(char *str, char c) {
89 int found = 0;
90 for (int i = 0; str[i]; i++) {
91 if (str[i] == c) {
92 ++found;
93 }
94 }
95 return found;
96}
97
98// criteria_str is e.g. '[class="some class regex" instance="instance name"]'.
99//
100// Will create array of pointers in buf, where first is duplicate of given
101// string (must be freed) and the rest are pointers to names and values in the
102// base string (every other, naturally). argc will be populated with the length
103// of buf.
104//
105// Returns error string or NULL if successful.
106static char *crit_tokens(int *argc, char ***buf,
107 const char * const criteria_str) {
108 wlr_log(L_DEBUG, "Parsing criteria: '%s'", criteria_str);
109 char *base = criteria_from(criteria_str);
110 char *head = base;
111 char *namep = head; // start of criteria name
112 char *valp = NULL; // start of value
113
114 // We're going to place EOS markers where we need to and fill up an array
115 // of pointers to the start of each token (either name or value).
116 int pairs = countchr(base, '=');
117 int max_tokens = pairs * 2 + 1; // this gives us at least enough slots
118
119 char **argv = *buf = calloc(max_tokens, sizeof(char*));
120 argv[0] = base; // this needs to be freed by caller
121 bool quoted = true;
122
123 *argc = 1; // uneven = name, even = value
124 while (*head && *argc < max_tokens) {
125 if (namep != head && *(head - 1) == '\\') {
126 // escaped character: don't try to parse this
127 } else if (*head == '=' && namep != head) {
128 if (*argc % 2 != 1) {
129 // we're not expecting a name
130 return strdup("Unable to parse criteria: "
131 "Found out of place equal sign");
132 } else {
133 // name ends here
134 char *end = head; // don't want to rewind the head
135 while (*(end - 1) == ' ') {
136 --end;
137 }
138 *end = '\0';
139 if (*(namep) == ' ') {
140 namep = strrchr(namep, ' ') + 1;
141 }
142 argv[*argc] = namep;
143 *argc += 1;
144 }
145 } else if (*head == '"') {
146 if (*argc % 2 != 0) {
147 // we're not expecting a value
148 return strdup("Unable to parse criteria: "
149 "Found quoted value where it was not expected");
150 } else if (!valp) { // value starts here
151 valp = head + 1;
152 quoted = true;
153 } else {
154 // value ends here
155 argv[*argc] = valp;
156 *argc += 1;
157 *head = '\0';
158 valp = NULL;
159 namep = head + 1;
160 }
161 } else if (*argc % 2 == 0 && *head != ' ') {
162 // parse unquoted values
163 if (!valp) {
164 quoted = false;
165 valp = head; // value starts here
166 }
167 } else if (valp && !quoted && *head == ' ') {
168 // value ends here
169 argv[*argc] = valp;
170 *argc += 1;
171 *head = '\0';
172 valp = NULL;
173 namep = head + 1;
174 }
175 head++;
176 }
177
178 // catch last unquoted value if needed
179 if (valp && !quoted && !*head) {
180 argv[*argc] = valp;
181 *argc += 1;
182 }
183
184 return NULL;
185}
186
187// Returns error string on failure or NULL otherwise.
188static char *parse_criteria_name(enum criteria_type *type, char *name) {
189 *type = CRIT_LAST;
190 for (int i = 0; i < CRIT_LAST; i++) {
191 if (strcmp(criteria_strings[i], name) == 0) {
192 *type = (enum criteria_type) i;
193 break;
194 }
195 }
196 if (*type == CRIT_LAST) {
197 const char *fmt = "Criteria type '%s' is invalid or unsupported.";
198 int len = strlen(name) + strlen(fmt) - 1;
199 char *error = malloc(len);
200 snprintf(error, len, fmt, name);
201 return error;
202 } else if (*type == CRIT_URGENT || *type == CRIT_WINDOW_ROLE ||
203 *type == CRIT_WINDOW_TYPE) {
204 // (we're just being helpful here)
205 const char *fmt = "\"%s\" criteria currently unsupported, "
206 "no window will match this";
207 int len = strlen(fmt) + strlen(name) - 1;
208 char *error = malloc(len);
209 snprintf(error, len, fmt, name);
210 return error;
211 }
212 return NULL;
213}
214
215// Returns error string on failure or NULL otherwise.
216static char *generate_regex(pcre **regex, char *value) {
217 const char *reg_err;
218 int offset;
219
220 *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, &reg_err, &offset, NULL);
221
222 if (!*regex) {
223 const char *fmt = "Regex compilation (for '%s') failed: %s";
224 int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3;
225 char *error = malloc(len);
226 snprintf(error, len, fmt, value, reg_err);
227 return error;
228 }
229 return NULL;
230}
231
232// Test whether the criterion corresponds to the currently focused window
233static bool crit_is_focused(const char *value) {
234 return !strcmp(value, "focused") || !strcmp(value, "__focused__");
235}
236
237// Populate list with crit_tokens extracted from criteria string, returns error
238// string or NULL if successful.
239char *extract_crit_tokens(list_t *tokens, const char * const criteria) {
240 int argc;
241 char **argv = NULL, *error = NULL;
242 if ((error = crit_tokens(&argc, &argv, criteria))) {
243 goto ect_cleanup;
244 }
245 for (int i = 1; i + 1 < argc; i += 2) {
246 char* name = argv[i], *value = argv[i + 1];
247 struct crit_token *token = calloc(1, sizeof(struct crit_token));
248 token->raw = strdup(value);
249
250 if ((error = parse_criteria_name(&token->type, name))) {
251 free_crit_token(token);
252 goto ect_cleanup;
253 } else if (token->type == CRIT_URGENT || crit_is_focused(value)) {
254 wlr_log(L_DEBUG, "%s -> \"%s\"", name, value);
255 list_add(tokens, token);
256 } else if((error = generate_regex(&token->regex, value))) {
257 free_crit_token(token);
258 goto ect_cleanup;
259 } else {
260 wlr_log(L_DEBUG, "%s -> /%s/", name, value);
261 list_add(tokens, token);
262 }
263 }
264ect_cleanup:
265 free(argv[0]); // base string
266 free(argv);
267 return error;
268}
269
270static int regex_cmp(const char *item, const pcre *regex) {
271 return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
272}
273
274// test a single view if it matches list of criteria tokens (all of them).
275static bool criteria_test(swayc_t *cont, list_t *tokens) {
276 if (cont->type != C_VIEW) {
277 return false;
278 }
279 int matches = 0;
280 for (int i = 0; i < tokens->length; i++) {
281 struct crit_token *crit = tokens->items[i];
282 switch (crit->type) {
283 case CRIT_CLASS:
284 {
285 const char *class = view_get_class(cont->sway_view);
286 if (!class) {
287 break;
288 }
289 if (crit->regex && regex_cmp(class, crit->regex) == 0) {
290 matches++;
291 }
292 break;
293 }
294 case CRIT_CON_ID:
295 {
296 char *endptr;
297 size_t crit_id = strtoul(crit->raw, &endptr, 10);
298
299 if (*endptr == 0 && cont->id == crit_id) {
300 ++matches;
301 }
302 break;
303 }
304 case CRIT_CON_MARK:
305 // TODO
306 break;
307 case CRIT_FLOATING:
308 // TODO
309 break;
310 case CRIT_ID:
311 // TODO
312 break;
313 case CRIT_APP_ID:
314 {
315 const char *app_id = view_get_app_id(cont->sway_view);
316 if (!app_id) {
317 break;
318 }
319
320 if (crit->regex && regex_cmp(app_id, crit->regex) == 0) {
321 matches++;
322 }
323 break;
324 }
325 case CRIT_INSTANCE:
326 {
327 const char *instance = view_get_instance(cont->sway_view);
328 if (!instance) {
329 break;
330 }
331
332 if (crit->regex && regex_cmp(instance, crit->regex) == 0) {
333 matches++;
334 }
335 break;
336 }
337 case CRIT_TILING:
338 // TODO
339 break;
340 case CRIT_TITLE:
341 {
342 const char *title = view_get_title(cont->sway_view);
343 if (!title) {
344 break;
345 }
346
347 if (crit->regex && regex_cmp(title, crit->regex) == 0) {
348 matches++;
349 }
350 break;
351 }
352 case CRIT_URGENT:
353 // TODO "latest" or "oldest"
354 break;
355 case CRIT_WINDOW_ROLE:
356 // TODO
357 break;
358 case CRIT_WINDOW_TYPE:
359 // TODO
360 break;
361 case CRIT_WORKSPACE:
362 // TODO
363 break;
364 default:
365 sway_abort("Invalid criteria type (%i)", crit->type);
366 break;
367 }
368 }
369 return matches == tokens->length;
370}
371
372int criteria_cmp(const void *a, const void *b) {
373 if (a == b) {
374 return 0;
375 } else if (!a) {
376 return -1;
377 } else if (!b) {
378 return 1;
379 }
380 const struct criteria *crit_a = a, *crit_b = b;
381 int cmp = lenient_strcmp(crit_a->cmdlist, crit_b->cmdlist);
382 if (cmp != 0) {
383 return cmp;
384 }
385 return lenient_strcmp(crit_a->crit_raw, crit_b->crit_raw);
386}
387
388void free_criteria(struct criteria *crit) {
389 if (crit->tokens) {
390 free_crit_tokens(crit->tokens);
391 }
392 if (crit->cmdlist) {
393 free(crit->cmdlist);
394 }
395 if (crit->crit_raw) {
396 free(crit->crit_raw);
397 }
398 free(crit);
399}
400
401bool criteria_any(swayc_t *cont, list_t *criteria) {
402 for (int i = 0; i < criteria->length; i++) {
403 struct criteria *bc = criteria->items[i];
404 if (criteria_test(cont, bc->tokens)) {
405 return true;
406 }
407 }
408 return false;
409}
410
411list_t *criteria_for(swayc_t *cont) {
412 list_t *criteria = config->criteria, *matches = create_list();
413 for (int i = 0; i < criteria->length; i++) {
414 struct criteria *bc = criteria->items[i];
415 if (criteria_test(cont, bc->tokens)) {
416 list_add(matches, bc);
417 }
418 }
419 return matches;
420}
421
422struct list_tokens {
423 list_t *list;
424 list_t *tokens;
425};
426
427static void container_match_add(swayc_t *container,
428 struct list_tokens *list_tokens) {
429 if (criteria_test(container, list_tokens->tokens)) {
430 list_add(list_tokens->list, container);
431 }
432}
433
434list_t *container_for_crit_tokens(list_t *tokens) {
435 struct list_tokens list_tokens =
436 (struct list_tokens){create_list(), tokens};
437
438 container_map(&root_container,
439 (void (*)(swayc_t *, void *))container_match_add,
440 &list_tokens);
441
442 // TODO look in the scratchpad
443
444 return list_tokens.list;
445}
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index e34f5160..0cde6583 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -51,6 +51,14 @@ static void set_activated(struct sway_view *view, bool activated) {
51 // no way to activate wl_shell 51 // no way to activate wl_shell
52} 52}
53 53
54static void close(struct sway_view *view) {
55 if (!assert_wl_shell(view)) {
56 return;
57 }
58
59 wl_client_destroy(view->wlr_wl_shell_surface->client);
60}
61
54static void handle_commit(struct wl_listener *listener, void *data) { 62static void handle_commit(struct wl_listener *listener, void *data) {
55 struct sway_wl_shell_surface *sway_surface = 63 struct sway_wl_shell_surface *sway_surface =
56 wl_container_of(listener, sway_surface, commit); 64 wl_container_of(listener, sway_surface, commit);
@@ -103,6 +111,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) {
103 sway_view->iface.set_size = set_size; 111 sway_view->iface.set_size = set_size;
104 sway_view->iface.set_position = set_position; 112 sway_view->iface.set_position = set_position;
105 sway_view->iface.set_activated = set_activated; 113 sway_view->iface.set_activated = set_activated;
114 sway_view->iface.close = close;
106 sway_view->wlr_wl_shell_surface = shell_surface; 115 sway_view->wlr_wl_shell_surface = shell_surface;
107 sway_view->sway_wl_shell_surface = sway_surface; 116 sway_view->sway_wl_shell_surface = sway_surface;
108 sway_view->surface = shell_surface->surface; 117 sway_view->surface = shell_surface->surface;
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index df48345c..4b50093f 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -57,6 +57,16 @@ static void set_activated(struct sway_view *view, bool activated) {
57 } 57 }
58} 58}
59 59
60static void close(struct sway_view *view) {
61 if (!assert_xdg(view)) {
62 return;
63 }
64 struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6;
65 if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) {
66 wlr_xdg_toplevel_v6_send_close(surface);
67 }
68}
69
60static void handle_commit(struct wl_listener *listener, void *data) { 70static void handle_commit(struct wl_listener *listener, void *data) {
61 struct sway_xdg_surface_v6 *sway_surface = 71 struct sway_xdg_surface_v6 *sway_surface =
62 wl_container_of(listener, sway_surface, commit); 72 wl_container_of(listener, sway_surface, commit);
@@ -107,6 +117,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
107 sway_view->iface.set_size = set_size; 117 sway_view->iface.set_size = set_size;
108 sway_view->iface.set_position = set_position; 118 sway_view->iface.set_position = set_position;
109 sway_view->iface.set_activated = set_activated; 119 sway_view->iface.set_activated = set_activated;
120 sway_view->iface.close = close;
110 sway_view->wlr_xdg_surface_v6 = xdg_surface; 121 sway_view->wlr_xdg_surface_v6 = xdg_surface;
111 sway_view->sway_xdg_surface_v6 = sway_surface; 122 sway_view->sway_xdg_surface_v6 = sway_surface;
112 sway_view->surface = xdg_surface->surface; 123 sway_view->surface = xdg_surface->surface;
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index a4d9687d..7603d3ca 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -80,6 +80,13 @@ static void set_activated(struct sway_view *view, bool activated) {
80 wlr_xwayland_surface_activate(surface, activated); 80 wlr_xwayland_surface_activate(surface, activated);
81} 81}
82 82
83static void close(struct sway_view *view) {
84 if (!assert_xwayland(view)) {
85 return;
86 }
87 wlr_xwayland_surface_close(view->wlr_xwayland_surface);
88}
89
83static void handle_commit(struct wl_listener *listener, void *data) { 90static void handle_commit(struct wl_listener *listener, void *data) {
84 struct sway_xwayland_surface *sway_surface = 91 struct sway_xwayland_surface *sway_surface =
85 wl_container_of(listener, sway_surface, commit); 92 wl_container_of(listener, sway_surface, commit);
@@ -192,6 +199,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
192 sway_view->iface.set_size = set_size; 199 sway_view->iface.set_size = set_size;
193 sway_view->iface.set_position = set_position; 200 sway_view->iface.set_position = set_position;
194 sway_view->iface.set_activated = set_activated; 201 sway_view->iface.set_activated = set_activated;
202 sway_view->iface.close = close;
195 sway_view->wlr_xwayland_surface = xsurface; 203 sway_view->wlr_xwayland_surface = xsurface;
196 sway_view->sway_xwayland_surface = sway_surface; 204 sway_view->sway_xwayland_surface = sway_surface;
197 sway_view->surface = xsurface->surface; 205 sway_view->surface = xsurface->surface;
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index bfe9d9c4..2d119cf2 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -372,3 +372,14 @@ void sway_input_manager_configure_xcursor(struct sway_input_manager *input) {
372 sway_seat_configure_xcursor(seat); 372 sway_seat_configure_xcursor(seat);
373 } 373 }
374} 374}
375
376struct sway_seat *sway_input_manager_get_default_seat(
377 struct sway_input_manager *input) {
378 struct sway_seat *seat = NULL;
379 wl_list_for_each(seat, &input->seats, link) {
380 if (strcmp(seat->wlr_seat->name, "seat0") == 0) {
381 return seat;
382 }
383 }
384 return seat;
385}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 5827a1ca..6dc57d46 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -89,9 +89,12 @@ static bool binding_matches_key_state(struct sway_binding *binding,
89 return false; 89 return false;
90} 90}
91 91
92static void binding_execute_command(struct sway_binding *binding) { 92static void keyboard_execute_command(struct sway_keyboard *keyboard,
93 struct sway_binding *binding) {
93 wlr_log(L_DEBUG, "running command for binding: %s", 94 wlr_log(L_DEBUG, "running command for binding: %s",
94 binding->command); 95 binding->command);
96 config_clear_handler_context(config);
97 config->handler_context.seat = keyboard->seat_device->sway_seat;
95 struct cmd_results *results = handle_command(binding->command); 98 struct cmd_results *results = handle_command(binding->command);
96 if (results->status != CMD_SUCCESS) { 99 if (results->status != CMD_SUCCESS) {
97 wlr_log(L_DEBUG, "could not run command for binding: %s", 100 wlr_log(L_DEBUG, "could not run command for binding: %s",
@@ -160,7 +163,7 @@ static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard,
160 } 163 }
161 164
162 if (match) { 165 if (match) {
163 binding_execute_command(binding); 166 keyboard_execute_command(keyboard, binding);
164 return true; 167 return true;
165 } 168 }
166 } 169 }
@@ -267,7 +270,7 @@ static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard,
267 for (int i = 0; i < keycode_bindings->length; ++i) { 270 for (int i = 0; i < keycode_bindings->length; ++i) {
268 struct sway_binding *binding = keycode_bindings->items[i]; 271 struct sway_binding *binding = keycode_bindings->items[i];
269 if (binding_matches_keycodes(wlr_keyboard, binding, event)) { 272 if (binding_matches_keycodes(wlr_keyboard, binding, event)) {
270 binding_execute_command(binding); 273 keyboard_execute_command(keyboard, binding);
271 return true; 274 return true;
272 } 275 }
273 } 276 }
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 22fee3c3..e9b375e0 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -214,7 +214,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
214 214
215 if (container) { 215 if (container) {
216 struct sway_view *view = container->sway_view; 216 struct sway_view *view = container->sway_view;
217 view->iface.set_activated(view, true); 217 view_set_activated(view, true);
218 wl_signal_add(&container->events.destroy, &seat->focus_destroy); 218 wl_signal_add(&container->events.destroy, &seat->focus_destroy);
219 seat->focus_destroy.notify = handle_focus_destroy; 219 seat->focus_destroy.notify = handle_focus_destroy;
220 220
@@ -234,8 +234,7 @@ void sway_seat_set_focus(struct sway_seat *seat, swayc_t *container) {
234 if (last_focus && 234 if (last_focus &&
235 !sway_input_manager_has_focus(seat->input, last_focus)) { 235 !sway_input_manager_has_focus(seat->input, last_focus)) {
236 struct sway_view *view = last_focus->sway_view; 236 struct sway_view *view = last_focus->sway_view;
237 view->iface.set_activated(view, false); 237 view_set_activated(view, false);
238
239 } 238 }
240} 239}
241 240
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index d2dd881f..a16a2b80 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -335,6 +335,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
335 switch (client->current_command) { 335 switch (client->current_command) {
336 case IPC_COMMAND: 336 case IPC_COMMAND:
337 { 337 {
338 config_clear_handler_context(config);
338 struct cmd_results *results = handle_command(buf); 339 struct cmd_results *results = handle_command(buf);
339 const char *json = cmd_results_to_json(results); 340 const char *json = cmd_results_to_json(results);
340 char reply[256]; 341 char reply[256];
diff --git a/sway/meson.build b/sway/meson.build
index 30ec166b..80ccc01d 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -10,6 +10,7 @@ sway_sources = files(
10 'commands/exit.c', 10 'commands/exit.c',
11 'commands/exec.c', 11 'commands/exec.c',
12 'commands/exec_always.c', 12 'commands/exec_always.c',
13 'commands/kill.c',
13 'commands/include.c', 14 'commands/include.c',
14 'commands/input.c', 15 'commands/input.c',
15 'commands/seat.c', 16 'commands/seat.c',
@@ -37,6 +38,7 @@ sway_sources = files(
37 'config/output.c', 38 'config/output.c',
38 'config/seat.c', 39 'config/seat.c',
39 'config/input.c', 40 'config/input.c',
41 'criteria.c',
40 'ipc-json.c', 42 'ipc-json.c',
41 'ipc-server.c', 43 'ipc-server.c',
42 'desktop/output.c', 44 'desktop/output.c',
@@ -46,10 +48,12 @@ sway_sources = files(
46 'security.c', 48 'security.c',
47 'tree/container.c', 49 'tree/container.c',
48 'tree/layout.c', 50 'tree/layout.c',
51 'tree/view.c',
49 'tree/workspace.c', 52 'tree/workspace.c',
50) 53)
51 54
52sway_deps = [ 55sway_deps = [
56 pcre,
53 pixman, 57 pixman,
54 wayland_server, 58 wayland_server,
55 jsonc, 59 jsonc,
diff --git a/sway/tree/container.c b/sway/tree/container.c
index d241f69a..b7b9bc68 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -157,7 +157,7 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) {
157 if (!sway_assert(sibling, "new_view called with NULL sibling/parent")) { 157 if (!sway_assert(sibling, "new_view called with NULL sibling/parent")) {
158 return NULL; 158 return NULL;
159 } 159 }
160 const char *title = sway_view->iface.get_prop(sway_view, VIEW_PROP_TITLE); 160 const char *title = view_get_title(sway_view);
161 swayc_t *swayc = new_swayc(C_VIEW); 161 swayc_t *swayc = new_swayc(C_VIEW);
162 wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d", 162 wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d",
163 swayc, title, sibling, sibling ? sibling->type : 0); 163 swayc, title, sibling, sibling ? sibling->type : 0);
@@ -321,3 +321,25 @@ swayc_t *swayc_at(swayc_t *parent, double lx, double ly,
321 321
322 return NULL; 322 return NULL;
323} 323}
324
325void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
326 if (container) {
327 int i;
328 if (container->children) {
329 for (i = 0; i < container->children->length; ++i) {
330 swayc_t *child = container->children->items[i];
331 container_map(child, f, data);
332 }
333 }
334 // TODO
335 /*
336 if (container->floating) {
337 for (i = 0; i < container->floating->length; ++i) {
338 swayc_t *child = container->floating->items[i];
339 container_map(child, f, data);
340 }
341 }
342 */
343 f(container, data);
344 }
345}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 01535f2d..41ff81b2 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -191,8 +191,8 @@ void arrange_windows(swayc_t *container, double width, double height) {
191 { 191 {
192 container->width = width; 192 container->width = width;
193 container->height = height; 193 container->height = height;
194 container->sway_view->iface.set_size(container->sway_view, 194 view_set_size(container->sway_view,
195 container->width, container->height); 195 container->width, container->height);
196 wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f", 196 wlr_log(L_DEBUG, "Set view to %.f x %.f @ %.f, %.f",
197 container->width, container->height, 197 container->width, container->height,
198 container->x, container->y); 198 container->x, container->y);
@@ -251,7 +251,7 @@ static void apply_horiz_layout(swayc_t *container,
251 wlr_log(L_DEBUG, 251 wlr_log(L_DEBUG,
252 "Calculating arrangement for %p:%d (will scale %f by %f)", 252 "Calculating arrangement for %p:%d (will scale %f by %f)",
253 child, child->type, width, scale); 253 child, child->type, width, scale);
254 child->sway_view->iface.set_position(child->sway_view, child_x, y); 254 view_set_position(child->sway_view, child_x, y);
255 255
256 if (i == end - 1) { 256 if (i == end - 1) {
257 double remaining_width = x + width - child_x; 257 double remaining_width = x + width - child_x;
@@ -301,7 +301,7 @@ void apply_vert_layout(swayc_t *container,
301 wlr_log(L_DEBUG, 301 wlr_log(L_DEBUG,
302 "Calculating arrangement for %p:%d (will scale %f by %f)", 302 "Calculating arrangement for %p:%d (will scale %f by %f)",
303 child, child->type, height, scale); 303 child, child->type, height, scale);
304 child->sway_view->iface.set_position(child->sway_view, x, child_y); 304 view_set_position(child->sway_view, x, child_y);
305 305
306 if (i == end - 1) { 306 if (i == end - 1) {
307 double remaining_height = y + height - child_y; 307 double remaining_height = y + height - child_y;
diff --git a/sway/tree/view.c b/sway/tree/view.c
new file mode 100644
index 00000000..b46c3b17
--- /dev/null
+++ b/sway/tree/view.c
@@ -0,0 +1,53 @@
1#include "sway/view.h"
2
3const char *view_get_title(struct sway_view *view) {
4 if (view->iface.get_prop) {
5 return view->iface.get_prop(view, VIEW_PROP_TITLE);
6 }
7 return NULL;
8}
9
10const char *view_get_app_id(struct sway_view *view) {
11 if (view->iface.get_prop) {
12 return view->iface.get_prop(view, VIEW_PROP_APP_ID);
13 }
14 return NULL;
15}
16
17const char *view_get_class(struct sway_view *view) {
18 if (view->iface.get_prop) {
19 return view->iface.get_prop(view, VIEW_PROP_CLASS);
20 }
21 return NULL;
22}
23
24const char *view_get_instance(struct sway_view *view) {
25 if (view->iface.get_prop) {
26 return view->iface.get_prop(view, VIEW_PROP_INSTANCE);
27 }
28 return NULL;
29}
30
31void view_set_size(struct sway_view *view, int width, int height) {
32 if (view->iface.set_size) {
33 view->iface.set_size(view, width, height);
34 }
35}
36
37void view_set_position(struct sway_view *view, double ox, double oy) {
38 if (view->iface.set_position) {
39 view->iface.set_position(view, ox, oy);
40 }
41}
42
43void view_set_activated(struct sway_view *view, bool activated) {
44 if (view->iface.set_activated) {
45 view->iface.set_activated(view, activated);
46 }
47}
48
49void view_close(struct sway_view *view) {
50 if (view->iface.close) {
51 view->iface.close(view);
52 }
53}