1import pytest 2 3 4def test_default_monitor(hlwm): 5 assert hlwm.get_attr('monitors.count') == '1' 6 assert hlwm.get_attr('monitors.focus.name') == '' 7 assert hlwm.get_attr('monitors.focus.index') == '0' 8 9 10def test_add_monitor_requires_unfocused_tag(hlwm): 11 hlwm.call_xfail('add_monitor 800x600+40+40 default monitor2') 12 13 assert hlwm.get_attr('monitors.count') == '1' 14 assert hlwm.get_attr('monitors.focus.name') == '' 15 assert hlwm.get_attr('monitors.focus.index') == '0' 16 17 18def test_add_monitor(hlwm): 19 hlwm.call('add tag2') 20 21 hlwm.call('add_monitor 800x600+40+40 tag2 monitor2') 22 23 assert hlwm.get_attr('monitors.count') == '2' 24 assert hlwm.get_attr('monitors.1.name') == 'monitor2' 25 26 27def test_add_monitor_with_no_name(hlwm): 28 hlwm.call('add tag2') 29 30 hlwm.call('add_monitor 800x600+40+40 tag2') 31 32 assert hlwm.get_attr('monitors.count') == '2' 33 assert hlwm.get_attr('monitors.1.name') == '' 34 35 36def test_cannot_add_monitor_without_free_tag(hlwm): 37 call = hlwm.call_xfail('add_monitor 800x600+40+40') 38 assert call.stderr == 'add_monitor: There are not enough free tags\n' 39 assert hlwm.get_attr('monitors.count') == '1' 40 41 42def test_cannot_add_monitor_with_nonexistent_tag(hlwm): 43 call = hlwm.call_xfail('add_monitor 800x600+40+40 derp') 44 assert call.stderr == 'add_monitor: Tag "derp" does not exist\n' 45 assert hlwm.get_attr('monitors.count') == '1' 46 47 48def test_cannot_add_monitor_with_already_viewed_tag(hlwm): 49 hlwm.call('add tag2') 50 call = hlwm.call_xfail('add_monitor 800x600+40+40 default') 51 assert call.stderr == 'add_monitor: Tag "default" is already being viewed on a monitor\n' 52 assert hlwm.get_attr('monitors.count') == '1' 53 54 55def test_cannot_add_monitor_with_numeric_name(hlwm): 56 hlwm.call('add tag2') 57 call = hlwm.call_xfail('add_monitor 800x600+40+40 tag2 123foo') 58 assert call.stderr == 'add_monitor: Invalid name "123foo": The monitor name may not start with a number\n' 59 assert hlwm.get_attr('monitors.count') == '1' 60 61 62def test_cannot_add_monitor_with_empty_name(hlwm): 63 hlwm.call('add tag2') 64 call = hlwm.call_xfail('add_monitor 800x600+40+40 tag2 ""') 65 assert call.stderr == 'add_monitor: An empty monitor name is not permitted\n' 66 assert hlwm.get_attr('monitors.count') == '1' 67 68 69def test_cannot_add_monitor_with_existing_name(hlwm): 70 hlwm.call('rename_monitor 0 mon1') 71 hlwm.call('add tag2') 72 call = hlwm.call_xfail('add_monitor 800x600+40+40 tag2 mon1') 73 assert call.stderr == 'add_monitor: A monitor with the name "mon1" already exists\n' 74 assert hlwm.get_attr('monitors.count') == '1' 75 76 77def test_remove_monitor(hlwm): 78 hlwm.call('add tag2') 79 hlwm.call('add_monitor 800x600+40+40 tag2 monitor2') 80 81 hlwm.call('remove_monitor 0') 82 83 assert hlwm.get_attr('monitors.0.index') == '0' 84 assert hlwm.get_attr('monitors.count') == '1' 85 assert hlwm.get_attr('monitors.focus.name') == 'monitor2' 86 87 88def test_cannot_remove_nonexistent_monitor(hlwm): 89 call = hlwm.call_xfail('remove_monitor 1') 90 assert call.stderr == 'remove_monitor: Monitor "1" not found!\n' 91 assert hlwm.get_attr('monitors.count') == '1' 92 93 94def test_cannot_remove_last_monitor(hlwm): 95 call = hlwm.call_xfail('remove_monitor 0') 96 assert call.stderr == 'remove_monitor: Can\'t remove the last monitor\n' 97 assert hlwm.get_attr('monitors.count') == '1' 98 99 100def test_move_monitor(hlwm): 101 r = [8, 4, 400, 300] # x,y,width,height 102 hlwm.call('move_monitor \"0\" %dx%d%+d%+d' % (r[2], r[3], r[0], r[1])) 103 assert hlwm.call('monitor_rect \"\"').stdout == ' '.join(map(str, r)) 104 105 106def test_focus_monitor(hlwm): 107 hlwm.call('add tag2') 108 hlwm.call('add_monitor 800x600+40+40') 109 assert hlwm.get_attr('monitors.focus.index') == '0' 110 assert hlwm.get_attr('tags.focus.index') == '0' 111 112 hlwm.call('focus_monitor 1') 113 114 assert hlwm.get_attr('monitors.focus.index') == '1' 115 assert hlwm.get_attr('tags.focus.index') == '1' 116 117 118def test_new_clients_appear_in_focused_monitor(hlwm): 119 hlwm.call('add tag2') 120 hlwm.call('add_monitor 800x600+40+40 tag2 monitor2') 121 hlwm.call('focus_monitor monitor2') 122 123 winid, _ = hlwm.create_client() 124 125 assert hlwm.get_attr('tags.by-name.tag2.client_count') == '1' 126 assert hlwm.get_attr('tags.by-name.default.client_count') == '0' 127 assert hlwm.get_attr('clients', winid, 'tag') == 'tag2' 128 129 130@pytest.mark.parametrize("arg", ['-l', '--list-all', '--no-disjoin']) 131def test_detect_monitors_does_not_crash(hlwm, arg): 132 # I don't know how to test detect_monitors properly, so just check that 133 # it does not crash at least 134 hlwm.call(['detect_monitors', arg]) 135 136 137def test_detect_monitors_affects_list_monitors(hlwm): 138 list_monitors_before = hlwm.call('list_monitors').stdout 139 hlwm.call('add othertag') 140 hlwm.call('set_monitors 80x80+5+5 80x80+85+5') 141 assert hlwm.get_attr('monitors.count') == '2' 142 assert list_monitors_before != hlwm.call('list_monitors').stdout 143 144 # check that detect monitors restores the one monitor 145 hlwm.call('detect_monitors') 146 147 assert hlwm.get_attr('monitors.count') == '1' 148 assert list_monitors_before == hlwm.call('list_monitors').stdout 149 150 151def test_rename_monitor(hlwm): 152 hlwm.call('rename_monitor 0 foo') 153 154 assert hlwm.get_attr('monitors.focus.name') == 'foo' 155 assert hlwm.list_children('monitors.by-name') == ['foo'] 156 157 158def test_rename_monitor_no_name(hlwm): 159 hlwm.call('rename_monitor 0 foo') 160 161 hlwm.call('rename_monitor foo ""') 162 163 assert hlwm.get_attr('monitors.focus.name') == '' 164 assert hlwm.list_children('monitors.by-name') == [] 165 166 167@pytest.mark.parametrize("tag_count", [1, 2, 3, 4]) 168@pytest.mark.parametrize("monitor_count", [1, 2, 3, 4]) 169def test_set_monitors_create_monitors(hlwm, tag_count, monitor_count): 170 for i in range(1, tag_count): 171 hlwm.call('add tag{}'.format(i)) 172 rects = ['100x200+{}+0'.format(100 * i) for i in range(0, monitor_count)] 173 174 if tag_count < monitor_count: 175 hlwm.call_xfail(['set_monitors'] + rects) \ 176 .expect_stderr('There are not enough free tags') 177 else: 178 hlwm.call(['set_monitors'] + rects) 179 180 assert int(hlwm.get_attr('monitors.count')) == monitor_count 181 monitors = hlwm.call('list_monitors').stdout.splitlines() 182 assert rects == [s.split(' ')[1] for s in monitors] 183 184 185@pytest.mark.parametrize("monitor_count_before", [1, 2, 3]) 186def test_set_monitors_removes_monitors(hlwm, monitor_count_before): 187 for i in range(1, monitor_count_before): 188 hlwm.call('add tag{}'.format(i)) 189 hlwm.call('add_monitor 100x200+{}+0'.format(100 * i)) 190 # focus the last monitor 191 hlwm.call('focus_monitor {}'.format(monitor_count_before - 1)) 192 193 hlwm.call(['set_monitors', '100x200+100+0']) 194 195 assert hlwm.get_attr('monitors.count') == '1' 196 monitors = hlwm.call('list_monitors').stdout 197 assert monitors == '0: 100x200+100+0 with tag "default" [FOCUS]\n' 198 199 200def test_raise_monitor_completion(hlwm): 201 hlwm.call('add tag2') 202 hlwm.call('add_monitor 800x600+40+40 tag2 monitor2') 203 204 expected = [''] 205 expected += '-1 +0 +1 0 1 monitor2'.split(' ') 206 expected.sort() 207 assert hlwm.complete('raise_monitor') == expected 208 209 210def test_use_previous_on_tag_stealing_monitor(hlwm): 211 hlwm.call('add tag2') 212 hlwm.call('add tag3') 213 hlwm.call('add_monitor 800x600+40+40 tag3 monitor2') 214 215 hlwm.call('use tag2') 216 hlwm.call('use tag3') # steal it from monitor2 217 hlwm.call('use_previous') 218 219 assert hlwm.get_attr('tags.focus.name') == 'tag2' 220 221 222def test_use_previous_on_stolen_monitor(hlwm): 223 hlwm.call('add tag2') 224 hlwm.call('add tag3') 225 hlwm.call('add tag4') 226 hlwm.call('add_monitor 800x600+40+40 tag4 monitor2') 227 hlwm.call('focus_monitor monitor2') 228 hlwm.call('use tag3') 229 hlwm.call('focus_monitor 0') 230 231 hlwm.call('use tag2') 232 hlwm.call('use tag3') # steal it from monitor2 233 hlwm.call('focus_monitor monitor2') 234 hlwm.call('use_previous') 235 236 assert hlwm.get_attr('tags.focus.name') == 'tag3' 237 238 239@pytest.mark.parametrize("two_monitors", [True, False]) 240def test_initial_client_position(hlwm, x11, two_monitors): 241 # create two monitors side by side (with a little y-offset) 242 if two_monitors: 243 hlwm.call('add other') 244 hlwm.call('set_monitors 173x174+4+5 199x198+200+100') 245 hlwm.call('focus_monitor 1') 246 hlwm.call('set_attr theme.border_width 0') # disable border 247 # add pad to the focused monitor and set its tag to floating 248 hlwm.call('pad +0 12 13 14 15') 249 hlwm.call('floating on') 250 251 # create a new window in the area of the second monitor. 252 g = (250, 160, 81, 82) # x, y, width, height 253 w, winid = x11.create_client(geometry=g) 254 assert int(hlwm.get_attr('tags.focus.client_count')) == 1 255 256 # check that the new client has the desired geometry 257 win_geo = w.get_geometry() 258 assert (win_geo.width, win_geo.height) == (g[2], g[3]) 259 x, y = x11.get_absolute_top_left(w) 260 assert (x, y) == (g[0], g[1]) 261 262 263def test_shift_to_monitor(hlwm): 264 hlwm.call('add tag2') 265 hlwm.call('set_monitors 80x80+0+0 80x80+80+0') 266 winid, _ = hlwm.create_client() 267 oldtag = hlwm.get_attr('monitors.0.tag') 268 assert hlwm.get_attr(f'clients.{winid}.tag') == oldtag 269 270 hlwm.call('shift_to_monitor 1') 271 272 newtag = hlwm.get_attr('monitors.1.tag') 273 assert oldtag != newtag 274 assert hlwm.get_attr(f'clients.{winid}.tag') == newtag 275 276 277def test_shift_to_monitor_invalid_mon(hlwm): 278 winid, _ = hlwm.create_client() 279 hlwm.call_xfail('shift_to_monitor 34') \ 280 .expect_stderr('Invalid monitor') 281 282 283def test_shift_to_monitor_no_client(hlwm): 284 hlwm.call('add tag2') 285 hlwm.call('set_monitors 80x80+0+0 80x80+80+0') 286 287 # there is no error message at the moment, so we only 288 # check that it does not crash 289 hlwm.call('shift_to_monitor 1') 290 291 292def test_invalid_monitor_name(hlwm): 293 cmds = [ 294 'list_padding', 'move_monitor', 295 'rename_monitor', 'lock_tag', 'unlock_tag' 296 ] 297 for command in cmds: 298 hlwm.call_xfail([command, 'thismonitordoesnotexist']) \ 299 .expect_stderr('Monitor "thismonitordoesnotexist" not found') 300 301 302def test_list_padding(hlwm): 303 hlwm.call('add othertag') 304 hlwm.call('add_monitor 800x600+600+0') 305 pad0 = '5 20 3 30' 306 pad1 = '1 2 4 8' 307 hlwm.call('pad 0 ' + pad0) 308 hlwm.call('pad 1 ' + pad1) 309 310 # this is a very primitive command, so we directly test multiple things at once 311 assert hlwm.call('list_padding 0').stdout == pad0 + '\n' 312 assert hlwm.call('list_padding 1').stdout == pad1 + '\n' 313 314 assert hlwm.call('list_padding').stdout == pad0 + '\n' 315 hlwm.call('focus_monitor 1') 316 assert hlwm.call('list_padding').stdout == pad1 + '\n' 317 318 319def test_list_padding_invalid_monitor(hlwm): 320 hlwm.call_xfail('list_padding 23') \ 321 .expect_stderr('Monitor.*not found') 322 323 324@pytest.mark.parametrize("mon_num,focus_idx", [ 325 (num, focus) for num in [1, 2, 3, 4, 5] for focus in [0, num - 1]]) 326@pytest.mark.parametrize("delta", ['-1', '+1']) 327@pytest.mark.parametrize("command", ['cycle_monitor', 'focus_monitor']) 328def test_cycle_monitor(hlwm, mon_num, focus_idx, delta, command): 329 """the present test also tests the MOD() function in utility.cpp""" 330 for i in range(1, mon_num): 331 hlwm.call('add tag' + str(i)) 332 hlwm.call('add_monitor 800x600+' + str(i * 10)) 333 hlwm.call(['focus_monitor', str(focus_idx)]) 334 assert hlwm.get_attr('monitors.focus.index') == str(focus_idx) 335 assert hlwm.get_attr('monitors.count') == str(mon_num) 336 337 hlwm.call([command, delta]) 338 339 new_index = (focus_idx + int(delta) + mon_num) % mon_num 340 assert hlwm.get_attr('monitors.focus.index') == str(new_index) 341 342 343@pytest.mark.parametrize("lock_tag_cmd", [ 344 lambda index: ['lock_tag', str(index)], 345 lambda index: ['set_attr', f'monitors.{index}.lock_tag', 'on'] 346]) 347def test_lock_tag_switch_away(hlwm, lock_tag_cmd): 348 hlwm.call('add tag1') 349 hlwm.call('add tag2') 350 hlwm.call('set_monitors 800x600+0+0 800x600+800+0') 351 hlwm.call(lock_tag_cmd(0)) 352 assert hlwm.attr.monitors[0].lock_tag() == hlwm.bool(True) 353 354 hlwm.call('focus_monitor 0') 355 356 # can not switch to another tag on the locked monitor 357 hlwm.call_xfail('use tag2') \ 358 .expect_stderr('Could not change .*monitor 0 is locked') 359 360 361@pytest.mark.parametrize("locked", [True, False]) 362def test_lock_tag_switch_to_locked(hlwm, locked): 363 hlwm.call('add tag1') 364 hlwm.call('add tag2') 365 hlwm.call('set_monitors 800x600+0+0 800x600+800+0') 366 hlwm.call('set swap_monitors_to_get_tag on') 367 368 hlwm.attr.monitors[0].lock_tag = hlwm.bool(locked) 369 hlwm.call('focus_monitor 1') 370 371 # being on monitor 1, try to focus the tag on monitor 0 372 tag_on_locked_monitor = hlwm.attr.monitors[0].tag() 373 hlwm.call(['use', tag_on_locked_monitor]) 374 375 if locked: 376 # if the monitor was locked, then the tag stays 377 # on monitor 0 378 expected_monitor_index = '0' 379 else: 380 # otherwise, the tag is moved to monitor 1 because 381 # of swap_monitors_to_get_tag 382 expected_monitor_index = '1' 383 assert hlwm.attr.tags.focus.name() == tag_on_locked_monitor 384 assert hlwm.attr.monitors.focus.index() == expected_monitor_index 385 386 387def test_lock_tag_command_vs_attribute(hlwm): 388 hlwm.call('add anothertag') 389 hlwm.call('set_monitors 800x600+0+0 800x600+800+0') 390 hlwm.call('focus_monitor 1') 391 392 # no argument modifies the attribute of the focused monitor 393 hlwm.call('lock_tag') 394 assert hlwm.attr.monitors[1].lock_tag() == hlwm.bool(True) 395 hlwm.call('unlock_tag') 396 assert hlwm.attr.monitors[1].lock_tag() == hlwm.bool(False) 397 398 hlwm.call('lock_tag 0') 399 assert hlwm.attr.monitors[0].lock_tag() == hlwm.bool(True) 400 hlwm.call('unlock_tag 0') 401 assert hlwm.attr.monitors[0].lock_tag() == hlwm.bool(False) 402 403 404def test_monitor_rect_too_small(hlwm): 405 hlwm.call_xfail('attr monitors.0.geometry 20x300+0+0') \ 406 .expect_stderr('too small.*wide') 407 hlwm.call_xfail('attr monitors.0.geometry 400x30+0+0') \ 408 .expect_stderr('too small.*high') 409 410 411def test_monitor_rect_is_updated(hlwm): 412 for rect in ['500x300+30+40', '500x300-30+40', '500x300+30-40', '500x300-30-40']: 413 hlwm.call(['move_monitor', 0, rect]) 414 assert hlwm.attr.monitors[0].geometry() == rect 415 416 417def test_monitor_rect_parser(hlwm): 418 for rect in [(400, 800, a * 40, b * 60) for a in [1, -1] for b in [1, -1]]: 419 420 hlwm.attr.monitors[0].geometry = '%dx%d%+d%+d' % rect 421 422 expected_output = ' '.join([str(rect[i]) for i in [2, 3, 0, 1]]) 423 assert hlwm.call('monitor_rect 0').stdout.strip() == expected_output 424 425 426def test_monitor_rect_apply_layout(hlwm, x11): 427 winhandle, winid = x11.create_client() 428 hlwm.attr.clients[winid].fullscreen = 'on' 429 for expected_geometry in [(600, 700, 40, 50), (400, 800, -10, 0)]: 430 hlwm.attr.monitors[0].geometry = '%dx%d%+d%+d' % expected_geometry 431 432 x11.display.sync() 433 geom = x11.get_absolute_geometry(winhandle) 434 assert (geom.width, geom.height, geom.x, geom.y) == expected_geometry 435