container: rehome the container_swap function into container.c

This function was already declared in container.h but defined in
commands/swap.c for some unknown reason. Everything in commands/ assumes
the handler context has been set appropriately by the command preludes
but this function snuck its way into seatop_* which doesn't set anything
in the handler context.

The fact that the seatop drag actions manipulate the focus without
custody of the seat means they are definitely very broken in multiseat.
This commit is contained in:
Ronan Pigott 2023-02-19 17:22:37 -07:00 committed by Tudor Brindus
parent 788118f194
commit 633d409b88
2 changed files with 175 additions and 174 deletions

View file

@ -5,6 +5,7 @@
#include "sway/commands.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@ -13,180 +14,6 @@
static const char expected_syntax[] =
"Expected 'swap container with id|con_id|mark <arg>'";
static void swap_places(struct sway_container *con1,
struct sway_container *con2) {
struct sway_container *temp = malloc(sizeof(struct sway_container));
temp->pending.x = con1->pending.x;
temp->pending.y = con1->pending.y;
temp->pending.width = con1->pending.width;
temp->pending.height = con1->pending.height;
temp->width_fraction = con1->width_fraction;
temp->height_fraction = con1->height_fraction;
temp->pending.parent = con1->pending.parent;
temp->pending.workspace = con1->pending.workspace;
bool temp_floating = container_is_floating(con1);
con1->pending.x = con2->pending.x;
con1->pending.y = con2->pending.y;
con1->pending.width = con2->pending.width;
con1->pending.height = con2->pending.height;
con1->width_fraction = con2->width_fraction;
con1->height_fraction = con2->height_fraction;
con2->pending.x = temp->pending.x;
con2->pending.y = temp->pending.y;
con2->pending.width = temp->pending.width;
con2->pending.height = temp->pending.height;
con2->width_fraction = temp->width_fraction;
con2->height_fraction = temp->height_fraction;
int temp_index = container_sibling_index(con1);
if (con2->pending.parent) {
container_insert_child(con2->pending.parent, con1,
container_sibling_index(con2));
} else if (container_is_floating(con2)) {
workspace_add_floating(con2->pending.workspace, con1);
} else {
workspace_insert_tiling(con2->pending.workspace, con1,
container_sibling_index(con2));
}
if (temp->pending.parent) {
container_insert_child(temp->pending.parent, con2, temp_index);
} else if (temp_floating) {
workspace_add_floating(temp->pending.workspace, con2);
} else {
workspace_insert_tiling(temp->pending.workspace, con2, temp_index);
}
free(temp);
}
static void swap_focus(struct sway_container *con1,
struct sway_container *con2, struct sway_seat *seat,
struct sway_container *focus) {
if (focus == con1 || focus == con2) {
struct sway_workspace *ws1 = con1->pending.workspace;
struct sway_workspace *ws2 = con2->pending.workspace;
enum sway_container_layout layout1 = container_parent_layout(con1);
enum sway_container_layout layout2 = container_parent_layout(con2);
if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) {
if (workspace_is_visible(ws2)) {
seat_set_focus(seat, &con2->node);
}
seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1);
} else if (focus == con2 && (layout1 == L_TABBED
|| layout1 == L_STACKED)) {
if (workspace_is_visible(ws1)) {
seat_set_focus(seat, &con1->node);
}
seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2);
} else if (ws1 != ws2) {
seat_set_focus_container(seat, focus == con1 ? con2 : con1);
} else {
seat_set_focus_container(seat, focus);
}
} else {
seat_set_focus_container(seat, focus);
}
if (root->fullscreen_global) {
seat_set_focus(seat,
seat_get_focus_inactive(seat, &root->fullscreen_global->node));
}
}
void container_swap(struct sway_container *con1, struct sway_container *con2) {
if (!sway_assert(con1 && con2, "Cannot swap with nothing")) {
return;
}
if (!sway_assert(!container_has_ancestor(con1, con2)
&& !container_has_ancestor(con2, con1),
"Cannot swap ancestor and descendant")) {
return;
}
sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu",
con1->node.id, con2->node.id);
bool scratch1 = con1->scratchpad;
bool hidden1 = container_is_scratchpad_hidden(con1);
bool scratch2 = con2->scratchpad;
bool hidden2 = container_is_scratchpad_hidden(con2);
if (scratch1) {
if (hidden1) {
root_scratchpad_show(con1);
}
root_scratchpad_remove_container(con1);
}
if (scratch2) {
if (hidden2) {
root_scratchpad_show(con2);
}
root_scratchpad_remove_container(con2);
}
enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode;
if (fs1) {
container_fullscreen_disable(con1);
}
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs2) {
container_fullscreen_disable(con2);
}
struct sway_seat *seat = config->handler_context.seat;
struct sway_container *focus = seat_get_focused_container(seat);
struct sway_workspace *vis1 =
output_get_active_workspace(con1->pending.workspace->output);
struct sway_workspace *vis2 =
output_get_active_workspace(con2->pending.workspace->output);
if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a"
"workspace. This should not happen")) {
return;
}
char *stored_prev_name = NULL;
if (seat->prev_workspace_name) {
stored_prev_name = strdup(seat->prev_workspace_name);
}
swap_places(con1, con2);
if (!workspace_is_visible(vis1)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node));
}
if (!workspace_is_visible(vis2)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node));
}
swap_focus(con1, con2, seat, focus);
if (stored_prev_name) {
free(seat->prev_workspace_name);
seat->prev_workspace_name = stored_prev_name;
}
if (scratch1) {
root_scratchpad_add_container(con2, NULL);
if (!hidden1) {
root_scratchpad_show(con2);
}
}
if (scratch2) {
root_scratchpad_add_container(con1, NULL);
if (!hidden2) {
root_scratchpad_show(con1);
}
}
if (fs1) {
container_set_fullscreen(con2, fs1);
}
if (fs2) {
container_set_fullscreen(con1, fs2);
}
}
static bool test_con_id(struct sway_container *container, void *data) {
size_t *con_id = data;
return container->node.id == *con_id;

View file

@ -1764,3 +1764,177 @@ int container_squash(struct sway_container *con) {
}
return change;
}
static void swap_places(struct sway_container *con1,
struct sway_container *con2) {
struct sway_container *temp = malloc(sizeof(struct sway_container));
temp->pending.x = con1->pending.x;
temp->pending.y = con1->pending.y;
temp->pending.width = con1->pending.width;
temp->pending.height = con1->pending.height;
temp->width_fraction = con1->width_fraction;
temp->height_fraction = con1->height_fraction;
temp->pending.parent = con1->pending.parent;
temp->pending.workspace = con1->pending.workspace;
bool temp_floating = container_is_floating(con1);
con1->pending.x = con2->pending.x;
con1->pending.y = con2->pending.y;
con1->pending.width = con2->pending.width;
con1->pending.height = con2->pending.height;
con1->width_fraction = con2->width_fraction;
con1->height_fraction = con2->height_fraction;
con2->pending.x = temp->pending.x;
con2->pending.y = temp->pending.y;
con2->pending.width = temp->pending.width;
con2->pending.height = temp->pending.height;
con2->width_fraction = temp->width_fraction;
con2->height_fraction = temp->height_fraction;
int temp_index = container_sibling_index(con1);
if (con2->pending.parent) {
container_insert_child(con2->pending.parent, con1,
container_sibling_index(con2));
} else if (container_is_floating(con2)) {
workspace_add_floating(con2->pending.workspace, con1);
} else {
workspace_insert_tiling(con2->pending.workspace, con1,
container_sibling_index(con2));
}
if (temp->pending.parent) {
container_insert_child(temp->pending.parent, con2, temp_index);
} else if (temp_floating) {
workspace_add_floating(temp->pending.workspace, con2);
} else {
workspace_insert_tiling(temp->pending.workspace, con2, temp_index);
}
free(temp);
}
static void swap_focus(struct sway_container *con1,
struct sway_container *con2, struct sway_seat *seat,
struct sway_container *focus) {
if (focus == con1 || focus == con2) {
struct sway_workspace *ws1 = con1->pending.workspace;
struct sway_workspace *ws2 = con2->pending.workspace;
enum sway_container_layout layout1 = container_parent_layout(con1);
enum sway_container_layout layout2 = container_parent_layout(con2);
if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) {
if (workspace_is_visible(ws2)) {
seat_set_focus(seat, &con2->node);
}
seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1);
} else if (focus == con2 && (layout1 == L_TABBED
|| layout1 == L_STACKED)) {
if (workspace_is_visible(ws1)) {
seat_set_focus(seat, &con1->node);
}
seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2);
} else if (ws1 != ws2) {
seat_set_focus_container(seat, focus == con1 ? con2 : con1);
} else {
seat_set_focus_container(seat, focus);
}
} else {
seat_set_focus_container(seat, focus);
}
if (root->fullscreen_global) {
seat_set_focus(seat,
seat_get_focus_inactive(seat, &root->fullscreen_global->node));
}
}
void container_swap(struct sway_container *con1, struct sway_container *con2) {
if (!sway_assert(con1 && con2, "Cannot swap with nothing")) {
return;
}
if (!sway_assert(!container_has_ancestor(con1, con2)
&& !container_has_ancestor(con2, con1),
"Cannot swap ancestor and descendant")) {
return;
}
sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu",
con1->node.id, con2->node.id);
bool scratch1 = con1->scratchpad;
bool hidden1 = container_is_scratchpad_hidden(con1);
bool scratch2 = con2->scratchpad;
bool hidden2 = container_is_scratchpad_hidden(con2);
if (scratch1) {
if (hidden1) {
root_scratchpad_show(con1);
}
root_scratchpad_remove_container(con1);
}
if (scratch2) {
if (hidden2) {
root_scratchpad_show(con2);
}
root_scratchpad_remove_container(con2);
}
enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode;
if (fs1) {
container_fullscreen_disable(con1);
}
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs2) {
container_fullscreen_disable(con2);
}
struct sway_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat);
struct sway_workspace *vis1 =
output_get_active_workspace(con1->pending.workspace->output);
struct sway_workspace *vis2 =
output_get_active_workspace(con2->pending.workspace->output);
if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a"
"workspace. This should not happen")) {
return;
}
char *stored_prev_name = NULL;
if (seat->prev_workspace_name) {
stored_prev_name = strdup(seat->prev_workspace_name);
}
swap_places(con1, con2);
if (!workspace_is_visible(vis1)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node));
}
if (!workspace_is_visible(vis2)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node));
}
swap_focus(con1, con2, seat, focus);
if (stored_prev_name) {
free(seat->prev_workspace_name);
seat->prev_workspace_name = stored_prev_name;
}
if (scratch1) {
root_scratchpad_add_container(con2, NULL);
if (!hidden1) {
root_scratchpad_show(con2);
}
}
if (scratch2) {
root_scratchpad_add_container(con1, NULL);
if (!hidden2) {
root_scratchpad_show(con1);
}
}
if (fs1) {
container_set_fullscreen(con2, fs1);
}
if (fs2) {
container_set_fullscreen(con1, fs2);
}
}