diff options
Diffstat (limited to 'sway/commands/swap.c')
-rw-r--r-- | sway/commands/swap.c | 182 |
1 files changed, 6 insertions, 176 deletions
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index a7f9691b..d44eb006 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/commands.h" | 5 | #include "sway/commands.h" |
6 | #include "sway/output.h" | 6 | #include "sway/output.h" |
7 | #include "sway/tree/arrange.h" | 7 | #include "sway/tree/arrange.h" |
8 | #include "sway/tree/container.h" | ||
8 | #include "sway/tree/root.h" | 9 | #include "sway/tree/root.h" |
9 | #include "sway/tree/view.h" | 10 | #include "sway/tree/view.h" |
10 | #include "sway/tree/workspace.h" | 11 | #include "sway/tree/workspace.h" |
@@ -13,180 +14,6 @@ | |||
13 | static const char expected_syntax[] = | 14 | static const char expected_syntax[] = |
14 | "Expected 'swap container with id|con_id|mark <arg>'"; | 15 | "Expected 'swap container with id|con_id|mark <arg>'"; |
15 | 16 | ||
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->width_fraction = con1->width_fraction; | ||
24 | temp->height_fraction = con1->height_fraction; | ||
25 | temp->parent = con1->parent; | ||
26 | temp->workspace = con1->workspace; | ||
27 | bool temp_floating = container_is_floating(con1); | ||
28 | |||
29 | con1->x = con2->x; | ||
30 | con1->y = con2->y; | ||
31 | con1->width = con2->width; | ||
32 | con1->height = con2->height; | ||
33 | con1->width_fraction = con2->width_fraction; | ||
34 | con1->height_fraction = con2->height_fraction; | ||
35 | |||
36 | con2->x = temp->x; | ||
37 | con2->y = temp->y; | ||
38 | con2->width = temp->width; | ||
39 | con2->height = temp->height; | ||
40 | con2->width_fraction = temp->width_fraction; | ||
41 | con2->height_fraction = temp->height_fraction; | ||
42 | |||
43 | int temp_index = container_sibling_index(con1); | ||
44 | if (con2->parent) { | ||
45 | container_insert_child(con2->parent, con1, | ||
46 | container_sibling_index(con2)); | ||
47 | } else if (container_is_floating(con2)) { | ||
48 | workspace_add_floating(con2->workspace, con1); | ||
49 | } else { | ||
50 | workspace_insert_tiling(con2->workspace, con1, | ||
51 | container_sibling_index(con2)); | ||
52 | } | ||
53 | if (temp->parent) { | ||
54 | container_insert_child(temp->parent, con2, temp_index); | ||
55 | } else if (temp_floating) { | ||
56 | workspace_add_floating(temp->workspace, con2); | ||
57 | } else { | ||
58 | workspace_insert_tiling(temp->workspace, con2, temp_index); | ||
59 | } | ||
60 | |||
61 | free(temp); | ||
62 | } | ||
63 | |||
64 | static void swap_focus(struct sway_container *con1, | ||
65 | struct sway_container *con2, struct sway_seat *seat, | ||
66 | struct sway_container *focus) { | ||
67 | if (focus == con1 || focus == con2) { | ||
68 | struct sway_workspace *ws1 = con1->workspace; | ||
69 | struct sway_workspace *ws2 = con2->workspace; | ||
70 | enum sway_container_layout layout1 = container_parent_layout(con1); | ||
71 | enum sway_container_layout layout2 = container_parent_layout(con2); | ||
72 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { | ||
73 | if (workspace_is_visible(ws2)) { | ||
74 | seat_set_focus(seat, &con2->node); | ||
75 | } | ||
76 | seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1); | ||
77 | } else if (focus == con2 && (layout1 == L_TABBED | ||
78 | || layout1 == L_STACKED)) { | ||
79 | if (workspace_is_visible(ws1)) { | ||
80 | seat_set_focus(seat, &con1->node); | ||
81 | } | ||
82 | seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2); | ||
83 | } else if (ws1 != ws2) { | ||
84 | seat_set_focus_container(seat, focus == con1 ? con2 : con1); | ||
85 | } else { | ||
86 | seat_set_focus_container(seat, focus); | ||
87 | } | ||
88 | } else { | ||
89 | seat_set_focus_container(seat, focus); | ||
90 | } | ||
91 | |||
92 | if (root->fullscreen_global) { | ||
93 | seat_set_focus(seat, | ||
94 | seat_get_focus_inactive(seat, &root->fullscreen_global->node)); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | void container_swap(struct sway_container *con1, struct sway_container *con2) { | ||
99 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { | ||
100 | return; | ||
101 | } | ||
102 | if (!sway_assert(!container_has_ancestor(con1, con2) | ||
103 | && !container_has_ancestor(con2, con1), | ||
104 | "Cannot swap ancestor and descendant")) { | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu", | ||
109 | con1->node.id, con2->node.id); | ||
110 | |||
111 | bool scratch1 = con1->scratchpad; | ||
112 | bool hidden1 = container_is_scratchpad_hidden(con1); | ||
113 | bool scratch2 = con2->scratchpad; | ||
114 | bool hidden2 = container_is_scratchpad_hidden(con2); | ||
115 | if (scratch1) { | ||
116 | if (hidden1) { | ||
117 | root_scratchpad_show(con1); | ||
118 | } | ||
119 | root_scratchpad_remove_container(con1); | ||
120 | } | ||
121 | if (scratch2) { | ||
122 | if (hidden2) { | ||
123 | root_scratchpad_show(con2); | ||
124 | } | ||
125 | root_scratchpad_remove_container(con2); | ||
126 | } | ||
127 | |||
128 | enum sway_fullscreen_mode fs1 = con1->fullscreen_mode; | ||
129 | enum sway_fullscreen_mode fs2 = con2->fullscreen_mode; | ||
130 | if (fs1) { | ||
131 | container_fullscreen_disable(con1); | ||
132 | } | ||
133 | if (fs2) { | ||
134 | container_fullscreen_disable(con2); | ||
135 | } | ||
136 | |||
137 | struct sway_seat *seat = config->handler_context.seat; | ||
138 | struct sway_container *focus = seat_get_focused_container(seat); | ||
139 | struct sway_workspace *vis1 = | ||
140 | output_get_active_workspace(con1->workspace->output); | ||
141 | struct sway_workspace *vis2 = | ||
142 | output_get_active_workspace(con2->workspace->output); | ||
143 | if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a" | ||
144 | "workspace. This should not happen")) { | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | char *stored_prev_name = NULL; | ||
149 | if (seat->prev_workspace_name) { | ||
150 | stored_prev_name = strdup(seat->prev_workspace_name); | ||
151 | } | ||
152 | |||
153 | swap_places(con1, con2); | ||
154 | |||
155 | if (!workspace_is_visible(vis1)) { | ||
156 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); | ||
157 | } | ||
158 | if (!workspace_is_visible(vis2)) { | ||
159 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); | ||
160 | } | ||
161 | |||
162 | swap_focus(con1, con2, seat, focus); | ||
163 | |||
164 | if (stored_prev_name) { | ||
165 | free(seat->prev_workspace_name); | ||
166 | seat->prev_workspace_name = stored_prev_name; | ||
167 | } | ||
168 | |||
169 | if (scratch1) { | ||
170 | root_scratchpad_add_container(con2, NULL); | ||
171 | if (!hidden1) { | ||
172 | root_scratchpad_show(con2); | ||
173 | } | ||
174 | } | ||
175 | if (scratch2) { | ||
176 | root_scratchpad_add_container(con1, NULL); | ||
177 | if (!hidden2) { | ||
178 | root_scratchpad_show(con1); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if (fs1) { | ||
183 | container_set_fullscreen(con2, fs1); | ||
184 | } | ||
185 | if (fs2) { | ||
186 | container_set_fullscreen(con1, fs2); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static bool test_con_id(struct sway_container *container, void *data) { | 17 | static bool test_con_id(struct sway_container *container, void *data) { |
191 | size_t *con_id = data; | 18 | size_t *con_id = data; |
192 | return container->node.id == *con_id; | 19 | return container->node.id == *con_id; |
@@ -219,7 +46,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
219 | } | 46 | } |
220 | 47 | ||
221 | if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) { | 48 | if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) { |
222 | return cmd_results_new(CMD_INVALID, expected_syntax); | 49 | return cmd_results_new(CMD_INVALID, "%s", expected_syntax); |
223 | } | 50 | } |
224 | 51 | ||
225 | struct sway_container *current = config->handler_context.container; | 52 | struct sway_container *current = config->handler_context.container; |
@@ -238,7 +65,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
238 | other = root_find_container(test_mark, value); | 65 | other = root_find_container(test_mark, value); |
239 | } else { | 66 | } else { |
240 | free(value); | 67 | free(value); |
241 | return cmd_results_new(CMD_INVALID, expected_syntax); | 68 | return cmd_results_new(CMD_INVALID, "%s", expected_syntax); |
242 | } | 69 | } |
243 | 70 | ||
244 | if (!other) { | 71 | if (!other) { |
@@ -247,6 +74,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
247 | } else if (!current) { | 74 | } else if (!current) { |
248 | error = cmd_results_new(CMD_FAILURE, | 75 | error = cmd_results_new(CMD_FAILURE, |
249 | "Can only swap with containers and views"); | 76 | "Can only swap with containers and views"); |
77 | } else if (current == other) { | ||
78 | error = cmd_results_new(CMD_FAILURE, | ||
79 | "Cannot swap a container with itself"); | ||
250 | } else if (container_has_ancestor(current, other) | 80 | } else if (container_has_ancestor(current, other) |
251 | || container_has_ancestor(other, current)) { | 81 | || container_has_ancestor(other, current)) { |
252 | error = cmd_results_new(CMD_FAILURE, | 82 | error = cmd_results_new(CMD_FAILURE, |