diff options
author | emersion <contact@emersion.fr> | 2018-01-22 01:16:23 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-22 01:16:23 +0100 |
commit | 0c58673c6a108ba241419a0f1d5fecd47f22370e (patch) | |
tree | c3e19af6dd70f04fc5c617e932b4afcc7a1b41d9 | |
parent | Remove sway/old/ (diff) | |
parent | dont allow kill command in config (diff) | |
download | sway-0c58673c6a108ba241419a0f1d5fecd47f22370e.tar.gz sway-0c58673c6a108ba241419a0f1d5fecd47f22370e.tar.zst sway-0c58673c6a108ba241419a0f1d5fecd47f22370e.zip |
Merge pull request #1574 from acrisci/config-refactor
Command criteria
40 files changed, 840 insertions, 52 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index 967d3756..48a8b0ab 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -350,6 +350,14 @@ struct sway_config { | |||
350 | list_t *command_policies; | 350 | list_t *command_policies; |
351 | list_t *feature_policies; | 351 | list_t *feature_policies; |
352 | list_t *ipc_policies; | 352 | list_t *ipc_policies; |
353 | |||
354 | // Context for command handlers | ||
355 | struct { | ||
356 | struct input_config *input_config; | ||
357 | struct seat_config *seat_config; | ||
358 | struct sway_seat *seat; | ||
359 | swayc_t *current_container; | ||
360 | } handler_context; | ||
353 | }; | 361 | }; |
354 | 362 | ||
355 | void pid_workspace_add(struct pid_workspace *pw); | 363 | void pid_workspace_add(struct pid_workspace *pw); |
@@ -375,6 +383,9 @@ bool read_config(FILE *file, struct sway_config *config); | |||
375 | * Free config struct | 383 | * Free config struct |
376 | */ | 384 | */ |
377 | void free_config(struct sway_config *config); | 385 | void free_config(struct sway_config *config); |
386 | |||
387 | void config_clear_handler_context(struct sway_config *config); | ||
388 | |||
378 | void free_sway_variable(struct sway_variable *var); | 389 | void free_sway_variable(struct sway_variable *var); |
379 | /** | 390 | /** |
380 | * Does variable replacement for a string based on the config's currently loaded variables. | 391 | * Does variable replacement for a string based on the config's currently loaded variables. |
diff --git a/include/sway/container.h b/include/sway/container.h index 9a5e312b..a99e2694 100644 --- a/include/sway/container.h +++ b/include/sway/container.h | |||
@@ -145,4 +145,6 @@ swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type); | |||
145 | swayc_t *swayc_at(swayc_t *parent, double lx, double ly, | 145 | swayc_t *swayc_at(swayc_t *parent, double lx, double ly, |
146 | struct wlr_surface **surface, double *sx, double *sy); | 146 | struct wlr_surface **surface, double *sx, double *sy); |
147 | 147 | ||
148 | void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data); | ||
149 | |||
148 | #endif | 150 | #endif |
diff --git a/include/sway/criteria.h b/include/sway/criteria.h new file mode 100644 index 00000000..9b4b4bef --- /dev/null +++ b/include/sway/criteria.h | |||
@@ -0,0 +1,42 @@ | |||
1 | #ifndef _SWAY_CRITERIA_H | ||
2 | #define _SWAY_CRITERIA_H | ||
3 | |||
4 | #include "container.h" | ||
5 | #include "list.h" | ||
6 | |||
7 | /** | ||
8 | * Maps criteria (as a list of criteria tokens) to a command list. | ||
9 | * | ||
10 | * A list of tokens together represent a single criteria string (e.g. | ||
11 | * '[class="abc" title="xyz"]' becomes two criteria tokens). | ||
12 | * | ||
13 | * for_window: Views matching all criteria will have the bound command list | ||
14 | * executed on them. | ||
15 | * | ||
16 | * Set via `for_window <criteria> <cmd list>`. | ||
17 | */ | ||
18 | struct criteria { | ||
19 | list_t *tokens; // struct crit_token, contains compiled regex. | ||
20 | char *crit_raw; // entire criteria string (for logging) | ||
21 | |||
22 | char *cmdlist; | ||
23 | }; | ||
24 | |||
25 | int criteria_cmp(const void *item, const void *data); | ||
26 | void free_criteria(struct criteria *crit); | ||
27 | |||
28 | // Pouplate list with crit_tokens extracted from criteria string, returns error | ||
29 | // string or NULL if successful. | ||
30 | char *extract_crit_tokens(list_t *tokens, const char *criteria); | ||
31 | |||
32 | // Returns list of criteria that match given container. These criteria have | ||
33 | // been set with `for_window` commands and have an associated cmdlist. | ||
34 | list_t *criteria_for(swayc_t *cont); | ||
35 | |||
36 | // Returns a list of all containers that match the given list of tokens. | ||
37 | list_t *container_for_crit_tokens(list_t *tokens); | ||
38 | |||
39 | // Returns true if any criteria in the given list matches this container | ||
40 | bool criteria_any(swayc_t *cont, list_t *criteria); | ||
41 | |||
42 | #endif | ||
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 53064eed..2bf297ce 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h | |||
@@ -5,9 +5,6 @@ | |||
5 | #include "sway/config.h" | 5 | #include "sway/config.h" |
6 | #include "list.h" | 6 | #include "list.h" |
7 | 7 | ||
8 | extern struct input_config *current_input_config; | ||
9 | extern struct seat_config *current_seat_config; | ||
10 | |||
11 | /** | 8 | /** |
12 | * The global singleton input manager | 9 | * The global singleton input manager |
13 | * TODO: make me not a global | 10 | * TODO: make me not a global |
@@ -46,4 +43,7 @@ void sway_input_manager_apply_input_config(struct sway_input_manager *input, | |||
46 | void sway_input_manager_apply_seat_config(struct sway_input_manager *input, | 43 | void sway_input_manager_apply_seat_config(struct sway_input_manager *input, |
47 | struct seat_config *seat_config); | 44 | struct seat_config *seat_config); |
48 | 45 | ||
46 | struct sway_seat *sway_input_manager_get_default_seat( | ||
47 | struct sway_input_manager *input); | ||
48 | |||
49 | #endif | 49 | #endif |
diff --git a/include/sway/view.h b/include/sway/view.h index 08c5480b..ac33e11a 100644 --- a/include/sway/view.h +++ b/include/sway/view.h | |||
@@ -92,10 +92,27 @@ struct sway_view { | |||
92 | void (*set_position)(struct sway_view *view, | 92 | void (*set_position)(struct sway_view *view, |
93 | double ox, double oy); | 93 | double ox, double oy); |
94 | void (*set_activated)(struct sway_view *view, bool activated); | 94 | void (*set_activated)(struct sway_view *view, bool activated); |
95 | void (*close)(struct sway_view *view); | ||
95 | } iface; | 96 | } iface; |
96 | 97 | ||
97 | // only used for unmanaged views (shell specific) | 98 | // only used for unmanaged views (shell specific) |
98 | struct wl_list unmanaged_view_link; // sway_root::unmanaged views | 99 | struct wl_list unmanaged_view_link; // sway_root::unmanaged views |
99 | }; | 100 | }; |
100 | 101 | ||
102 | const char *view_get_title(struct sway_view *view); | ||
103 | |||
104 | const char *view_get_app_id(struct sway_view *view); | ||
105 | |||
106 | const char *view_get_class(struct sway_view *view); | ||
107 | |||
108 | const char *view_get_instance(struct sway_view *view); | ||
109 | |||
110 | void view_set_size(struct sway_view *view, int width, int height); | ||
111 | |||
112 | void view_set_position(struct sway_view *view, double ox, double oy); | ||
113 | |||
114 | void view_set_activated(struct sway_view *view, bool activated); | ||
115 | |||
116 | void view_close(struct sway_view *view); | ||
117 | |||
101 | #endif | 118 | #endif |
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 | ||
79 | void apply_seat_config(struct seat_config *seat) { | 78 | void 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 | ||
8 | struct cmd_results *input_cmd_click_method(int argc, char **argv) { | 8 | struct 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 | ||
8 | struct cmd_results *input_cmd_events(int argc, char **argv) { | 8 | struct 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 | ||
8 | struct cmd_results *input_cmd_tap(int argc, char **argv) { | 8 | struct 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 | ||
7 | struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) { | 7 | struct 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 | ||
7 | struct cmd_results *input_cmd_xkb_model(int argc, char **argv) { | 7 | struct 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 | ||
7 | struct cmd_results *input_cmd_xkb_options(int argc, char **argv) { | 7 | struct 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 | ||
7 | struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) { | 7 | struct 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 | ||
7 | struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) { | 7 | struct 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 | |||
8 | struct 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 | ||
56 | void free_config(struct sway_config *config) { | 56 | void 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 | ||
490 | void 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 | ||
489 | bool read_config(FILE *file, struct sway_config *config) { | 497 | bool 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 | |||
14 | enum 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 | |||
31 | static 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 | */ | ||
51 | struct crit_token { | ||
52 | enum criteria_type type; | ||
53 | pcre *regex; | ||
54 | char *raw; | ||
55 | }; | ||
56 | |||
57 | static void free_crit_token(struct crit_token *crit) { | ||
58 | pcre_free(crit->regex); | ||
59 | free(crit->raw); | ||
60 | free(crit); | ||
61 | } | ||
62 | |||
63 | static 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. | ||
72 | static 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. | ||
88 | static 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. | ||
106 | static 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. | ||
188 | static 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. | ||
216 | static 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, ®_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 | ||
233 | static 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. | ||
239 | char *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 | } | ||
264 | ect_cleanup: | ||
265 | free(argv[0]); // base string | ||
266 | free(argv); | ||
267 | return error; | ||
268 | } | ||
269 | |||
270 | static 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). | ||
275 | static 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 | |||
372 | int 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 | |||
388 | void 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 | |||
401 | bool 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 | |||
411 | list_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 | |||
422 | struct list_tokens { | ||
423 | list_t *list; | ||
424 | list_t *tokens; | ||
425 | }; | ||
426 | |||
427 | static 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 | |||
434 | list_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 | ||
54 | static 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 | |||
54 | static void handle_commit(struct wl_listener *listener, void *data) { | 62 | static 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 | ||
60 | static 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 | |||
60 | static void handle_commit(struct wl_listener *listener, void *data) { | 70 | static 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 | ||
83 | static 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 | |||
83 | static void handle_commit(struct wl_listener *listener, void *data) { | 90 | static 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 | |||
376 | struct 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 | ||
92 | static void binding_execute_command(struct sway_binding *binding) { | 92 | static 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 | ||
52 | sway_deps = [ | 55 | sway_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 | |||
325 | void 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 | |||
3 | const 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 | |||
10 | const 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 | |||
17 | const 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 | |||
24 | const 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 | |||
31 | void 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 | |||
37 | void 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 | |||
43 | void 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 | |||
49 | void view_close(struct sway_view *view) { | ||
50 | if (view->iface.close) { | ||
51 | view->iface.close(view); | ||
52 | } | ||
53 | } | ||