Merge pull request #1387 from lbonn/ipc-work

ipc: various fixes for i3 compat
This commit is contained in:
Drew DeVault 2017-10-08 10:02:52 -04:00 committed by GitHub
commit 43161a7e17
5 changed files with 109 additions and 32 deletions

View file

@ -458,7 +458,11 @@ struct cmd_results *handle_command(char *_exec, enum command_context context) {
if (!containers) { if (!containers) {
current_container = get_focused_container(&root_container); current_container = get_focused_container(&root_container);
} else if (containers->length == 0) { } 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 { } else {
current_container = (swayc_t *)containers->items[i]; current_container = (swayc_t *)containers->items[i];
} }

View file

@ -12,9 +12,12 @@
enum criteria_type { // *must* keep in sync with criteria_strings[] enum criteria_type { // *must* keep in sync with criteria_strings[]
CRIT_CLASS, CRIT_CLASS,
CRIT_CON_ID,
CRIT_CON_MARK, CRIT_CON_MARK,
CRIT_FLOATING,
CRIT_ID, CRIT_ID,
CRIT_INSTANCE, CRIT_INSTANCE,
CRIT_TILING,
CRIT_TITLE, CRIT_TITLE,
CRIT_URGENT, CRIT_URGENT,
CRIT_WINDOW_ROLE, 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] = { static const char * const criteria_strings[CRIT_LAST] = {
[CRIT_CLASS] = "class", [CRIT_CLASS] = "class",
[CRIT_CON_ID] = "con_id",
[CRIT_CON_MARK] = "con_mark", [CRIT_CON_MARK] = "con_mark",
[CRIT_FLOATING] = "floating",
[CRIT_ID] = "id", [CRIT_ID] = "id",
[CRIT_INSTANCE] = "instance", [CRIT_INSTANCE] = "instance",
[CRIT_TILING] = "tiling",
[CRIT_TITLE] = "title", [CRIT_TITLE] = "title",
[CRIT_URGENT] = "urgent", // either "latest" or "oldest" ... [CRIT_URGENT] = "urgent", // either "latest" or "oldest" ...
[CRIT_WINDOW_ROLE] = "window_role", [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*)); char **argv = *buf = calloc(max_tokens, sizeof(char*));
argv[0] = base; // this needs to be freed by caller argv[0] = base; // this needs to be freed by caller
bool quoted = true;
*argc = 1; // uneven = name, even = value *argc = 1; // uneven = name, even = value
while (*head && *argc < max_tokens) { while (*head && *argc < max_tokens) {
@ -128,7 +135,8 @@ static char *crit_tokens(int *argc, char ***buf, const char * const criteria_str
if (*(namep) == ' ') { if (*(namep) == ' ') {
namep = strrchr(namep, ' ') + 1; namep = strrchr(namep, ' ') + 1;
} }
argv[(*argc)++] = namep; argv[*argc] = namep;
*argc += 1;
} }
} else if (*head == '"') { } else if (*head == '"') {
if (*argc % 2 != 0) { 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"); "Found quoted value where it was not expected");
} else if (!valp) { // value starts here } else if (!valp) { // value starts here
valp = head + 1; valp = head + 1;
quoted = true;
} else { } else {
// value ends here // value ends here
argv[(*argc)++] = valp; argv[*argc] = valp;
*argc += 1;
*head = '\0'; *head = '\0';
valp = NULL; valp = NULL;
namep = head + 1; namep = head + 1;
} }
} else if (*argc % 2 == 0 && !valp && *head != ' ') { } else if (*argc % 2 == 0 && *head != ' ') {
// We're expecting a quoted value, haven't found one yet, and this // parse unquoted values
// is not an empty space. if (!valp) {
return strdup("Unable to parse criteria: " quoted = false;
"Names must be unquoted, values must be quoted"); 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++; head++;
} }
// catch last unquoted value if needed
if (valp && !quoted && !*head) {
argv[*argc] = valp;
*argc += 1;
}
return NULL; return NULL;
} }
@ -263,6 +288,15 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
matches++; matches++;
} }
break; 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: case CRIT_CON_MARK:
if (crit->regex && cont->marks && (list_seq_find(cont->marks, (int (*)(const void *, const void *))regex_cmp, crit->regex) != -1)) { 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 // Make sure it isn't matching the NUL string
@ -271,6 +305,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
} }
} }
break; break;
case CRIT_FLOATING:
if (cont->is_floating) {
matches++;
}
break;
case CRIT_ID: case CRIT_ID:
if (!cont->app_id) { if (!cont->app_id) {
// ignore // ignore
@ -290,6 +329,11 @@ static bool criteria_test(swayc_t *cont, list_t *tokens) {
matches++; matches++;
} }
break; break;
case CRIT_TILING:
if (!cont->is_floating) {
matches++;
}
break;
case CRIT_TITLE: case CRIT_TITLE:
if (!cont->name) { if (!cont->name) {
// ignore // ignore

View file

@ -557,6 +557,8 @@ static void handle_view_destroyed(wlc_handle handle) {
parent->fullscreen = NULL; parent->fullscreen = NULL;
} }
ipc_event_window(parent, "close");
// Destroy empty workspaces // Destroy empty workspaces
if (parent->type == C_WORKSPACE && if (parent->type == C_WORKSPACE &&
parent->children->length == 0 && parent->children->length == 0 &&
@ -567,7 +569,6 @@ static void handle_view_destroyed(wlc_handle handle) {
} }
arrange_windows(parent, -1, -1); arrange_windows(parent, -1, -1);
ipc_event_window(parent, "close");
} else { } else {
// Is it unmanaged? // Is it unmanaged?
int i; int i;

View file

@ -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, "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, "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, "type", json_object_new_string("workspace"));
json_object_object_add(object, "layout", (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); 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) { static void ipc_json_describe_view(swayc_t *c, json_object *object) {
json_object *props = json_object_new_object(); json_object *props = json_object_new_object();
float percent = ipc_json_child_percentage(c);
const char *layout = (c->parent->type == C_CONTAINER) ? const char *layout = (c->parent->type == C_CONTAINER) ?
ipc_json_layout_description(c->parent->layout) : "none"; ipc_json_layout_description(c->parent->layout) : "none";
const char *last_layout = (c->parent->type == C_CONTAINER) ? 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_object_add(object, "scratchpad_state",
json_object_new_string(ipc_json_get_scratchpad_state(c))); 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", json_object_object_add(object, "layout",
(strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout));
json_object_object_add(object, "last_split_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_object_add(object, "workspace_layout",
json_object_new_string(ipc_json_layout_description(swayc_parent_by_type(c, C_WORKSPACE)->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, "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) : 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); 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) : 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); 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) { 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."))) { if (!(sway_assert(c, "Container must not be null."))) {
return 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, "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, "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) { switch (c->type) {
case C_ROOT: case C_ROOT:
json_object_object_add(object, "type", json_object_new_string("root")); ipc_json_describe_root(c, object);
break; break;
case C_OUTPUT: case C_OUTPUT:
@ -451,21 +454,50 @@ json_object *ipc_json_describe_container_recursive(swayc_t *c) {
int i; int i;
json_object *floating = json_object_new_array(); 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) { 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_object_add(object, "floating_nodes", floating);
json_object *children = json_object_new_array(); 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) { for (i = 0; i < c->children->length; ++i) {
json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i]));
} }
} }
json_object_object_add(object, "nodes", children); 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) { if (c->type == C_ROOT) {
json_object *scratchpad_json = json_object_new_array(); json_object *scratchpad_json = json_object_new_array();
if (scratchpad->length > 0) { if (scratchpad->length > 0) {

View file

@ -792,11 +792,7 @@ void ipc_event_window(swayc_t *window, const char *change) {
sway_log(L_DEBUG, "Sending window::%s event", change); sway_log(L_DEBUG, "Sending window::%s event", change);
json_object *obj = json_object_new_object(); json_object *obj = json_object_new_object();
json_object_object_add(obj, "change", json_object_new_string(change)); json_object_object_add(obj, "change", json_object_new_string(change));
if (strcmp(change, "close") == 0 || !window) { json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
json_object_object_add(obj, "container", NULL);
} else {
json_object_object_add(obj, "container", ipc_json_describe_container(window));
}
const char *json_string = json_object_to_json_string(obj); const char *json_string = json_object_to_json_string(obj);
ipc_send_event(json_string, IPC_EVENT_WINDOW); ipc_send_event(json_string, IPC_EVENT_WINDOW);