aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sway/commands.c6
-rw-r--r--sway/criteria.c58
-rw-r--r--sway/handlers.c3
-rw-r--r--sway/ipc-json.c68
-rw-r--r--sway/ipc-server.c6
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) {
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];
}
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 @@
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",
@@ -108,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) {
@@ -128,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) {
@@ -137,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;
}
@@ -263,6 +288,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 +305,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 +329,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
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-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)
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:
@@ -451,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) {
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);