]> git.sur5r.net Git - i3/i3/blob - testcases/t/291-swap.t
3ba8f51ba151ee3d78d2fcc606bc186a584cf74c
[i3/i3] / testcases / t / 291-swap.t
1 #!perl
2 # vim:ts=4:sw=4:expandtab
3 #
4 # Please read the following documents before working on tests:
5 # • http://build.i3wm.org/docs/testsuite.html
6 #   (or docs/testsuite)
7 #
8 # • http://build.i3wm.org/docs/lib-i3test.html
9 #   (alternatively: perldoc ./testcases/lib/i3test.pm)
10 #
11 # • http://build.i3wm.org/docs/ipc.html
12 #   (or docs/ipc)
13 #
14 # • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
15 #   (unless you are already familiar with Perl)
16 #
17 # Tests the swap command.
18 # Ticket: #917
19 use i3test i3_autostart => 0;
20
21 my $config = <<EOT;
22 # i3 config file (v4)
23 font font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
24
25 for_window[class="mark_A"] mark A
26 for_window[class="mark_B"] mark B
27 EOT
28
29 my ($pid);
30 my ($ws, $ws1, $ws2, $ws3);
31 my ($nodes, $expected_focus, $A, $B, $F);
32 my ($result);
33 my @urgent;
34
35 $pid = launch_with_config($config);
36
37 ###############################################################################
38 # Invalid con_id should not crash i3
39 # See issue #2895.
40 ###############################################################################
41
42 $ws = fresh_workspace;
43
44 open_window;
45 cmd "swap container with con_id 1";
46
47 does_i3_live;
48 kill_all_windows;
49
50 ###############################################################################
51 # Swap 2 windows in different workspaces using con_id
52 ###############################################################################
53
54 $ws = fresh_workspace;
55 open_window;
56 $A = get_focused($ws);
57
58 $ws = fresh_workspace;
59 open_window;
60
61 cmd "swap container with con_id $A";
62 is(get_focused($ws), $A, 'A is now focused');
63
64 kill_all_windows;
65
66 ###############################################################################
67 # Swap two containers next to each other.
68 # Focus should stay on B because both windows are on the focused workspace.
69 # The focused container is B.
70 #
71 # +---+---+    Layout: H1[ A B ]
72 # | A | B |    Focus Stacks:
73 # +---+---+        H1: B, A
74 ###############################################################################
75 $ws = fresh_workspace;
76
77 $A = open_window(wm_class => 'mark_A');
78 $B = open_window(wm_class => 'mark_B');
79 $expected_focus = get_focused($ws);
80
81 cmd '[con_mark=B] swap container with mark A';
82
83 $nodes = get_ws_content($ws);
84 is($nodes->[0]->{window}, $B->{id}, 'B is on the left');
85 is($nodes->[1]->{window}, $A->{id}, 'A is on the right');
86 is(get_focused($ws), $expected_focus, 'B is still focused');
87
88 kill_all_windows;
89
90 ###############################################################################
91 # Swap two containers with different parents.
92 # In this test, the focus head of the left v-split container is A.
93 # The focused container is B.
94 #
95 # +---+---+    Layout: H1[ V1[ A Y ] V2[ X B ] ]
96 # | A | X |    Focus Stacks:
97 # +---+---+        H1: V2, V1
98 # | Y | B |        V1: A, Y
99 # +---+---+        V2: B, X
100 ###############################################################################
101 $ws = fresh_workspace;
102
103 $A = open_window(wm_class => 'mark_A');
104 $B = open_window(wm_class => 'mark_B');
105 cmd 'split v';
106 open_window;
107 cmd 'move up, focus left';
108 cmd 'split v';
109 open_window;
110 cmd 'focus up, focus right, focus down';
111 $expected_focus = get_focused($ws);
112
113 cmd '[con_mark=B] swap container with mark A';
114
115 $nodes = get_ws_content($ws);
116 is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
117 is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
118 is(get_focused($ws), $expected_focus, 'B is still focused');
119
120 kill_all_windows;
121
122 ###############################################################################
123 # Swap two containers with different parents.
124 # In this test, the focus head of the left v-split container is _not_ A.
125 # The focused container is B.
126 #
127 # +---+---+    Layout: H1[ V1[ A Y ] V2[ X B ] ]
128 # | A | X |    Focus Stacks:
129 # +---+---+        H1: V2, V1
130 # | Y | B |        V1: Y, A
131 # +---+---+        V2: B, X
132 ###############################################################################
133 $ws = fresh_workspace;
134
135 $A = open_window(wm_class => 'mark_A');
136 $B = open_window(wm_class => 'mark_B');
137 cmd 'split v';
138 open_window;
139 cmd 'move up, focus left';
140 cmd 'split v';
141 open_window;
142 cmd 'focus right, focus down';
143 $expected_focus = get_focused($ws);
144
145 cmd '[con_mark=B] swap container with mark A';
146
147 $nodes = get_ws_content($ws);
148 is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
149 is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
150 is(get_focused($ws), $expected_focus, 'B is still focused');
151
152 kill_all_windows;
153
154 ###############################################################################
155 # Swap two containers with one being on a different workspace.
156 # The focused container is B.
157 #
158 # Layout: O1[ W1[ H1 ] W2[ H2 ] ]
159 # Focus Stacks:
160 #     O1: W2, W1
161 #
162 # +---+---+    Layout: H1[ A X ]
163 # | A | X |    Focus Stacks:
164 # +---+---+        H1: A, X
165 #
166 # +---+---+    Layout: H2[ Y, B ]
167 # | Y | B |    Focus Stacks:
168 # +---+---+        H2: B, Y
169 ###############################################################################
170 $ws1 = fresh_workspace;
171 $A = open_window(wm_class => 'mark_A');
172 $expected_focus = get_focused($ws1);
173 open_window;
174 cmd 'focus left';
175
176 $ws2 = fresh_workspace;
177 open_window;
178 $B = open_window(wm_class => 'mark_B');
179
180 cmd '[con_mark=B] swap container with mark A';
181
182 $nodes = get_ws_content($ws1);
183 is($nodes->[0]->{window}, $B->{id}, 'B is on ws1:left');
184
185 $nodes = get_ws_content($ws2);
186 is($nodes->[1]->{window}, $A->{id}, 'A is on ws1:right');
187 is(get_focused($ws2), $expected_focus, 'A is focused');
188
189 kill_all_windows;
190
191 ###############################################################################
192 # Swap two non-focused containers within the same workspace.
193 #
194 # +---+---+    Layout: H1[ V1[ A X ] V2[ F B ] ]
195 # | A | F |    Focus Stacks:
196 # +---+---+        H1: V2, V1
197 # | X | B |        V1: A, X
198 # +---+---+        V2: F, B
199 ###############################################################################
200 $ws = fresh_workspace;
201
202 $A = open_window(wm_class => 'mark_A');
203 $B = open_window(wm_class => 'mark_B');
204 cmd 'split v';
205 open_window;
206 cmd 'move up, focus left';
207 cmd 'split v';
208 open_window;
209 cmd 'focus up, focus right';
210 $expected_focus = get_focused($ws);
211
212 cmd '[con_mark=B] swap container with mark A';
213
214 $nodes = get_ws_content($ws);
215 is($nodes->[0]->{nodes}->[0]->{window}, $B->{id}, 'B is on the top left');
216 is($nodes->[1]->{nodes}->[1]->{window}, $A->{id}, 'A is on the bottom right');
217 is(get_focused($ws), $expected_focus, 'F is still focused');
218
219 kill_all_windows;
220
221 ###############################################################################
222 # Swap two non-focused containers which are both on different workspaces.
223 #
224 # Layout: O1[ W1[ A ] W2[ B ] W3[ F ] ]
225 # Focus Stacks:
226 #     O1: W3, W2, W1
227 #
228 # +---+
229 # | A |
230 # +---+
231 #
232 # +---+
233 # | B |
234 # +---+
235 #
236 # +---+
237 # | F |
238 # +---+
239 ###############################################################################
240 $ws1 = fresh_workspace;
241 $A = open_window(wm_class => 'mark_A');
242
243 $ws2 = fresh_workspace;
244 $B = open_window(wm_class => 'mark_B');
245
246 $ws3 = fresh_workspace;
247 open_window;
248 $expected_focus = get_focused($ws3);
249
250 cmd '[con_mark=B] swap container with mark A';
251
252 $nodes = get_ws_content($ws1);
253 is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace');
254
255 $nodes = get_ws_content($ws2);
256 is($nodes->[0]->{window}, $A->{id}, 'A is on the second workspace');
257
258 is(get_focused($ws3), $expected_focus, 'F is still focused');
259
260 kill_all_windows;
261
262 ###############################################################################
263 # Swap two non-focused containers with one being on a different workspace.
264 #
265 # Layout: O1[ W1[ A ] W2[ H2 ] ]
266 # Focus Stacks:
267 #     O1: W2, W1
268 #
269 # +---+
270 # | A |
271 # +---+
272 #
273 # +---+---+    Layout: H2[ B, F ]
274 # | B | F |    Focus Stacks:
275 # +---+---+        H2: F, B
276 ###############################################################################
277
278 $ws1 = fresh_workspace;
279 $A = open_window(wm_class => 'mark_A');
280
281 $ws2 = fresh_workspace;
282 $B = open_window(wm_class => 'mark_B');
283 open_window;
284 $expected_focus = get_focused($ws2);
285
286 cmd '[con_mark=B] swap container with mark A';
287
288 $nodes = get_ws_content($ws1);
289 is($nodes->[0]->{window}, $B->{id}, 'B is on the first workspace');
290
291 $nodes = get_ws_content($ws2);
292 is($nodes->[0]->{window}, $A->{id}, 'A is on the left of the second workspace');
293 is(get_focused($ws2), $expected_focus, 'F is still focused');
294
295 kill_all_windows;
296
297 ###############################################################################
298 # 1. A container cannot be swapped with its parent.
299 # 2. A container cannot be swapped with one of its children.
300 #
301 #      ↓A↓
302 # +---+---+    Layout: H1[ X V1[ Y B ] ]
303 # |   | Y |        (with A := V1)
304 # | X +---+
305 # |   | B |
306 # +---+---+
307 ###############################################################################
308 $ws = fresh_workspace;
309 open_window;
310 open_window;
311 cmd 'split v';
312 $B = open_window(wm_class => 'mark_B');
313 cmd 'focus parent, mark A, focus child';
314
315 $result = cmd '[con_mark=B] swap container with mark A';
316 is($result->[0]->{success}, 0, 'B cannot be swappd with its parent');
317
318 $result = cmd '[con_mark=A] swap container with mark B';
319 is($result->[0]->{success}, 0, 'A cannot be swappd with one of its children');
320
321 kill_all_windows;
322
323 ###############################################################################
324 # Swapping two containers preserves the geometry of the container they are
325 # being swapped with.
326 #
327 # Before:
328 # +---+-------+
329 # | A |   B   |
330 # +---+-------+
331 #
332 # After:
333 # +---+-------+
334 # | B |   A   |
335 # +---+-------+
336 ###############################################################################
337 $ws = fresh_workspace;
338 $A = open_window(wm_class => 'mark_A');
339 $B = open_window(wm_class => 'mark_B');
340 cmd 'resize grow width 0 or 25 ppt';
341
342 # sanity checks
343 $nodes = get_ws_content($ws);
344 cmp_float($nodes->[0]->{percent}, 0.25, 'A has 25% width');
345 cmp_float($nodes->[1]->{percent}, 0.75, 'B has 75% width');
346
347 cmd '[con_mark=B] swap container with mark A';
348
349 $nodes = get_ws_content($ws);
350 cmp_float($nodes->[0]->{percent}, 0.25, 'B has 25% width');
351 cmp_float($nodes->[1]->{percent}, 0.75, 'A has 75% width');
352
353 kill_all_windows;
354
355 ###############################################################################
356 # Swapping containers not sharing the same parent preserves the geometry of
357 # the container they are swapped with.
358 #
359 # Before:
360 # +---+-----+
361 # | A |     |
362 # +---+  B  |
363 # |   |     |
364 # | Y +-----+
365 # |   |  X  |
366 # +---+-----+
367 #
368 # After:
369 # +---+-----+
370 # | B |     |
371 # +---+  A  |
372 # |   |     |
373 # | Y +-----+
374 # |   |  X  |
375 # +---+-----+
376 ###############################################################################
377 $ws = fresh_workspace;
378
379 $A = open_window(wm_class => 'mark_A');
380 $B = open_window(wm_class => 'mark_B');
381 cmd 'split v';
382 open_window;
383 cmd 'focus up, resize grow height 0 or 25 ppt';
384 cmd 'focus left, split v';
385 open_window;
386 cmd 'resize grow height 0 or 25 ppt';
387
388 # sanity checks
389 $nodes = get_ws_content($ws);
390 cmp_float($nodes->[0]->{nodes}->[0]->{percent}, 0.25, 'A has 25% height');
391 cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.75, 'B has 75% height');
392
393 cmd '[con_mark=B] swap container with mark A';
394
395 $nodes = get_ws_content($ws);
396 cmp_float($nodes->[0]->{nodes}->[0]->{percent}, 0.25, 'B has 25% height');
397 cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.75, 'A has 75% height');
398
399 kill_all_windows;
400
401 ###############################################################################
402 # Swapping containers moves the urgency hint correctly.
403 ###############################################################################
404
405 $ws1 = fresh_workspace;
406 $A = open_window(wm_class => 'mark_A');
407 $ws2 = fresh_workspace;
408 $B = open_window(wm_class => 'mark_B');
409 open_window;
410
411 $B->add_hint('urgency');
412 sync_with_i3;
413
414 cmd '[con_mark=B] swap container with mark A';
415
416 @urgent = grep { $_->{urgent} } @{get_ws_content($ws1)};
417 is(@urgent, 1, 'B is marked urgent');
418 is(get_ws($ws1)->{urgent}, 1, 'the first workspace is marked urgent');
419
420 @urgent = grep { $_->{urgent} } @{get_ws_content($ws2)};
421 is(@urgent, 0, 'A is not marked urgent');
422 is(get_ws($ws2)->{urgent}, 0, 'the second workspace is not marked urgent');
423
424 kill_all_windows;
425
426 ###############################################################################
427
428 exit_gracefully($pid);
429
430 done_testing;