diff options
Diffstat (limited to 'sway/commands/swap.c')
-rw-r--r-- | sway/commands/swap.c | 128 |
1 files changed, 127 insertions, 1 deletions
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index f881a002..f25c43a1 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -1,15 +1,141 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
1 | #include <strings.h> | 2 | #include <strings.h> |
2 | #include <wlr/util/log.h> | 3 | #include <wlr/util/log.h> |
3 | #include "config.h" | 4 | #include "config.h" |
5 | #include "log.h" | ||
4 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
5 | #include "sway/tree/arrange.h" | 7 | #include "sway/tree/arrange.h" |
6 | #include "sway/tree/layout.h" | 8 | #include "sway/tree/root.h" |
7 | #include "sway/tree/view.h" | 9 | #include "sway/tree/view.h" |
10 | #include "sway/tree/workspace.h" | ||
8 | #include "stringop.h" | 11 | #include "stringop.h" |
9 | 12 | ||
10 | static const char* EXPECTED_SYNTAX = | 13 | static const char* EXPECTED_SYNTAX = |
11 | "Expected 'swap container with id|con_id|mark <arg>'"; | 14 | "Expected 'swap container with id|con_id|mark <arg>'"; |
12 | 15 | ||
16 | static void swap_places(struct sway_container *con1, | ||
17 | struct sway_container *con2) { | ||
18 | struct sway_container *temp = malloc(sizeof(struct sway_container)); | ||
19 | temp->x = con1->x; | ||
20 | temp->y = con1->y; | ||
21 | temp->width = con1->width; | ||
22 | temp->height = con1->height; | ||
23 | temp->parent = con1->parent; | ||
24 | |||
25 | con1->x = con2->x; | ||
26 | con1->y = con2->y; | ||
27 | con1->width = con2->width; | ||
28 | con1->height = con2->height; | ||
29 | |||
30 | con2->x = temp->x; | ||
31 | con2->y = temp->y; | ||
32 | con2->width = temp->width; | ||
33 | con2->height = temp->height; | ||
34 | |||
35 | int temp_index = container_sibling_index(con1); | ||
36 | container_insert_child(con2->parent, con1, container_sibling_index(con2)); | ||
37 | container_insert_child(temp->parent, con2, temp_index); | ||
38 | |||
39 | free(temp); | ||
40 | } | ||
41 | |||
42 | static void swap_focus(struct sway_container *con1, | ||
43 | struct sway_container *con2, struct sway_seat *seat, | ||
44 | struct sway_container *focus) { | ||
45 | if (focus == con1 || focus == con2) { | ||
46 | struct sway_container *ws1 = container_parent(con1, C_WORKSPACE); | ||
47 | struct sway_container *ws2 = container_parent(con2, C_WORKSPACE); | ||
48 | if (focus == con1 && (con2->parent->layout == L_TABBED | ||
49 | || con2->parent->layout == L_STACKED)) { | ||
50 | if (workspace_is_visible(ws2)) { | ||
51 | seat_set_focus_warp(seat, con2, false, true); | ||
52 | } | ||
53 | seat_set_focus(seat, ws1 != ws2 ? con2 : con1); | ||
54 | } else if (focus == con2 && (con1->parent->layout == L_TABBED | ||
55 | || con1->parent->layout == L_STACKED)) { | ||
56 | if (workspace_is_visible(ws1)) { | ||
57 | seat_set_focus_warp(seat, con1, false, true); | ||
58 | } | ||
59 | seat_set_focus(seat, ws1 != ws2 ? con1 : con2); | ||
60 | } else if (ws1 != ws2) { | ||
61 | seat_set_focus(seat, focus == con1 ? con2 : con1); | ||
62 | } else { | ||
63 | seat_set_focus(seat, focus); | ||
64 | } | ||
65 | } else { | ||
66 | seat_set_focus(seat, focus); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static void container_swap(struct sway_container *con1, | ||
71 | struct sway_container *con2) { | ||
72 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { | ||
73 | return; | ||
74 | } | ||
75 | if (!sway_assert(con1->type >= C_CONTAINER && con2->type >= C_CONTAINER, | ||
76 | "Can only swap containers and views")) { | ||
77 | return; | ||
78 | } | ||
79 | if (!sway_assert(!container_has_ancestor(con1, con2) | ||
80 | && !container_has_ancestor(con2, con1), | ||
81 | "Cannot swap ancestor and descendant")) { | ||
82 | return; | ||
83 | } | ||
84 | if (!sway_assert(!container_is_floating(con1) | ||
85 | && !container_is_floating(con2), | ||
86 | "Swapping with floating containers is not supported")) { | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); | ||
91 | |||
92 | int fs1 = con1->is_fullscreen; | ||
93 | int fs2 = con2->is_fullscreen; | ||
94 | if (fs1) { | ||
95 | container_set_fullscreen(con1, false); | ||
96 | } | ||
97 | if (fs2) { | ||
98 | container_set_fullscreen(con2, false); | ||
99 | } | ||
100 | |||
101 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
102 | struct sway_container *focus = seat_get_focus(seat); | ||
103 | struct sway_container *vis1 = container_parent( | ||
104 | seat_get_focus_inactive(seat, container_parent(con1, C_OUTPUT)), | ||
105 | C_WORKSPACE); | ||
106 | struct sway_container *vis2 = container_parent( | ||
107 | seat_get_focus_inactive(seat, container_parent(con2, C_OUTPUT)), | ||
108 | C_WORKSPACE); | ||
109 | |||
110 | char *stored_prev_name = NULL; | ||
111 | if (prev_workspace_name) { | ||
112 | stored_prev_name = strdup(prev_workspace_name); | ||
113 | } | ||
114 | |||
115 | swap_places(con1, con2); | ||
116 | |||
117 | if (!workspace_is_visible(vis1)) { | ||
118 | seat_set_focus(seat, seat_get_focus_inactive(seat, vis1)); | ||
119 | } | ||
120 | if (!workspace_is_visible(vis2)) { | ||
121 | seat_set_focus(seat, seat_get_focus_inactive(seat, vis2)); | ||
122 | } | ||
123 | |||
124 | swap_focus(con1, con2, seat, focus); | ||
125 | |||
126 | if (stored_prev_name) { | ||
127 | free(prev_workspace_name); | ||
128 | prev_workspace_name = stored_prev_name; | ||
129 | } | ||
130 | |||
131 | if (fs1) { | ||
132 | container_set_fullscreen(con2, true); | ||
133 | } | ||
134 | if (fs2) { | ||
135 | container_set_fullscreen(con1, true); | ||
136 | } | ||
137 | } | ||
138 | |||
13 | static bool test_con_id(struct sway_container *container, void *con_id) { | 139 | static bool test_con_id(struct sway_container *container, void *con_id) { |
14 | return container->id == (size_t)con_id; | 140 | return container->id == (size_t)con_id; |
15 | } | 141 | } |