d6cd79c342
This introduces the following `for_each` functions: * root_for_each_workspace * root_for_each_container * output_for_each_workspace * output_for_each_container * workspace_for_each_container And introduces the following `find` functions: * root_find_output * root_find_workspace * root_find_container * output_find_workspace * output_find_container * workspace_find_container * container_find_child And removes the following functions: * container_descendants * container_for_each_descendant * container_find This change is preparing the way for demoting sway_container. Eventually these functions will accept and return sway_outputs, sway_workspaces and sway_containers (meaning a C_CONTAINER or C_VIEW). This change also makes it easy to handle abnormalities like the workspace floating list, root's scratchpad list and (once implemented) root's saved workspaces list for when there's no connected outputs.
95 lines
2.8 KiB
C
95 lines
2.8 KiB
C
#include <strings.h>
|
|
#include <wlr/util/log.h>
|
|
#include "config.h"
|
|
#include "sway/commands.h"
|
|
#include "sway/tree/arrange.h"
|
|
#include "sway/tree/layout.h"
|
|
#include "sway/tree/view.h"
|
|
#include "stringop.h"
|
|
|
|
static const char* EXPECTED_SYNTAX =
|
|
"Expected 'swap container with id|con_id|mark <arg>'";
|
|
|
|
static bool test_con_id(struct sway_container *container, void *con_id) {
|
|
return container->id == (size_t)con_id;
|
|
}
|
|
|
|
static bool test_id(struct sway_container *container, void *id) {
|
|
#ifdef HAVE_XWAYLAND
|
|
xcb_window_t *wid = id;
|
|
return (container->type == C_VIEW
|
|
&& container->sway_view->type == SWAY_VIEW_XWAYLAND
|
|
&& container->sway_view->wlr_xwayland_surface->window_id == *wid);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static bool test_mark(struct sway_container *container, void *mark) {
|
|
if (container->type == C_VIEW && container->sway_view->marks->length) {
|
|
return !list_seq_find(container->sway_view->marks,
|
|
(int (*)(const void *, const void *))strcmp, mark);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct cmd_results *cmd_swap(int argc, char **argv) {
|
|
struct cmd_results *error = NULL;
|
|
if ((error = checkarg(argc, "swap", EXPECTED_AT_LEAST, 4))) {
|
|
return error;
|
|
}
|
|
|
|
if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) {
|
|
return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX);
|
|
}
|
|
|
|
struct sway_container *current = config->handler_context.current_container;
|
|
struct sway_container *other;
|
|
|
|
char *value = join_args(argv + 3, argc - 3);
|
|
if (strcasecmp(argv[2], "id") == 0) {
|
|
#ifdef HAVE_XWAYLAND
|
|
xcb_window_t id = strtol(value, NULL, 0);
|
|
other = root_find_container(test_id, (void *)&id);
|
|
#endif
|
|
} else if (strcasecmp(argv[2], "con_id") == 0) {
|
|
size_t con_id = atoi(value);
|
|
other = root_find_container(test_con_id, (void *)con_id);
|
|
} else if (strcasecmp(argv[2], "mark") == 0) {
|
|
other = root_find_container(test_mark, (void *)value);
|
|
} else {
|
|
free(value);
|
|
return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX);
|
|
}
|
|
|
|
if (!other) {
|
|
error = cmd_results_new(CMD_FAILURE, "swap",
|
|
"Failed to find %s '%s'", argv[2], value);
|
|
} else if (current->type < C_CONTAINER || other->type < C_CONTAINER) {
|
|
error = cmd_results_new(CMD_FAILURE, "swap",
|
|
"Can only swap with containers and views");
|
|
} else if (container_has_ancestor(current, other)
|
|
|| container_has_ancestor(other, current)) {
|
|
error = cmd_results_new(CMD_FAILURE, "swap",
|
|
"Cannot swap ancestor and descendant");
|
|
} else if (current->layout == L_FLOATING || other->layout == L_FLOATING) {
|
|
error = cmd_results_new(CMD_FAILURE, "swap",
|
|
"Swapping with floating containers is not supported");
|
|
}
|
|
|
|
free(value);
|
|
|
|
if (error) {
|
|
return error;
|
|
}
|
|
|
|
container_swap(current, other);
|
|
|
|
arrange_windows(current->parent);
|
|
if (other->parent != current->parent) {
|
|
arrange_windows(other->parent);
|
|
}
|
|
|
|
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
|
|
}
|