aboutsummaryrefslogtreecommitdiff
path: root/sway/tree/container.c
diff options
context:
space:
mode:
authorRonan Pigott <ronan@rjp.ie>2023-02-19 17:22:37 -0700
committerTudor Brindus <vulcainus@gmail.com>2023-02-19 20:07:39 -0500
commit633d409b8897aec48ad1e328cb04261faa2b1a0b (patch)
tree3fa8778e8cc77cfccad215e4ad41b631b20a3045 /sway/tree/container.c
parent788118f1944ca23a7f9a7d19537b7756f3518f55 (diff)
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.
Diffstat (limited to 'sway/tree/container.c')
-rw-r--r--sway/tree/container.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 20701081..335dae87 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -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);
+ }
+}