From 661625b29edb820a7e6d29f4eafcdd3d9610ef22 Mon Sep 17 00:00:00 2001 From: lbonn Date: Sat, 7 Oct 2017 22:02:08 +0200 Subject: ipc/tree: output mandatory fields for all nodes Still missing: focus --- sway/ipc-json.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 31de53f0..775fcc24 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) json_object_object_add(object, "num", json_object_new_int(num)); json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); - json_object_object_add(object, "urgent", json_object_new_boolean(false)); json_object_object_add(object, "type", json_object_new_string("workspace")); json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); } @@ -156,7 +155,6 @@ static const char *ipc_json_get_scratchpad_state(swayc_t *c) { static void ipc_json_describe_view(swayc_t *c, json_object *object) { json_object *props = json_object_new_object(); - float percent = ipc_json_child_percentage(c); const char *layout = (c->parent->type == C_CONTAINER) ? ipc_json_layout_description(c->parent->layout) : "none"; 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) { json_object_object_add(object, "scratchpad_state", json_object_new_string(ipc_json_get_scratchpad_state(c))); - json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); - // TODO: make urgency actually work once Sway supports it - json_object_object_add(object, "urgent", json_object_new_boolean(false)); json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); json_object_object_add(object, "last_split_layout", @@ -177,17 +172,8 @@ static void ipc_json_describe_view(swayc_t *c, json_object *object) { json_object_object_add(object, "workspace_layout", json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->workspace_layout))); - json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); - json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); - - json_object_object_add(object, "rect", ipc_json_create_rect(c)); - json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); - json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); - json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); - json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); - json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat json_object_object_add(props, "class", c->class ? json_object_new_string(c->class) : c->app_id ? json_object_new_string(c->app_id) : NULL); 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) { json_object_object_add(object, "app_id", c->app_id ? json_object_new_string(c->app_id) : NULL); } +static void ipc_json_describe_root(swayc_t *c, json_object *object) { + json_object_object_add(object, "type", json_object_new_string("root")); + json_object_object_add(object, "layout", json_object_new_string("splith")); +} + json_object *ipc_json_describe_container(swayc_t *c) { + float percent = ipc_json_child_percentage(c); + if (!(sway_assert(c, "Container must not be null."))) { return NULL; } @@ -218,9 +211,19 @@ json_object *ipc_json_describe_container(swayc_t *c) { json_object_object_add(object, "visible", json_object_new_boolean(c->visible)); json_object_object_add(object, "focused", json_object_new_boolean(c == current_focus)); + json_object_object_add(object, "border", json_object_new_string(ipc_json_border_description(c))); + json_object_object_add(object, "window_rect", ipc_json_create_rect_from_geometry(c->actual_geometry)); + json_object_object_add(object, "deco_rect", ipc_json_create_rect_from_geometry(c->title_bar_geometry)); + json_object_object_add(object, "geometry", ipc_json_create_rect_from_geometry(c->cached_geometry)); + json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); + json_object_object_add(object, "window", json_object_new_int(c->handle)); // for the sake of i3 compat + // TODO: make urgency actually work once Sway supports it + json_object_object_add(object, "urgent", json_object_new_boolean(false)); + json_object_object_add(object, "current_border_width", json_object_new_int(c->border_thickness)); + switch (c->type) { case C_ROOT: - json_object_object_add(object, "type", json_object_new_string("root")); + ipc_json_describe_root(c, object); break; case C_OUTPUT: -- cgit v1.2.3-54-g00ecf From fd7c4bacbda311a8966a7f273dec16ce0ca45205 Mon Sep 17 00:00:00 2001 From: lbonn Date: Sun, 8 Oct 2017 00:00:53 +0200 Subject: ipc/tree: populate `focus` fields Ids of children, by order of focus --- sway/ipc-json.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 775fcc24..94768aa4 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -454,21 +454,50 @@ json_object *ipc_json_describe_container_recursive(swayc_t *c) { int i; json_object *floating = json_object_new_array(); - if (c->type != C_VIEW && c->floating && c->floating->length > 0) { + if (c->type != C_VIEW && c->floating) { for (i = 0; i < c->floating->length; ++i) { - json_object_array_add(floating, ipc_json_describe_container_recursive(c->floating->items[i])); + swayc_t *item = c->floating->items[i]; + json_object_array_add(floating, ipc_json_describe_container_recursive(item)); } } json_object_object_add(object, "floating_nodes", floating); json_object *children = json_object_new_array(); - if (c->type != C_VIEW && c->children && c->children->length > 0) { + if (c->type != C_VIEW && c->children) { for (i = 0; i < c->children->length; ++i) { json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); } } json_object_object_add(object, "nodes", children); + json_object *focus = json_object_new_array(); + if (c->type != C_VIEW) { + if (c->focused) { + json_object_array_add(focus, json_object_new_double(c->focused->id)); + } + if (c->floating) { + for (i = 0; i < c->floating->length; ++i) { + swayc_t *item = c->floating->items[i]; + if (item == c->focused) { + continue; + } + + json_object_array_add(focus, json_object_new_double(item->id)); + } + } + if (c->children) { + for (i = 0; i < c->children->length; ++i) { + swayc_t *item = c->children->items[i]; + if (item == c->focused) { + continue; + } + + json_object_array_add(focus, json_object_new_double(item->id)); + } + } + } + json_object_object_add(object, "focus", focus); + if (c->type == C_ROOT) { json_object *scratchpad_json = json_object_new_array(); if (scratchpad->length > 0) { -- cgit v1.2.3-54-g00ecf From d879e5b15d146a04ed7585b6c78653c4ac56b6dd Mon Sep 17 00:00:00 2001 From: lbonn Date: Sun, 8 Oct 2017 00:24:42 +0200 Subject: commands: implement 3 missing criteria from i3 * con_id * floating * tiling --- sway/criteria.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sway/criteria.c b/sway/criteria.c index 04683f66..9a04b48e 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -12,9 +12,12 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] CRIT_CLASS, + CRIT_CON_ID, CRIT_CON_MARK, + CRIT_FLOATING, CRIT_ID, CRIT_INSTANCE, + CRIT_TILING, CRIT_TITLE, CRIT_URGENT, CRIT_WINDOW_ROLE, @@ -25,9 +28,12 @@ enum criteria_type { // *must* keep in sync with criteria_strings[] static const char * const criteria_strings[CRIT_LAST] = { [CRIT_CLASS] = "class", + [CRIT_CON_ID] = "con_id", [CRIT_CON_MARK] = "con_mark", + [CRIT_FLOATING] = "floating", [CRIT_ID] = "id", [CRIT_INSTANCE] = "instance", + [CRIT_TILING] = "tiling", [CRIT_TITLE] = "title", [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... [CRIT_WINDOW_ROLE] = "window_role", @@ -263,6 +269,15 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { matches++; } break; + case CRIT_CON_ID: { + char *endptr; + size_t crit_id = strtoul(crit->raw, &endptr, 10); + + if (*endptr == 0 && cont->id == crit_id) { + ++matches; + } + break; + } case CRIT_CON_MARK: if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { // Make sure it isn't matching the NUL string @@ -271,6 +286,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { } } break; + case CRIT_FLOATING: + if (cont->is_floating) { + matches++; + } + break; case CRIT_ID: if (!cont->app_id) { // ignore @@ -290,6 +310,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) { matches++; } break; + case CRIT_TILING: + if (!cont->is_floating) { + matches++; + } + break; case CRIT_TITLE: if (!cont->name) { // ignore -- cgit v1.2.3-54-g00ecf From 514eed7e4b256565d85c63014500d1252fec2928 Mon Sep 17 00:00:00 2001 From: lbonn Date: Sun, 8 Oct 2017 01:05:40 +0200 Subject: commands: allow criterion values to be unquoted Sometimes it doesn't really make sense to quote them (numeric values for example) In that case, the value is parsed until the next space or the end of the whole criteria expression --- sway/criteria.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/sway/criteria.c b/sway/criteria.c index 9a04b48e..f5fe40cb 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -114,6 +114,7 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str char **argv = *buf = calloc(max_tokens, sizeof(char*)); argv[0] = base; // this needs to be freed by caller + bool quoted = true; *argc = 1; // uneven = name, even = value while (*head && *argc < max_tokens) { @@ -134,7 +135,8 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str if (*(namep) == ' ') { namep = strrchr(namep, ' ') + 1; } - argv[(*argc)++] = namep; + argv[*argc] = namep; + *argc += 1; } } else if (*head == '"') { if (*argc % 2 != 0) { @@ -143,21 +145,38 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str "Found quoted value where it was not expected"); } else if (!valp) { // value starts here valp = head + 1; + quoted = true; } else { // value ends here - argv[(*argc)++] = valp; + argv[*argc] = valp; + *argc += 1; *head = '\0'; valp = NULL; namep = head + 1; } - } else if (*argc % 2 == 0 && !valp && *head != ' ') { - // We're expecting a quoted value, haven't found one yet, and this - // is not an empty space. - return strdup("Unable to parse criteria: " - "Names must be unquoted, values must be quoted"); + } else if (*argc % 2 == 0 && *head != ' ') { + // parse unquoted values + if (!valp) { + quoted = false; + valp = head; // value starts here + } + } else if (valp && !quoted && *head == ' ') { + // value ends here + argv[*argc] = valp; + *argc += 1; + *head = '\0'; + valp = NULL; + namep = head + 1; } head++; } + + // catch last unquoted value if needed + if (valp && !quoted && !*head) { + argv[*argc] = valp; + *argc += 1; + } + return NULL; } -- cgit v1.2.3-54-g00ecf From b2d4caf6c34d8b6f6eccb9872a7d95772be19c10 Mon Sep 17 00:00:00 2001 From: lbonn Date: Sun, 8 Oct 2017 02:14:20 +0200 Subject: commands: fail when criteria match nothing For whatever command, this probably was not intended by the user --- sway/commands.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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) { if (!containers) { current_container = get_focused_container(&root_container); } else if (containers->length == 0) { - break; + if (results) { + free_cmd_results(results); + } + results = cmd_results_new(CMD_FAILURE, argv[0], "No matching container"); + goto cleanup; } else { current_container = (swayc_t *)containers->items[i]; } -- cgit v1.2.3-54-g00ecf From 61005c3bdab54b2ee84365fed4894c0e34da6c5b Mon Sep 17 00:00:00 2001 From: lbonn Date: Sun, 8 Oct 2017 02:24:08 +0200 Subject: ipc/window-event: fill "container" on close events Also use the recursive description to include children as well Careful: send the event before deleting the parent --- sway/handlers.c | 3 ++- sway/ipc-server.c | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) 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) { parent->fullscreen = NULL; } + ipc_event_window(parent, "close"); + // Destroy empty workspaces if (parent->type == C_WORKSPACE && parent->children->length == 0 && @@ -567,7 +569,6 @@ static void handle_view_destroyed(wlc_handle handle) { } arrange_windows(parent, -1, -1); - ipc_event_window(parent, "close"); } else { // Is it unmanaged? int i; 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) { sway_log(L_DEBUG, "Sending window::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); - if (strcmp(change, "close") == 0 || !window) { - json_object_object_add(obj, "container", NULL); - } else { - json_object_object_add(obj, "container", ipc_json_describe_container(window)); - } + json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); const char *json_string = json_object_to_json_string(obj); ipc_send_event(json_string, IPC_EVENT_WINDOW); -- cgit v1.2.3-54-g00ecf