diff options
author | Drew DeVault <sir@cmpwn.com> | 2017-10-08 10:02:52 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-08 10:02:52 -0400 |
commit | 43161a7e178b59b6bff3f210f46e21e8bf67e066 (patch) | |
tree | 8550777f6cffe2f692831b5edb77c45c2867adc5 | |
parent | Merge pull request #1385 from lbonn/sec-no-hidden (diff) | |
parent | ipc/window-event: fill "container" on close events (diff) | |
download | sway-43161a7e178b59b6bff3f210f46e21e8bf67e066.tar.gz sway-43161a7e178b59b6bff3f210f46e21e8bf67e066.tar.zst sway-43161a7e178b59b6bff3f210f46e21e8bf67e066.zip |
Merge pull request #1387 from lbonn/ipc-work
ipc: various fixes for i3 compat
-rw-r--r-- | sway/commands.c | 6 | ||||
-rw-r--r-- | sway/criteria.c | 58 | ||||
-rw-r--r-- | sway/handlers.c | 3 | ||||
-rw-r--r-- | sway/ipc-json.c | 68 | ||||
-rw-r--r-- | sway/ipc-server.c | 6 |
5 files changed, 109 insertions, 32 deletions
diff --git a/sway/commands.c b/sway/commands.c index d55d9a96..c7dbf731 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -458,7 +458,11 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) { | |||
458 | if (!containers) { | 458 | if (!containers) { |
459 | current_container = get_focused_container(&root_container); | 459 | current_container = get_focused_container(&root_container); |
460 | } else if (containers->length == 0) { | 460 | } else if (containers->length == 0) { |
461 | break; | 461 | if (results) { |
462 | free_cmd_results(results); | ||
463 | } | ||
464 | results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container"); | ||
465 | goto cleanup; | ||
462 | } else { | 466 | } else { |
463 | current_container = (swayc_t *)containers->items[i]; | 467 | current_container = (swayc_t *)containers->items[i]; |
464 | } | 468 | } |
diff --git a/sway/criteria.c b/sway/criteria.c index 04683f66..f5fe40cb 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -12,9 +12,12 @@ | |||
12 | 12 | ||
13 | enum criteria_type { // *must* keep in sync with criteria_strings[] | 13 | enum criteria_type { // *must* keep in sync with criteria_strings[] |
14 | CRIT_CLASS, | 14 | CRIT_CLASS, |
15 | CRIT_CON_ID, | ||
15 | CRIT_CON_MARK, | 16 | CRIT_CON_MARK, |
17 | CRIT_FLOATING, | ||
16 | CRIT_ID, | 18 | CRIT_ID, |
17 | CRIT_INSTANCE, | 19 | CRIT_INSTANCE, |
20 | CRIT_TILING, | ||
18 | CRIT_TITLE, | 21 | CRIT_TITLE, |
19 | CRIT_URGENT, | 22 | CRIT_URGENT, |
20 | CRIT_WINDOW_ROLE, | 23 | CRIT_WINDOW_ROLE, |
@@ -25,9 +28,12 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] | |||
25 | 28 | ||
26 | static const char * const criteria_strings[CRIT_LAST] = { | 29 | static const char * const criteria_strings[CRIT_LAST] = { |
27 | [CRIT_CLASS] = "class", | 30 | [CRIT_CLASS] = "class", |
31 | [CRIT_CON_ID] = "con_id", | ||
28 | [CRIT_CON_MARK] = "con_mark", | 32 | [CRIT_CON_MARK] = "con_mark", |
33 | [CRIT_FLOATING] = "floating", | ||
29 | [CRIT_ID] = "id", | 34 | [CRIT_ID] = "id", |
30 | [CRIT_INSTANCE] = "instance", | 35 | [CRIT_INSTANCE] = "instance", |
36 | [CRIT_TILING] = "tiling", | ||
31 | [CRIT_TITLE] = "title", | 37 | [CRIT_TITLE] = "title", |
32 | [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... | 38 | [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... |
33 | [CRIT_WINDOW_ROLE] = "window_role", | 39 | [CRIT_WINDOW_ROLE] = "window_role", |
@@ -108,6 +114,7 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str | |||
108 | 114 | ||
109 | char **argv = *buf = calloc(max_tokens, sizeof(char*)); | 115 | char **argv = *buf = calloc(max_tokens, sizeof(char*)); |
110 | argv[0] = base; // this needs to be freed by caller | 116 | argv[0] = base; // this needs to be freed by caller |
117 | bool quoted = true; | ||
111 | 118 | ||
112 | *argc = 1; // uneven = name, even = value | 119 | *argc = 1; // uneven = name, even = value |
113 | while (*head && *argc < max_tokens) { | 120 | while (*head && *argc < max_tokens) { |
@@ -128,7 +135,8 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str | |||
128 | if (*(namep) == ' ') { | 135 | if (*(namep) == ' ') { |
129 | namep = strrchr(namep, ' ') + 1; | 136 | namep = strrchr(namep, ' ') + 1; |
130 | } | 137 | } |
131 | argv[(*argc)++] = namep; | 138 | argv[*argc] = namep; |
139 | *argc += 1; | ||
132 | } | 140 | } |
133 | } else if (*head == '"') { | 141 | } else if (*head == '"') { |
134 | if (*argc % 2 != 0) { | 142 | if (*argc % 2 != 0) { |
@@ -137,21 +145,38 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str | |||
137 | "Found quoted value where it was not expected"); | 145 | "Found quoted value where it was not expected"); |
138 | } else if (!valp) { // value starts here | 146 | } else if (!valp) { // value starts here |
139 | valp = head + 1; | 147 | valp = head + 1; |
148 | quoted = true; | ||
140 | } else { | 149 | } else { |
141 | // value ends here | 150 | // value ends here |
142 | argv[(*argc)++] = valp; | 151 | argv[*argc] = valp; |
152 | *argc += 1; | ||
143 | *head = '\0'; | 153 | *head = '\0'; |
144 | valp = NULL; | 154 | valp = NULL; |
145 | namep = head + 1; | 155 | namep = head + 1; |
146 | } | 156 | } |
147 | } else if (*argc % 2 == 0 && !valp && *head != ' ') { | 157 | } else if (*argc % 2 == 0 && *head != ' ') { |
148 | // We're expecting a quoted value, haven't found one yet, and this | 158 | // parse unquoted values |
149 | // is not an empty space. | 159 | if (!valp) { |
150 | return strdup("Unable to parse criteria: " | 160 | quoted = false; |
151 | "Names must be unquoted, values must be quoted"); | 161 | valp = head; // value starts here |
162 | } | ||
163 | } else if (valp && !quoted && *head == ' ') { | ||
164 | // value ends here | ||
165 | argv[*argc] = valp; | ||
166 | *argc += 1; | ||
167 | *head = '\0'; | ||
168 | valp = NULL; | ||
169 | namep = head + 1; | ||
152 | } | 170 | } |
153 | head++; | 171 | head++; |
154 | } | 172 | } |
173 | |||
174 | // catch last unquoted value if needed | ||
175 | if (valp && !quoted && !*head) { | ||
176 | argv[*argc] = valp; | ||
177 | *argc += 1; | ||
178 | } | ||
179 | |||
155 | return NULL; | 180 | return NULL; |
156 | } | 181 | } |
157 | 182 | ||
@@ -263,6 +288,15 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
263 | matches++; | 288 | matches++; |
264 | } | 289 | } |
265 | break; | 290 | break; |
291 | case CRIT_CON_ID: { | ||
292 | char *endptr; | ||
293 | size_t crit_id = strtoul(crit->raw, &endptr, 10); | ||
294 | |||
295 | if (*endptr == 0 && cont->id == crit_id) { | ||
296 | ++matches; | ||
297 | } | ||
298 | break; | ||
299 | } | ||
266 | case CRIT_CON_MARK: | 300 | case CRIT_CON_MARK: |
267 | if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { | 301 | if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { |
268 | // Make sure it isn't matching the NUL string | 302 | // Make sure it isn't matching the NUL string |
@@ -271,6 +305,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
271 | } | 305 | } |
272 | } | 306 | } |
273 | break; | 307 | break; |
308 | case CRIT_FLOATING: | ||
309 | if (cont->is_floating) { | ||
310 | matches++; | ||
311 | } | ||
312 | break; | ||
274 | case CRIT_ID: | 313 | case CRIT_ID: |
275 | if (!cont->app_id) { | 314 | if (!cont->app_id) { |
276 | // ignore | 315 | // ignore |
@@ -290,6 +329,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { | |||
290 | matches++; | 329 | matches++; |
291 | } | 330 | } |
292 | break; | 331 | break; |
332 | case CRIT_TILING: | ||
333 | if (!cont->is_floating) { | ||
334 | matches++; | ||
335 | } | ||
336 | break; | ||
293 | case CRIT_TITLE: | 337 | case CRIT_TITLE: |
294 | if (!cont->name) { | 338 | if (!cont->name) { |
295 | // ignore | 339 | // ignore |
diff --git a/sway/handlers.c b/sway/handlers.c index 4a2298cd..db0c5e24 100644 --- a/sway/handlers.c +++ b/sway/handlers.c | |||
@@ -557,6 +557,8 @@ static void handle_view_destroyed(wlc_handle handle) { | |||
557 | parent->fullscreen = NULL; | 557 | parent->fullscreen = NULL; |
558 | } | 558 | } |
559 | 559 | ||
560 | ipc_event_window(parent, "close"); | ||
561 | |||
560 | // Destroy empty workspaces | 562 | // Destroy empty workspaces |
561 | if (parent->type == C_WORKSPACE && | 563 | if (parent->type == C_WORKSPACE && |
562 | parent->children->length == 0 && | 564 | parent->children->length == 0 && |
@@ -567,7 +569,6 @@ static void handle_view_destroyed(wlc_handle handle) { | |||
567 | } | 569 | } |
568 | 570 | ||
569 | arrange_windows(parent, -1, -1); | 571 | arrange_windows(parent, -1, -1); |
570 | ipc_event_window(parent, "close"); | ||
571 | } else { | 572 | } else { |
572 | // Is it unmanaged? | 573 | // Is it unmanaged? |
573 | int i; | 574 | int i; |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 31de53f0..94768aa4 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -138,7 +138,6 @@ static void ipc_json_describe_workspace(swayc_t *workspace, json_object *object) | |||
138 | 138 | ||
139 | json_object_object_add(object, "num", json_object_new_int(num)); | 139 | json_object_object_add(object, "num", json_object_new_int(num)); |
140 | json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); | 140 | json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); |
141 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
142 | json_object_object_add(object, "type", json_object_new_string("workspace")); | 141 | json_object_object_add(object, "type", json_object_new_string("workspace")); |
143 | json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); | 142 | json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); |
144 | } | 143 | } |
@@ -156,7 +155,6 @@ static const char *ipc_json_get_scratchpad_state(swayc_t *c) { | |||
156 | 155 | ||
157 | static void ipc_json_describe_view(swayc_t *c, json_object *object) { | 156 | static void ipc_json_describe_view(swayc_t *c, json_object *object) { |
158 | json_object *props = json_object_new_object(); | 157 | json_object *props = json_object_new_object(); |
159 | float percent = ipc_json_child_percentage(c); | ||
160 | const char *layout = (c->parent->type == C_CONTAINER) ? | 158 | const char *layout = (c->parent->type == C_CONTAINER) ? |
161 | ipc_json_layout_description(c->parent->layout) : "none"; | 159 | ipc_json_layout_description(c->parent->layout) : "none"; |
162 | const char *last_layout = (c->parent->type == C_CONTAINER) ? | 160 | const char *last_layout = (c->parent->type == C_CONTAINER) ? |
@@ -167,9 +165,6 @@ static void ipc_json_describe_view(swayc_t *c, json_object *object) { | |||
167 | 165 | ||
168 | json_object_object_add(object, "scratchpad_state", | 166 | json_object_object_add(object, "scratchpad_state", |
169 | json_object_new_string(ipc_json_get_scratchpad_state(c))); | 167 | json_object_new_string(ipc_json_get_scratchpad_state(c))); |
170 | json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); | ||
171 | // TODO: make urgency actually work once Sway supports it | ||
172 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
173 | json_object_object_add(object, "layout", | 168 | json_object_object_add(object, "layout", |
174 | (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); | 169 | (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); |
175 | json_object_object_add(object, "last_split_layout", | 170 | json_object_object_add(object, "last_split_layout", |
@@ -177,17 +172,8 @@ static void ipc_json_describe_view(swayc_t *c, json_object *object) { | |||
177 | json_object_object_add(object, "workspace_layout", | 172 | json_object_object_add(object, "workspace_layout", |
178 | json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); | 173 | json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); |
179 | 174 | ||
180 | json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); | ||
181 | json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); | ||
182 | |||
183 | json_object_object_add(object, "rect", ipc_json_create_rect(c)); | ||
184 | json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); | ||
185 | json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); | ||
186 | json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); | ||
187 | |||
188 | json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); | 175 | json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); |
189 | 176 | ||
190 | json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat | ||
191 | json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : | 177 | json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : |
192 | c->app_id ? json_object_new_string(c->app_id) : NULL); | 178 | c->app_id ? json_object_new_string(c->app_id) : NULL); |
193 | json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) : | 179 | json_object_object_add(props, "instance", c->instance ? json_object_new_string(c->instance) : |
@@ -205,7 +191,14 @@ static void ipc_json_describe_view(swayc_t *c, json_object *object) { | |||
205 | json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); | 191 | json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); |
206 | } | 192 | } |
207 | 193 | ||
194 | static void ipc_json_describe_root(swayc_t *c, json_object *object) { | ||
195 | json_object_object_add(object, "type", json_object_new_string("root")); | ||
196 | json_object_object_add(object, "layout", json_object_new_string("splith")); | ||
197 | } | ||
198 | |||
208 | json_object *ipc_json_describe_container(swayc_t *c) { | 199 | json_object *ipc_json_describe_container(swayc_t *c) { |
200 | float percent = ipc_json_child_percentage(c); | ||
201 | |||
209 | if (!(sway_assert(c, "Container must not be null."))) { | 202 | if (!(sway_assert(c, "Container must not be null."))) { |
210 | return NULL; | 203 | return NULL; |
211 | } | 204 | } |
@@ -218,9 +211,19 @@ json_object *ipc_json_describe_container(swayc_t *c) { | |||
218 | json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); | 211 | json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); |
219 | json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); | 212 | json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); |
220 | 213 | ||
214 | json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); | ||
215 | json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); | ||
216 | json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); | ||
217 | json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); | ||
218 | json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); | ||
219 | json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat | ||
220 | // TODO: make urgency actually work once Sway supports it | ||
221 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
222 | json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); | ||
223 | |||
221 | switch (c->type) { | 224 | switch (c->type) { |
222 | case C_ROOT: | 225 | case C_ROOT: |
223 | json_object_object_add(object, "type", json_object_new_string("root")); | 226 | ipc_json_describe_root(c, object); |
224 | break; | 227 | break; |
225 | 228 | ||
226 | case C_OUTPUT: | 229 | case C_OUTPUT: |
@@ -451,21 +454,50 @@ json_object *ipc_json_describe_container_recursive(swayc_t *c) { | |||
451 | int i; | 454 | int i; |
452 | 455 | ||
453 | json_object *floating = json_object_new_array(); | 456 | json_object *floating = json_object_new_array(); |
454 | if (c->type != C_VIEW && c->floating && c->floating->length > 0) { | 457 | if (c->type != C_VIEW && c->floating) { |
455 | for (i = 0; i < c->floating->length; ++i) { | 458 | for (i = 0; i < c->floating->length; ++i) { |
456 | json_object_array_add(floating, ipc_json_describe_container_recursive(c->floating->items[i])); | 459 | swayc_t *item = c->floating->items[i]; |
460 | json_object_array_add(floating, ipc_json_describe_container_recursive(item)); | ||
457 | } | 461 | } |
458 | } | 462 | } |
459 | json_object_object_add(object, "floating_nodes", floating); | 463 | json_object_object_add(object, "floating_nodes", floating); |
460 | 464 | ||
461 | json_object *children = json_object_new_array(); | 465 | json_object *children = json_object_new_array(); |
462 | if (c->type != C_VIEW && c->children && c->children->length > 0) { | 466 | if (c->type != C_VIEW && c->children) { |
463 | for (i = 0; i < c->children->length; ++i) { | 467 | for (i = 0; i < c->children->length; ++i) { |
464 | json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); | 468 | json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); |
465 | } | 469 | } |
466 | } | 470 | } |
467 | json_object_object_add(object, "nodes", children); | 471 | json_object_object_add(object, "nodes", children); |
468 | 472 | ||
473 | json_object *focus = json_object_new_array(); | ||
474 | if (c->type != C_VIEW) { | ||
475 | if (c->focused) { | ||
476 | json_object_array_add(focus, json_object_new_double(c->focused->id)); | ||
477 | } | ||
478 | if (c->floating) { | ||
479 | for (i = 0; i < c->floating->length; ++i) { | ||
480 | swayc_t *item = c->floating->items[i]; | ||
481 | if (item == c->focused) { | ||
482 | continue; | ||
483 | } | ||
484 | |||
485 | json_object_array_add(focus, json_object_new_double(item->id)); | ||
486 | } | ||
487 | } | ||
488 | if (c->children) { | ||
489 | for (i = 0; i < c->children->length; ++i) { | ||
490 | swayc_t *item = c->children->items[i]; | ||
491 | if (item == c->focused) { | ||
492 | continue; | ||
493 | } | ||
494 | |||
495 | json_object_array_add(focus, json_object_new_double(item->id)); | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | json_object_object_add(object, "focus", focus); | ||
500 | |||
469 | if (c->type == C_ROOT) { | 501 | if (c->type == C_ROOT) { |
470 | json_object *scratchpad_json = json_object_new_array(); | 502 | json_object *scratchpad_json = json_object_new_array(); |
471 | if (scratchpad->length > 0) { | 503 | if (scratchpad->length > 0) { |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 26d0be65..9122d548 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -792,11 +792,7 @@ void ipc_event_window(swayc_t *window, const char *change) { | |||
792 | sway_log(L_DEBUG, "Sending window::%s event", change); | 792 | sway_log(L_DEBUG, "Sending window::%s event", change); |
793 | json_object *obj = json_object_new_object(); | 793 | json_object *obj = json_object_new_object(); |
794 | json_object_object_add(obj, "change", json_object_new_string(change)); | 794 | json_object_object_add(obj, "change", json_object_new_string(change)); |
795 | if (strcmp(change, "close") == 0 || !window) { | 795 | json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); |
796 | json_object_object_add(obj, "container", NULL); | ||
797 | } else { | ||
798 | json_object_object_add(obj, "container", ipc_json_describe_container(window)); | ||
799 | } | ||
800 | 796 | ||
801 | const char *json_string = json_object_to_json_string(obj); | 797 | const char *json_string = json_object_to_json_string(obj); |
802 | ipc_send_event(json_string, IPC_EVENT_WINDOW); | 798 | ipc_send_event(json_string, IPC_EVENT_WINDOW); |