]> git.sur5r.net Git - i3/i3/blob - testcases/t/165-for_window.t
Added new criteria 'tiling' / 'floating'. (#2481)
[i3/i3] / testcases / t / 165-for_window.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 use i3test i3_autostart => 0;
18 use X11::XCB qw(PROP_MODE_REPLACE);
19
20 my (@nodes);
21
22 ##############################################################
23 # 1: test the following directive:
24 #    for_window [class="borderless"] border none
25 # by first creating a window with a different class (should get
26 # the normal border), then creating a window with the class
27 # "borderless" (should get no border)
28 ##############################################################
29
30 my $config = <<EOT;
31 # i3 config file (v4)
32 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
33 for_window [class="borderless"] border none
34 for_window [title="special borderless title"] border none
35 EOT
36
37 my $pid = launch_with_config($config);
38
39 my $tmp = fresh_workspace;
40
41 my $window = open_window(name => 'Border window');
42
43 my @content = @{get_ws_content($tmp)};
44 cmp_ok(@content, '==', 1, 'one node on this workspace now');
45 is($content[0]->{border}, 'normal', 'normal border');
46
47 $window->unmap;
48 wait_for_unmap $window;
49
50 @content = @{get_ws_content($tmp)};
51 cmp_ok(@content, '==', 0, 'no more nodes');
52 diag('content = '. Dumper(\@content));
53
54 $window = open_window(
55     name => 'Borderless window',
56     wm_class => 'borderless',
57 );
58
59 @content = @{get_ws_content($tmp)};
60 cmp_ok(@content, '==', 1, 'one node on this workspace now');
61 is($content[0]->{border}, 'none', 'no border');
62
63 $window->unmap;
64 wait_for_unmap $window;
65
66 @content = @{get_ws_content($tmp)};
67 cmp_ok(@content, '==', 0, 'no more nodes');
68
69 exit_gracefully($pid);
70
71 ##############################################################
72 # 2: match on the title, check if for_window is really executed
73 # only once
74 ##############################################################
75
76 $config = <<EOT;
77 # i3 config file (v4)
78 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
79 for_window [class="borderless"] border none
80 for_window [title="special borderless title"] border none
81 EOT
82
83 $pid = launch_with_config($config);
84
85 $tmp = fresh_workspace;
86
87 $window = open_window(name => 'special title');
88
89 @content = @{get_ws_content($tmp)};
90 cmp_ok(@content, '==', 1, 'one node on this workspace now');
91 is($content[0]->{border}, 'normal', 'normal border');
92
93 $window->name('special borderless title');
94 sync_with_i3;
95
96 @content = @{get_ws_content($tmp)};
97 is($content[0]->{border}, 'none', 'no border');
98
99 $window->name('special title');
100 sync_with_i3;
101
102 cmd 'border normal';
103
104 @content = @{get_ws_content($tmp)};
105 is($content[0]->{border}, 'normal', 'border reset to normal');
106
107 $window->name('special borderless title');
108 sync_with_i3;
109
110 @content = @{get_ws_content($tmp)};
111 is($content[0]->{border}, 'normal', 'still normal border');
112
113 $window->unmap;
114 wait_for_unmap $window;
115
116 @content = @{get_ws_content($tmp)};
117 cmp_ok(@content, '==', 0, 'no more nodes');
118
119 exit_gracefully($pid);
120
121 ##############################################################
122 # 3: match on the title, set border style *and* a mark
123 ##############################################################
124
125 $config = <<EOT;
126 # i3 config file (v4)
127 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
128 for_window [class="borderless" title="usethis"] border none
129 for_window [class="borderless"] border none
130 for_window [title="special borderless title"] border none
131 for_window [title="special mark title"] border none, mark bleh
132 EOT
133
134 $pid = launch_with_config($config);
135
136 $tmp = fresh_workspace;
137
138 $window = open_window(name => 'special mark title');
139
140 @content = @{get_ws_content($tmp)};
141 cmp_ok(@content, '==', 1, 'one node on this workspace now');
142 is($content[0]->{border}, 'none', 'no border');
143
144 my $other = open_window;
145
146 @content = @{get_ws_content($tmp)};
147 cmp_ok(@content, '==', 2, 'two nodes');
148 is($content[0]->{border}, 'none', 'no border');
149 is($content[1]->{border}, 'normal', 'normal border');
150 ok(!$content[0]->{focused}, 'first one not focused');
151
152 cmd qq|[con_mark="bleh"] focus|;
153
154 @content = @{get_ws_content($tmp)};
155 ok($content[0]->{focused}, 'first node focused');
156
157 exit_gracefully($pid);
158
159 ##############################################################
160 # 4: multiple criteria for the for_window command
161 ##############################################################
162
163 $config = <<EOT;
164 # i3 config file (v4)
165 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
166 for_window [class="borderless" title="usethis"] border none
167 EOT
168
169 $pid = launch_with_config($config);
170
171 $tmp = fresh_workspace;
172
173 $window = open_window(
174     name => 'usethis',
175     wm_class => 'borderless',
176 );
177
178 @content = @{get_ws_content($tmp)};
179 cmp_ok(@content, '==', 1, 'one node on this workspace now');
180 is($content[0]->{border}, 'none', 'no border');
181
182 cmd 'kill';
183 wait_for_unmap $window;
184 $window->destroy;
185
186 # give i3 a chance to delete the window from its tree
187 sync_with_i3;
188
189 @content = @{get_ws_content($tmp)};
190 cmp_ok(@content, '==', 0, 'no nodes on this workspace now');
191
192 $window->_create;
193 $window->wm_class('borderless');
194 $window->name('notthis');
195 $window->map;
196 wait_for_map $window;
197
198 @content = @{get_ws_content($tmp)};
199 cmp_ok(@content, '==', 1, 'one node on this workspace now');
200 is($content[0]->{border}, 'normal', 'no border');
201
202
203 exit_gracefully($pid);
204
205 ##############################################################
206 # 5: check that a class criterion does not match the instance
207 ##############################################################
208
209 $config = <<EOT;
210 # i3 config file (v4)
211 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
212 for_window [class="foo"] border 1pixel
213 EOT
214
215 $pid = launch_with_config($config);
216
217 $tmp = fresh_workspace;
218
219
220 $window = open_window(
221     name => 'usethis',
222     wm_class => 'bar',
223     instance => 'foo',
224 );
225
226 @content = @{get_ws_content($tmp)};
227 cmp_ok(@content, '==', 1, 'one node on this workspace now');
228 is($content[0]->{border}, 'normal', 'normal border, not matched');
229
230 exit_gracefully($pid);
231
232 ##############################################################
233 # 6: check that the 'instance' criterion works
234 ##############################################################
235
236 $config = <<EOT;
237 # i3 config file (v4)
238 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
239 for_window [class="foo"] border 1pixel
240 for_window [instance="foo"] border none
241 EOT
242
243 $pid = launch_with_config($config);
244
245 $tmp = fresh_workspace;
246
247 $window = open_window(
248     name => 'usethis',
249     wm_class => 'bar',
250     instance => 'foo',
251 );
252
253 @content = @{get_ws_content($tmp)};
254 cmp_ok(@content, '==', 1, 'one node on this workspace now');
255 is($content[0]->{border}, 'none', 'no border');
256
257 exit_gracefully($pid);
258
259 ##############################################################
260 # 7: check that invalid criteria don’t end up matching all windows
261 ##############################################################
262
263 # this configuration is broken because "asdf" is not a valid integer
264 # the for_window should therefore recognize this error and don’t add the
265 # assignment
266 $config = <<EOT;
267 # i3 config file (v4)
268 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
269 for_window [id="asdf"] border none
270 EOT
271
272 $pid = launch_with_config($config);
273
274 $tmp = fresh_workspace;
275
276 $window = open_window(
277     name => 'usethis',
278     wm_class => 'bar',
279     instance => 'foo',
280 );
281
282 @content = @{get_ws_content($tmp)};
283 cmp_ok(@content, '==', 1, 'one node on this workspace now');
284 is($content[0]->{border}, 'normal', 'normal border');
285
286 exit_gracefully($pid);
287
288 ##############################################################
289 # 8: check that the role criterion works properly
290 ##############################################################
291
292 $config = <<EOT;
293 # i3 config file (v4)
294 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
295 for_window [window_role="i3test"] border none
296 EOT
297
298 $pid = launch_with_config($config);
299
300 $tmp = fresh_workspace;
301
302 $window = open_window(
303     name => 'usethis',
304     before_map => sub {
305         my ($window) = @_;
306         my $atomname = $x->atom(name => 'WM_WINDOW_ROLE');
307         my $atomtype = $x->atom(name => 'STRING');
308         $x->change_property(
309             PROP_MODE_REPLACE,
310             $window->id,
311             $atomname->id,
312             $atomtype->id,
313             8,
314             length("i3test") + 1,
315             "i3test\x00"
316         );
317     },
318 );
319
320 @content = @{get_ws_content($tmp)};
321 cmp_ok(@content, '==', 1, 'one node on this workspace now');
322 is($content[0]->{border}, 'none', 'no border (window_role)');
323
324 exit_gracefully($pid);
325
326 ##############################################################
327 # 9: another test for the window_role, but this time it changes
328 #    *after* the window has been mapped
329 ##############################################################
330
331 $config = <<EOT;
332 # i3 config file (v4)
333 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
334 for_window [window_role="i3test"] border none
335 EOT
336
337 $pid = launch_with_config($config);
338
339 $tmp = fresh_workspace;
340
341 $window = open_window(name => 'usethis');
342
343 @content = @{get_ws_content($tmp)};
344 cmp_ok(@content, '==', 1, 'one node on this workspace now');
345 is($content[0]->{border}, 'normal', 'normal border (window_role 2)');
346
347 my $atomname = $x->atom(name => 'WM_WINDOW_ROLE');
348 my $atomtype = $x->atom(name => 'STRING');
349 $x->change_property(
350   PROP_MODE_REPLACE,
351   $window->id,
352   $atomname->id,
353   $atomtype->id,
354   8,
355   length("i3test") + 1,
356   "i3test\x00"
357 );
358
359 $x->flush;
360
361 sync_with_i3;
362
363 @content = @{get_ws_content($tmp)};
364 cmp_ok(@content, '==', 1, 'one node on this workspace now');
365 is($content[0]->{border}, 'none', 'no border (window_role 2)');
366
367 exit_gracefully($pid);
368
369 ##############################################################
370 # 10: check that the criterion 'window_type' works
371 ##############################################################
372
373 # test all window types
374 my %window_types = (
375     'normal'        => '_NET_WM_WINDOW_TYPE_NORMAL',
376     'dialog'        => '_NET_WM_WINDOW_TYPE_DIALOG',
377     'utility'       => '_NET_WM_WINDOW_TYPE_UTILITY',
378     'toolbar'       => '_NET_WM_WINDOW_TYPE_TOOLBAR',
379     'splash'        => '_NET_WM_WINDOW_TYPE_SPLASH',
380     'menu'          => '_NET_WM_WINDOW_TYPE_MENU',
381     'dropdown_menu' => '_NET_WM_WINDOW_TYPE_DROPDOWN_MENU',
382     'popup_menu'    => '_NET_WM_WINDOW_TYPE_POPUP_MENU',
383     'tooltip'       => '_NET_WM_WINDOW_TYPE_TOOLTIP',
384     'notification'  => '_NET_WM_WINDOW_TYPE_NOTIFICATION'
385 );
386
387 while (my ($window_type, $atom) = each %window_types) {
388
389     $config = <<"EOT";
390 # i3 config file (v4)
391 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
392 for_window [window_type="$window_type"] floating enable, mark branded
393 EOT
394
395     $pid = launch_with_config($config);
396     $tmp = fresh_workspace;
397
398     $window = open_window(window_type => $x->atom(name => $atom));
399
400     my @nodes = @{get_ws($tmp)->{floating_nodes}};
401     cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
402     is_deeply($nodes[0]->{nodes}[0]->{marks}, [ 'branded' ], "mark set (window_type = $atom)");
403
404     exit_gracefully($pid);
405
406 }
407
408 ##############################################################
409 # 11: check that the criterion 'window_type' works if the
410 #     _NET_WM_WINDOW_TYPE is changed after managing.
411 ##############################################################
412
413 while (my ($window_type, $atom) = each %window_types) {
414
415     $config = <<"EOT";
416 # i3 config file (v4)
417 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
418 for_window [window_type="$window_type"] floating enable, mark branded
419 EOT
420
421     $pid = launch_with_config($config);
422     $tmp = fresh_workspace;
423
424     $window = open_window();
425
426     my $atomname = $x->atom(name => '_NET_WM_WINDOW_TYPE');
427     my $atomtype = $x->atom(name => 'ATOM');
428     $x->change_property(PROP_MODE_REPLACE, $window->id, $atomname->id, $atomtype->id,
429       32, 1, pack('L1', $x->atom(name => $atom)->id));
430     $x->flush;
431     sync_with_i3;
432
433     my @nodes = @{get_ws($tmp)->{floating_nodes}};
434     cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
435     is_deeply($nodes[0]->{nodes}[0]->{marks}, [ 'branded' ], "mark set (window_type = $atom)");
436
437     exit_gracefully($pid);
438
439 }
440
441 ##############################################################
442 # 12: check that the criterion 'workspace' works
443 ##############################################################
444
445 $config = <<"EOT";
446 # i3 config file (v4)
447 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
448 for_window [workspace="trigger"] floating enable, mark triggered
449 EOT
450
451 $pid = launch_with_config($config);
452
453 cmd 'workspace trigger';
454 $window = open_window;
455
456 @nodes = @{get_ws('trigger')->{floating_nodes}};
457 cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
458 is_deeply($nodes[0]->{nodes}[0]->{marks}, [ 'triggered' ], "mark set for workspace criterion");
459
460 exit_gracefully($pid);
461
462 ##############################################################
463 # 13: check that the tiling / floating criteria work.
464 ##############################################################
465
466 $config = <<"EOT";
467 # i3 config file (v4)
468 font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
469 for_window [tiling] mark tiled
470 for_window [floating] mark floated
471 EOT
472
473 $pid = launch_with_config($config);
474 $tmp = fresh_workspace;
475
476 open_window;
477 open_floating_window;
478
479 @nodes = @{get_ws($tmp)->{nodes}};
480 cmp_ok(@nodes, '==', 1, 'one tiling container on this workspace');
481 is_deeply($nodes[0]->{marks}, [ 'tiled' ], "mark set for 'tiling' criterion");
482
483 @nodes = @{get_ws($tmp)->{floating_nodes}};
484 cmp_ok(@nodes, '==', 1, 'one floating container on this workspace');
485 is_deeply($nodes[0]->{nodes}[0]->{marks}, [ 'floated' ], "mark set for 'floating' criterion");
486
487 exit_gracefully($pid);
488
489 ##############################################################
490
491 done_testing;