Fix for_window criteria and mouse button bindings

Previously, the special case handling of scratchpad and unmark commands
was (probably accidentally) limited to criteria directly handled in the
execute_command function. This would exclude: 1. for_window criteria, as
these are handled externally for views and 2. and mouse bindings which
select target the node currently under the mouse cursor.

As a concrete example `for_window [app_id="foobar"] move scratchpad,
scratchpad show` would show (or hide due to the toggling functionality)
another window from the scratchpad, instead of showing the window with
app_id "foobar".

This commit replaces the "using_criteria" flag with "node_overridden"
with the more general notion of signifying that the node (and
container/workspace) in the current command handler context of the sway
config is not defined by the currently focused node, but instead
overridden by other means, i.e., criteria or mouse position.
master
ftilde 4 years ago committed by Tudor Brindus
parent c6e7cf1ae5
commit 1afedcb94c

@ -559,7 +559,7 @@ struct sway_config {
struct sway_node *node; struct sway_node *node;
struct sway_container *container; struct sway_container *container;
struct sway_workspace *workspace; struct sway_workspace *workspace;
bool using_criteria; bool node_overridden; // True if the node is selected by means other than focus
struct { struct {
int argc; int argc;
char **argv; char **argv;

@ -174,10 +174,11 @@ static const struct cmd_handler *find_core_handler(char *line) {
handlers, sizeof(handlers)); handlers, sizeof(handlers));
} }
static void set_config_node(struct sway_node *node) { static void set_config_node(struct sway_node *node, bool node_overridden) {
config->handler_context.node = node; config->handler_context.node = node;
config->handler_context.container = NULL; config->handler_context.container = NULL;
config->handler_context.workspace = NULL; config->handler_context.workspace = NULL;
config->handler_context.node_overridden = node_overridden;
if (node == NULL) { if (node == NULL) {
return; return;
@ -202,6 +203,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
char *cmd; char *cmd;
char matched_delim = ';'; char matched_delim = ';';
list_t *containers = NULL; list_t *containers = NULL;
bool using_criteria = false;
if (seat == NULL) { if (seat == NULL) {
// passing a NULL seat means we just pick the default seat // passing a NULL seat means we just pick the default seat
@ -225,7 +227,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
for (; isspace(*head); ++head) {} for (; isspace(*head); ++head) {}
// Extract criteria (valid for this command list only). // Extract criteria (valid for this command list only).
if (matched_delim == ';') { if (matched_delim == ';') {
config->handler_context.using_criteria = false; using_criteria = false;
if (*head == '[') { if (*head == '[') {
char *error = NULL; char *error = NULL;
struct criteria *criteria = criteria_parse(head, &error); struct criteria *criteria = criteria_parse(head, &error);
@ -239,7 +241,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
containers = criteria_get_containers(criteria); containers = criteria_get_containers(criteria);
head += strlen(criteria->raw); head += strlen(criteria->raw);
criteria_destroy(criteria); criteria_destroy(criteria);
config->handler_context.using_criteria = true; using_criteria = true;
// Skip leading whitespace // Skip leading whitespace
for (; isspace(*head); ++head) {} for (; isspace(*head); ++head) {}
} }
@ -278,11 +280,14 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
argv[i] = do_var_replacement(argv[i]); argv[i] = do_var_replacement(argv[i]);
} }
if (!config->handler_context.using_criteria) {
// The container or workspace which this command will run on. if (!using_criteria) {
struct sway_node *node = con ? &con->node : if (con) {
seat_get_focus_inactive(seat, &root->node); set_config_node(&con->node, true);
set_config_node(node); } else {
set_config_node(seat_get_focus_inactive(seat, &root->node),
false);
}
struct cmd_results *res = handler->handle(argc-1, argv+1); struct cmd_results *res = handler->handle(argc-1, argv+1);
list_add(res_list, res); list_add(res_list, res);
if (res->status == CMD_INVALID) { if (res->status == CMD_INVALID) {
@ -296,7 +301,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
struct cmd_results *fail_res = NULL; struct cmd_results *fail_res = NULL;
for (int i = 0; i < containers->length; ++i) { for (int i = 0; i < containers->length; ++i) {
struct sway_container *container = containers->items[i]; struct sway_container *container = containers->items[i];
set_config_node(&container->node); set_config_node(&container->node, true);
struct cmd_results *res = handler->handle(argc-1, argv+1); struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status == CMD_SUCCESS) { if (res->status == CMD_SUCCESS) {
free_cmd_results(res); free_cmd_results(res);

@ -105,12 +105,12 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Scratchpad is empty"); return cmd_results_new(CMD_INVALID, "Scratchpad is empty");
} }
if (config->handler_context.using_criteria) { if (config->handler_context.node_overridden) {
struct sway_container *con = config->handler_context.container; struct sway_container *con = config->handler_context.container;
// If the container is in a floating split container, // If the container is in a floating split container,
// operate on the split container instead of the child. // operate on the split container instead of the child.
if (container_is_floating_or_child(con)) { if (con && container_is_floating_or_child(con)) {
while (con->pending.parent) { while (con->pending.parent) {
con = con->pending.parent; con = con->pending.parent;
} }
@ -118,8 +118,9 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) {
// If using criteria, this command is executed for every container which // If using criteria, this command is executed for every container which
// matches the criteria. If this container isn't in the scratchpad, // matches the criteria. If this container isn't in the scratchpad,
// we'll just silently return a success. // we'll just silently return a success. The same is true if the
if (!con->scratchpad) { // overridden node is not a container.
if (!con || !con->scratchpad) {
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);
} }
scratchpad_toggle_container(con); scratchpad_toggle_container(con);

@ -21,7 +21,7 @@ static void remove_all_marks_iterator(struct sway_container *con, void *data) {
struct cmd_results *cmd_unmark(int argc, char **argv) { struct cmd_results *cmd_unmark(int argc, char **argv) {
// Determine the container // Determine the container
struct sway_container *con = NULL; struct sway_container *con = NULL;
if (config->handler_context.using_criteria) { if (config->handler_context.node_overridden) {
con = config->handler_context.container; con = config->handler_context.container;
} }

Loading…
Cancel
Save