mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	Allow running commands on containers without focusing them
This adds a `con` argument to `execute_command` which allows you to specify the container to execute the command on. In most cases it leaves it as `NULL` which makes it use the focused node. We only set it when executing `for_window` criteria such as when a view maps. This means we don't send unnecessary IPC focus events, and fixes a crash when the criteria command is `move scratchpad` (because we can't give focus to a hidden scratchpad container). Each of the shell map handlers now check to see if the view has a workspace. It won't have a workspace if criteria has moved it to the scratchpad.
This commit is contained in:
		
							parent
							
								
									082488a81c
								
							
						
					
					
						commit
						cb66bbea42
					
				
					 9 changed files with 28 additions and 19 deletions
				
			
		| 
						 | 
					@ -4,6 +4,8 @@
 | 
				
			||||||
#include <wlr/util/edges.h>
 | 
					#include <wlr/util/edges.h>
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct sway_container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct cmd_results *sway_cmd(int argc, char **argv);
 | 
					typedef struct cmd_results *sway_cmd(int argc, char **argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_handler {
 | 
					struct cmd_handler {
 | 
				
			||||||
| 
						 | 
					@ -50,8 +52,13 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
 | 
				
			||||||
		int handlers_size);
 | 
							int handlers_size);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Parse and executes a command.
 | 
					 * Parse and executes a command.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the command string contains criteria then the command will be executed on
 | 
				
			||||||
 | 
					 * all matching containers. Otherwise, it'll run on the `con` container. If
 | 
				
			||||||
 | 
					 * `con` is NULL then it'll run on the currently focused container.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct cmd_results *execute_command(char *command,  struct sway_seat *seat);
 | 
					struct cmd_results *execute_command(char *command,  struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_container *con);
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Parse and handles a command during config file loading.
 | 
					 * Parse and handles a command during config file loading.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,7 +237,8 @@ static void set_config_node(struct sway_node *node) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 | 
					struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct sway_container *con) {
 | 
				
			||||||
	// Even though this function will process multiple commands we will only
 | 
						// Even though this function will process multiple commands we will only
 | 
				
			||||||
	// return the last error, if any (for now). (Since we have access to an
 | 
						// return the last error, if any (for now). (Since we have access to an
 | 
				
			||||||
	// error string we could e.g. concatenate all errors there.)
 | 
						// error string we could e.g. concatenate all errors there.)
 | 
				
			||||||
| 
						 | 
					@ -256,6 +257,15 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This is the container or workspace which this command will run on.
 | 
				
			||||||
 | 
						// Ignored if the command string contains criteria.
 | 
				
			||||||
 | 
						struct sway_node *node;
 | 
				
			||||||
 | 
						if (con) {
 | 
				
			||||||
 | 
							node = &con->node;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							node = seat_get_focus_inactive(seat, &root->node);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->handler_context.seat = seat;
 | 
						config->handler_context.seat = seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	head = exec;
 | 
						head = exec;
 | 
				
			||||||
| 
						 | 
					@ -318,9 +328,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (!config->handler_context.using_criteria) {
 | 
								if (!config->handler_context.using_criteria) {
 | 
				
			||||||
				// without criteria, the command acts upon the focused
 | 
									set_config_node(node);
 | 
				
			||||||
				// container
 | 
					 | 
				
			||||||
				set_config_node(seat_get_focus_inactive(seat, &root->node));
 | 
					 | 
				
			||||||
				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_argv(argc, argv);
 | 
										free_argv(argc, argv);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -321,7 +321,7 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config->handler_context.seat = seat;
 | 
						config->handler_context.seat = seat;
 | 
				
			||||||
	struct cmd_results *results = execute_command(binding->command, NULL);
 | 
						struct cmd_results *results = execute_command(binding->command, NULL, NULL);
 | 
				
			||||||
	if (results->status == CMD_SUCCESS) {
 | 
						if (results->status == CMD_SUCCESS) {
 | 
				
			||||||
		ipc_event_binding(binding_copy);
 | 
							ipc_event_binding(binding_copy);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -401,7 +401,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (view->container->parent) {
 | 
							if (view->container->parent) {
 | 
				
			||||||
			arrange_container(view->container->parent);
 | 
								arrange_container(view->container->parent);
 | 
				
			||||||
		} else {
 | 
							} else if (view->container->workspace) {
 | 
				
			||||||
			arrange_workspace(view->container->workspace);
 | 
								arrange_workspace(view->container->workspace);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -398,7 +398,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (view->container->parent) {
 | 
							if (view->container->parent) {
 | 
				
			||||||
			arrange_container(view->container->parent);
 | 
								arrange_container(view->container->parent);
 | 
				
			||||||
		} else {
 | 
							} else if (view->container->workspace) {
 | 
				
			||||||
			arrange_workspace(view->container->workspace);
 | 
								arrange_workspace(view->container->workspace);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -394,7 +394,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (view->container->parent) {
 | 
							if (view->container->parent) {
 | 
				
			||||||
			arrange_container(view->container->parent);
 | 
								arrange_container(view->container->parent);
 | 
				
			||||||
		} else {
 | 
							} else if (view->container->workspace) {
 | 
				
			||||||
			arrange_workspace(view->container->workspace);
 | 
								arrange_workspace(view->container->workspace);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -580,7 +580,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
 | 
				
			||||||
	switch (client->current_command) {
 | 
						switch (client->current_command) {
 | 
				
			||||||
	case IPC_COMMAND:
 | 
						case IPC_COMMAND:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		struct cmd_results *results = execute_command(buf, NULL);
 | 
							struct cmd_results *results = execute_command(buf, NULL, NULL);
 | 
				
			||||||
		transaction_commit_dirty();
 | 
							transaction_commit_dirty();
 | 
				
			||||||
		char *json = cmd_results_to_json(results);
 | 
							char *json = cmd_results_to_json(results);
 | 
				
			||||||
		int length = strlen(json);
 | 
							int length = strlen(json);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -429,7 +429,7 @@ int main(int argc, char **argv) {
 | 
				
			||||||
	wlr_log(WLR_DEBUG, "Running deferred commands");
 | 
						wlr_log(WLR_DEBUG, "Running deferred commands");
 | 
				
			||||||
	while (config->cmd_queue->length) {
 | 
						while (config->cmd_queue->length) {
 | 
				
			||||||
		char *line = config->cmd_queue->items[0];
 | 
							char *line = config->cmd_queue->items[0];
 | 
				
			||||||
		struct cmd_results *res = execute_command(line, NULL);
 | 
							struct cmd_results *res = execute_command(line, NULL, NULL);
 | 
				
			||||||
		if (res->status != CMD_SUCCESS) {
 | 
							if (res->status != CMD_SUCCESS) {
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
 | 
								wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -391,8 +391,6 @@ static bool view_has_executed_criteria(struct sway_view *view,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void view_execute_criteria(struct sway_view *view) {
 | 
					void view_execute_criteria(struct sway_view *view) {
 | 
				
			||||||
	struct sway_seat *seat = input_manager_current_seat(input_manager);
 | 
					 | 
				
			||||||
	struct sway_node *prior_focus = seat_get_focus(seat);
 | 
					 | 
				
			||||||
	list_t *criterias = criteria_for_view(view, CT_COMMAND);
 | 
						list_t *criterias = criteria_for_view(view, CT_COMMAND);
 | 
				
			||||||
	for (int i = 0; i < criterias->length; i++) {
 | 
						for (int i = 0; i < criterias->length; i++) {
 | 
				
			||||||
		struct criteria *criteria = criterias->items[i];
 | 
							struct criteria *criteria = criterias->items[i];
 | 
				
			||||||
| 
						 | 
					@ -403,16 +401,12 @@ void view_execute_criteria(struct sway_view *view) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
 | 
							wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
 | 
				
			||||||
				criteria->raw, view, criteria->cmdlist);
 | 
									criteria->raw, view, criteria->cmdlist);
 | 
				
			||||||
		seat_set_focus_container(seat, view->container);
 | 
					 | 
				
			||||||
		list_add(view->executed_criteria, criteria);
 | 
							list_add(view->executed_criteria, criteria);
 | 
				
			||||||
		struct cmd_results *res = execute_command(criteria->cmdlist, NULL);
 | 
							struct cmd_results *res = execute_command(
 | 
				
			||||||
		if (res->status != CMD_SUCCESS) {
 | 
									criteria->cmdlist, NULL, view->container);
 | 
				
			||||||
			wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		free_cmd_results(res);
 | 
							free_cmd_results(res);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	list_free(criterias);
 | 
						list_free(criterias);
 | 
				
			||||||
	seat_set_focus(seat, prior_focus);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sway_workspace *select_workspace(struct sway_view *view) {
 | 
					static struct sway_workspace *select_workspace(struct sway_view *view) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue