Example #1
0
def test_drag_resize_floating_client(hlwm, x11, mouse, live_update):
    hlwm.attr.settings.update_dragged_clients = hlwm.bool(live_update)

    client, winid = x11.create_client(geometry=(50, 50, 300, 200))
    hlwm.call(f'set_attr clients.{winid}.floating true')
    geom_before = Rectangle.from_user_str(hlwm.attr.clients[winid].geometry_reported())
    assert geom_before == x11.get_absolute_geometry(client)  # duck-typing
    assert (geom_before.width, geom_before.height) == (300, 200)
    # move cursor to the top left corner, so we change the
    # window position and the size (and the bottom right corner is fixed)
    # Just positioning the mouse pointer, no need to wait for hlwm
    mouse.move_into(winid, x=0, y=0, wait=False)

    hlwm.call(['drag', winid, 'resize'])
    assert hlwm.get_attr('clients.dragged.winid') == winid
    mouse.move_relative(100, 120)
    final_size = (geom_before.width - 100, geom_before.height - 120)

    # check geometry during drag
    x11.display.sync()
    geom_after = client.get_geometry()
    x_after, y_after = x11.get_absolute_top_left(client)
    assert (x_after, y_after) == (geom_before.x + 100, geom_before.y + 120)
    expected_size = (geom_before.width, geom_before.height)
    if live_update:
        expected_size = final_size
    assert (geom_after.width, geom_after.height) == expected_size

    # stop drag and check final size
    mouse.click('1', wait=True)
    geom_after = client.get_geometry()
    assert (geom_after.width, geom_after.height) == final_size
    assert Rectangle.from_user_str(hlwm.attr.clients[winid].geometry_reported()) \
        == geom_before.adjusted(dx=100, dy=120, dw=-100, dh=-120)
def test_sizehint_change_applied(hlwm, x11, floating):
    hlwm.attr.tags.focus.floating = floating
    # create a client with a geometry that does not match the sizehints
    # we will set later
    handle, winid = x11.create_client()
    old_geometry = Rectangle(x=30, y=40, width=111, height=121)
    hlwm.attr.clients[winid].floating_geometry = old_geometry
    if floating:
        assert hlwm.attr.clients[winid].content_geometry().size(
        ) == old_geometry.size()

    # update the size hints:
    hints = {
        'flags': Xutil.PResizeInc,
        'width_inc': 5,
        'height_inc': 7,
    }
    handle.set_wm_normal_hints(hints)
    x11.sync_with_hlwm()

    new_geometry = hlwm.attr.clients[winid].floating_geometry()
    # the new size adheres to the size hints
    assert new_geometry.width % hints['width_inc'] == 0
    assert new_geometry.height % hints['height_inc'] == 0
    # the new size changes only as little as necessary
    assert abs(new_geometry.width - old_geometry.width) <= hints['width_inc']
    assert abs(new_geometry.height -
               old_geometry.height) <= hints['height_inc']

    if floating:
        assert hlwm.attr.clients[winid].content_geometry().size(
        ) == new_geometry.size()
Example #3
0
def test_floating_geometry_and_placement(hlwm, x11, place_center):
    hlwm.attr.tags.focus.floating = True

    rule_geo = Rectangle(30, 40, 140, 170)
    rule = ['floating_geometry=' + rule_geo.to_user_str()]
    if place_center:
        rule += ['floatplacement=center']
    else:
        # also add another rule whose floatplacement is then overwritten:
        hlwm.call('rule floatplacement=center')
        rule += ['floatplacement=none']

    # 'floatplacement' is only applied by 'rule', so no test
    # for 'apply_tmp_rule' or 'apply_rules'
    hlwm.call(['rule'] + rule)
    _, winid = x11.create_client()

    client_geo = hlwm.attr.clients[winid].floating_geometry()
    monitor_geo = hlwm.attr.monitors.focus.geometry()

    assert client_geo.size() == rule_geo.size()
    if place_center:
        assert client_geo.center() == monitor_geo.center()
    else:
        assert client_geo.topleft() == rule_geo.topleft()
Example #4
0
def test_floating_geometry(hlwm, x11, command, visible_tag):
    if command != 'rule':
        _, winid = x11.create_client()  # client first

    geo = Rectangle(30, 40, 140, 170)
    rule = [
        'floating=on', 'focus=on', 'floating_geometry=' + geo.to_user_str()
    ]

    if not visible_tag:
        hlwm.call('add othertag')
        rule += ['tag=othertag']

    if command == 'rule':
        hlwm.call(['rule'] + rule)
        _, winid = x11.create_client()  # client second
    elif command == 'apply_rules':
        # apply fresh rules to long existing client
        hlwm.call(['rule'] + rule)
        hlwm.call(['apply_rules', winid])
    else:
        hlwm.call(['apply_tmp_rule', winid] + rule)

    if not visible_tag:
        hlwm.call('use othertag')

    assert hlwm.attr.clients.focus.floating_geometry() == geo
    assert hlwm.attr.clients.focus.content_geometry() == geo
Example #5
0
def test_implicit_type_conversion_rectangle(hlwm):
    # TODO: change as soon as custom attributes support Rectangle!
    geo = Rectangle(10, 20, 400, 500)
    hlwm.attr.monitors.focus.geometry = geo
    assert hlwm.attr.monitors.focus.geometry() == geo

    geo = Rectangle(20, 30, 422, 522)
    hlwm.attr.monitors.focus.geometry = geo
    assert hlwm.attr.monitors.focus.geometry() == geo
def test_directional_shift_resize_left_up(hlwm, command, direction,
                                          put_obstacle):
    """
    run: shift/resize up/left
    possibly put a window obstacle in the way
    """
    hlwm.attr.tags.focus.floating = True
    client, _ = hlwm.create_client()
    bw = 3
    hlwm.attr.theme.border_width = bw
    gap = 2
    hlwm.attr.settings.snap_gap = gap
    hlwm.attr.clients[client].sizehints_floating = False
    old_geo = Rectangle(x=160, y=170, width=80, height=90)
    hlwm.attr.clients[client].floating_geometry = old_geo

    # possibly put a window obstacle between the 'client' and the screen edge:
    if put_obstacle:
        obstacle, _ = hlwm.create_client()
        hlwm.attr.clients[obstacle].sizehints_floating = False
        obstacle_pos = 100 + bw
        if direction == 'up':
            hlwm.attr.clients[obstacle].floating_geometry = \
                Rectangle(x=0, y=0, width=400, height=100)
        elif direction == 'left':
            hlwm.attr.clients[obstacle].floating_geometry = \
                Rectangle(x=0, y=0, width=100, height=400)
    else:
        # the next obstacle is the screen edge
        obstacle_pos = 0

    if direction == 'up':
        # expected position after shift up: same x, different y
        expected_pos = (160, obstacle_pos + bw + gap)
    elif direction == 'left':
        # expected position after shift left: different x, same y
        expected_pos = (obstacle_pos + bw + gap, 170)

    hlwm.call(['jumpto', client])
    hlwm.call([command, direction])  # the actual shift/resize

    # check that the top left corner of the window is adjusted as expected
    new_geo = hlwm.attr.clients.focus.floating_geometry()
    assert expected_pos == (new_geo.x, new_geo.y)

    if command == 'shift':
        # shift means: size is unchanged
        assert (old_geo.width, old_geo.height) == (new_geo.width,
                                                   new_geo.height)
    else:
        # resize means: bottom right corner is unchanged
        assert old_geo.x + old_geo.width == new_geo.x + new_geo.width
        assert old_geo.y + old_geo.height == new_geo.y + new_geo.height
def test_resize_shrink_not_possible(hlwm, direction):
    hlwm.attr.settings.snap_gap = 5
    hlwm.attr.tags.focus.floating = True

    winid, _ = hlwm.create_client()
    hlwm.attr.clients.focus.sizehints_floating = False
    # place the client roughly in the center of the monitor:
    geo_orig = Rectangle(x=200, y=200, width=160, height=140)
    hlwm.attr.clients.focus.floating_geometry = geo_orig

    # call resize multiple times
    for i in range(0, 15):
        proc = hlwm.unchecked_call(['resize', direction])
        if proc.returncode != 0:
            assert f"{winid} is too small to be shrunk" in proc.stderr
            break
    geo_final = hlwm.attr.clients.focus.floating_geometry()

    # after calling 'resize' that often, the minimum window size
    # must have been reached. So calling it again will not change the geometry:
    hlwm.call_xfail(['resize', direction]).expect_stderr('too small')
    assert geo_final == hlwm.attr.clients.focus.floating_geometry()

    if direction in ['up', 'down']:
        assert geo_orig.width == geo_final.width
    else:
        assert geo_orig.height == geo_final.height

    assert geo_final.width >= 50
    assert geo_final.height >= 50
Example #8
0
def test_drag_move_sends_configure(hlwm, x11, mouse, update_dragged):
    hlwm.attr.tags.focus.floating = 'on'
    hlwm.attr.settings.update_dragged_clients = hlwm.bool(update_dragged)
    client, winid = x11.create_client()
    x, y = x11.get_absolute_top_left(client)
    before = Rectangle.from_user_str(hlwm.attr.clients[winid].geometry_reported())
    assert (x, y) == (before.x, before.y)
    mouse.move_into(winid, wait=True)

    hlwm.call(['drag', winid, 'move'])
    mouse.move_relative(12, 15)
    mouse.click('1')  # stop dragging
    hlwm.call('true')  # sync

    after = Rectangle.from_user_str(hlwm.attr.clients[winid].geometry_reported())
    assert before.adjusted(dx=12, dy=15) == after
Example #9
0
def test_detect_monitors_xrandr(hlwm_spawner, screens, xvfb):
    args = ['-extension', 'XINERAMA']
    args += ['+extension', 'RANDR']
    with MultiscreenDisplay(server='Xephyr', screens=screens,
                            extra_args=args) as xserver:
        # boot up hlwm
        hlwm_proc = hlwm_spawner(display=xserver.display)
        hlwm = conftest.HlwmBridge(xserver.display, hlwm_proc)

        # for the debugging if something fails:
        lines = hlwm.call('detect_monitors --list-all').stdout.splitlines()
        for cur_line in lines:
            words = cur_line.split(' ')
            if words[0] == 'xinerama:':
                # check that xinerama is disabled
                assert len(words) == 1
            elif words[0] == 'xrandr:':
                # unfortunately, xrandr in Xephyr only reports the first screen
                assert len(words) == 2
                assert words[1] == Rectangle(
                    x=0, y=0, width=screens[0][0],
                    height=screens[0][1]).to_user_str()
            else:
                assert False, f"unknown detect_monitors output: {cur_line}"

        hlwm_proc.shutdown()
def test_can_move_client_at_monitor_edge(hlwm, mouse):
    hlwm.attr.tags.focus.floating = True
    winid, _ = hlwm.create_client()
    hlwm.call('move_monitor 0 600x400+0+0')
    # move floating coordinates clearly off screen:
    floating_geo = Rectangle(x=2000, y=4000, width=300, height=200)
    hlwm.attr.clients[winid].sizehints_floating = False
    hlwm.attr.clients[winid].floating_geometry = floating_geo
    # still, the window overlaps with the monitor by a few pixels
    content_geo = hlwm.attr.clients[winid].content_geometry()
    assert content_geo.x + 20 < 600
    assert content_geo.y + 20 < 400
    assert hlwm.attr.clients[winid].floating_geometry() == floating_geo
    # so, despite the floating geo is far off,
    # the window is shown on the monitor

    # now drag the window by a few pixels back into the monitor:
    mouse.move_into(winid)
    hlwm.attr.settings.update_dragged_clients = True
    hlwm.call(['drag', winid, 'move'])
    delta = Point(-72, -93)
    assert hlwm.get_attr('clients.dragged.winid') == winid
    mouse.move_relative(delta.x, delta.y)

    # then, we expect that the window actually moves back
    # by precisely this distance:
    # (in old hlwm versions, the window was glueing in the bottom right corner)
    assert hlwm.attr.clients[winid].content_geometry() == content_geo.adjusted(dx=delta.x, dy=delta.y)
    # but of course the floating geo changed a lot (e.g. more than 500),
    # because the window is now within the screen again:
    new_floating_geo = hlwm.attr.clients[winid].floating_geometry()
    assert abs(new_floating_geo.x - floating_geo.x) > 500
    assert abs(new_floating_geo.y - floating_geo.y) > 500
Example #11
0
def test_decorated_off_floating_geometry_correct(hlwm):
    winid, _ = hlwm.create_client()
    hlwm.attr.theme.border_width = 8
    client_obj = hlwm.attr.clients[winid]

    client_obj.floating_geometry = Rectangle(10, 20, 200, 100)
    client_obj.floating = True
    client_obj.decorated = False

    assert client_obj.floating_geometry() == client_obj.decoration_geometry()
Example #12
0
def test_floating_geometry_change(hlwm, minimized, floating, x11, othertag):
    if othertag:
        hlwm.call('add othertag')
        hlwm.call('rule tag=othertag')
    handle, winid = x11.create_client()
    clientobj = hlwm.attr.clients[winid]
    clientobj.floating = hlwm.bool(floating)
    clientobj.minimized = hlwm.bool(minimized)
    hlwm.call('pad "" 0 0 0 0')
    hlwm.call('move_monitor "" 800x600+0+0')

    for geom in [Rectangle(x=50, y=100, width=100, height=300),
                 Rectangle(x=-20, y=2, width=430, height=200)]:

        clientobj.floating_geometry = geom.to_user_str()

        if not minimized and not othertag:
            assert (clientobj.content_geometry() == geom) == floating
            assert (x11.get_absolute_top_left(handle) == (geom.x, geom.y)) == floating
def test_resize_shrink_client(hlwm, direction):
    hlwm.attr.settings.snap_gap = 5
    hlwm.attr.tags.focus.floating = True
    hlwm.attr.monitors.focus.geometry = Rectangle(x=0,
                                                  y=0,
                                                  width=800,
                                                  height=900)

    hlwm.create_client()
    hlwm.attr.clients.focus.sizehints_floating = False
    # place the client roughly in the center of the monitor:
    geo_orig = Rectangle(x=200, y=200, width=300, height=400)
    hlwm.attr.clients.focus.floating_geometry = geo_orig
    # shift the client towards the monitor edge in the specified 'direction'
    hlwm.call(['shift', direction])
    geo_moved = hlwm.attr.clients.focus.floating_geometry()
    # and the size is as originally
    assert geo_moved.width == geo_orig.width
    assert geo_moved.height == geo_orig.height

    # calling 'resize' with the same direction forces the client to shrink:
    hlwm.call(['resize', direction])

    geo_shrunk = hlwm.attr.clients.focus.floating_geometry()
    if direction in ['up', 'down']:
        # client was shrunk in height
        assert geo_shrunk.width == geo_moved.width
        assert geo_shrunk.height == geo_moved.height // 2
    else:
        # client was shrunk in width
        assert geo_shrunk.width == geo_moved.width // 2
        assert geo_shrunk.height == geo_moved.height

    if direction in ['right', 'down']:
        # bottom right corner stays unchanged
        assert geo_shrunk.x + geo_shrunk.width == geo_moved.x + geo_moved.width
        assert geo_shrunk.y + geo_shrunk.height == geo_moved.y + geo_moved.height
    else:
        # top left corner stays unchanged
        assert geo_shrunk.x == geo_moved.x
        assert geo_shrunk.y == geo_moved.y
Example #14
0
def test_panel_object(hlwm, x11):
    assert int(hlwm.attr.panels.count()) == 0

    _, winid = x11.create_client(geometry=(1, 0, 800, 30),
                                 wm_class=('panelinst', 'panelclass'),
                                 window_type='_NET_WM_WINDOW_TYPE_DOCK')

    assert int(hlwm.attr.panels.count()) == 1
    assert hlwm.attr.panels[winid].instance() == 'panelinst'
    assert hlwm.attr.panels[winid]['class']() == 'panelclass'
    assert hlwm.attr.panels[winid].geometry() == Rectangle(1, 0, 800, 30)
    assert hlwm.attr.panels[winid].winid() == winid
def test_drag_floating_to_other_monitor(hlwm, mouse, source_floating, client_floating, target_floating, client_focused):
    total_width = hlwm.attr.monitors.focus.geometry().width
    total_height = hlwm.attr.monitors.focus.geometry().height
    # create two monitors side by side with small gaps, pads, and some odd coordinates
    hlwm.call('add othertag')
    geo1 = Rectangle(x=10, y=20, width=total_width / 2 - 30, height=total_height)
    geo2 = Rectangle(x=total_width / 2, y=15, width=total_width / 2, height=total_height)
    hlwm.call(['set_monitors', geo1.to_user_str(), geo2.to_user_str()])
    hlwm.call(['pad', '0', '11', '12', '13', '14'])
    hlwm.call(['pad', '1', '15', '16', '17', '18'])
    hlwm.attr.settings.update_dragged_clients = True

    hlwm.attr.tags[0].floating = source_floating
    hlwm.attr.tags[1].floating = target_floating
    # another dummy client
    otherclient, _ = hlwm.create_client()

    # put client in the middle of tag 0
    hlwm.call('rule floatplacement=center')
    winid, _ = hlwm.create_client()
    if client_focused:
        focused_winid = winid
    else:
        focused_winid = otherclient
    hlwm.call(['jumpto', focused_winid])
    hlwm.attr.clients[winid].floating = client_floating
    assert hlwm.attr.clients[winid].tag() == hlwm.attr.tags[0].name()
    assert hlwm.attr.clients.focus.winid() == focused_winid

    # start dragging
    content_geo_before = hlwm.attr.clients[winid].content_geometry()
    start = content_geo_before.center()
    mouse.move_to(start.x, start.y)
    hlwm.call(['drag', winid, 'move'])
    end = hlwm.attr.monitors[1].geometry().center()
    mouse.move_to(end.x, end.y)
    content_geo_after = hlwm.attr.clients[winid].content_geometry()
    assert end == content_geo_after.center()
    assert hlwm.attr.clients[winid].tag() == hlwm.attr.tags[1].name()
    assert hlwm.attr.clients[winid].floating_effectively() is True
    # check that the focused client does not change:
    assert hlwm.attr.clients.focus.winid() == focused_winid
    # check that the correct monitor is focused
    assert hlwm.attr.monitors.focus.tag() == hlwm.attr.clients.focus.tag()
    assert hlwm.attr.monitors.focus.index() == (1 if client_focused else 0)
    if not target_floating:
        # if the target tag is not floating, the client must have been
        # set to single-window floating
        assert hlwm.attr.clients[winid].floating() is True
    else:
        # if the target tag is floating, then the client's floating
        # state is unchanged
        assert hlwm.attr.clients[winid].floating() == client_floating
Example #16
0
def test_smart_placement_within_monitor(hlwm):
    """
    In the smart placement, the outer geometry of clients
    must be used. So test that even with wide decorations,
    the top left corner of the decoration is not off screen.
    """
    hlwm.attr.tags.focus.floating = 'on'
    hlwm.call('rule floatplacement=smart')
    bw = 25
    hlwm.attr.theme.border_width = bw
    hlwm.attr.settings.snap_gap = 5  # something smaller than bw
    winid, _ = hlwm.create_client()

    inner_geometry = Rectangle.from_user_str(
        hlwm.attr.clients[winid].geometry_reported())

    # assert that the top left corner of the decoration
    # is still within the monitor
    assert inner_geometry.x - bw >= 0
    assert inner_geometry.y - bw >= 0
Example #17
0
def test_detect_monitors_deduplication(hlwm_spawner, screens, xvfb):
    args = ['+extension', 'XINERAMA']
    args += ['-extension', 'RANDR']
    # Xvfb puts all screens at position (0,0),
    # so we use it to verify that detect_monitors removes duplicates
    # while preserving the order
    with MultiscreenDisplay(server='Xvfb', screens=screens,
                            extra_args=args) as xserver:
        # boot up hlwm
        hlwm_proc = hlwm_spawner(display=xserver.display)
        hlwm = conftest.HlwmBridge(xserver.display, hlwm_proc)
        # create enough tags
        hlwm.call('chain , add tag1 , add tag2 , add tag3')
        assert hlwm.get_attr('monitors.count') == '1'
        rects = hlwm.call(['detect_monitors', '-l']).stdout.splitlines()
        expected = [
            Rectangle(0, 0, s[0], s[1]).to_user_str()
            for idx, s in enumerate(screens) if screens.index(s) == idx
        ]

        assert rects == expected

        hlwm_proc.shutdown()