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