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