Skip to content

Commit

Permalink
Fix window matching on ScreenSplit layout
Browse files Browse the repository at this point in the history
There was a bug where the matching rules for nested layouts were never
actually being checked. This PR fixes that and adds a test for it.
  • Loading branch information
elParaguayo committed Apr 7, 2024
1 parent 8ce23de commit 2da82cc
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 59 deletions.
11 changes: 9 additions & 2 deletions libqtile/layout/screensplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def __init__(self, **config):
self._split_index = 0
self.layouts = {}
self._move_win = None
self._has_matches = False
self._has_matches = None
print(self.splits)
splits = []
for s in self.splits:
Expand All @@ -134,6 +134,13 @@ def __init__(self, **config):
def _should_check(self, win):
return win not in self.layouts and self._move_win is None

@property
def has_matches(self):
if self._has_matches is None:
self._has_matches = any(split.matches for split in self.splits)

return self._has_matches

@property
def active_split(self):
return self.splits[self._split_index]
Expand Down Expand Up @@ -201,7 +208,7 @@ def add_client(self, win: Window) -> None:
split = None
# If this is a new window and we're not moving this window between splits
# then we should check for match rules
if self._has_matches and self._should_check(win):
if self.has_matches and self._should_check(win):
split = self._match_win(win)

if split is not None:
Expand Down
145 changes: 88 additions & 57 deletions test/layouts/test_screensplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,79 +26,110 @@
from test.layouts.layout_utils import assert_dimensions


class ScreenSplitConfig(Config):
auto_fullscreen = True
groups = [libqtile.config.Group("a")]
layouts = [layout.ScreenSplit()]
floating_layout = libqtile.resources.default_config.floating_layout
keys = []
mouse = []
screens = []
follow_mouse_focus = False
@pytest.fixture(scope="function")
def ss_manager(manager_nospawn, request):
class ScreenSplitConfig(Config):
auto_fullscreen = True
groups = [libqtile.config.Group("a")]
layouts = [layout.ScreenSplit(**getattr(request, "param", dict()))]
floating_layout = libqtile.resources.default_config.floating_layout
keys = []
mouse = []
screens = []
follow_mouse_focus = False

manager_nospawn.start(ScreenSplitConfig)

screensplit_config = pytest.mark.parametrize("manager", [ScreenSplitConfig], indirect=True)
yield manager_nospawn


@screensplit_config
def test_screensplit(manager):
def ss_config(**kwargs):
return pytest.mark.parametrize("ss_manager", [kwargs], indirect=True)


@ss_config()
def test_screensplit(ss_manager):
# Max layout is default, occupies top half of screen
assert manager.c.layout.info()["current_layout"] == "max"
manager.test_window("one")
assert_dimensions(manager, 0, 0, 800, 300)
manager.test_window("two")
assert_dimensions(manager, 0, 0, 800, 300)
assert manager.c.layout.info()["current_clients"] == ["one", "two"]
assert ss_manager.c.layout.info()["current_layout"] == "max"
ss_manager.test_window("one")
assert_dimensions(ss_manager, 0, 0, 800, 300)
ss_manager.test_window("two")
assert_dimensions(ss_manager, 0, 0, 800, 300)
assert ss_manager.c.layout.info()["current_clients"] == ["one", "two"]

manager.c.layout.next_split()
assert manager.c.layout.info()["current_layout"] == "columns"
assert manager.c.layout.info()["current_clients"] == []
ss_manager.c.layout.next_split()
assert ss_manager.c.layout.info()["current_layout"] == "columns"
assert ss_manager.c.layout.info()["current_clients"] == []

# Columns layout has no border on single...
manager.test_window("three")
assert_dimensions(manager, 0, 300, 800, 300)
ss_manager.test_window("three")
assert_dimensions(ss_manager, 0, 300, 800, 300)
# ... but a border of 2 when multiple windows
manager.test_window("four")
assert_dimensions(manager, 400, 300, 396, 296)
assert manager.c.layout.info()["current_clients"] == ["three", "four"]
ss_manager.test_window("four")
assert_dimensions(ss_manager, 400, 300, 396, 296)
assert ss_manager.c.layout.info()["current_clients"] == ["three", "four"]

manager.c.layout.next_split()
assert manager.c.layout.info()["current_layout"] == "max"
assert manager.c.layout.info()["current_clients"] == ["one", "two"]
ss_manager.c.layout.next_split()
assert ss_manager.c.layout.info()["current_layout"] == "max"
assert ss_manager.c.layout.info()["current_clients"] == ["one", "two"]


@screensplit_config
def test_commands_passthrough(manager):
assert manager.c.layout.info()["current_layout"] == "max"
assert "grow_left" not in manager.c.layout.commands()
@ss_config()
def test_commands_passthrough(ss_manager):
assert ss_manager.c.layout.info()["current_layout"] == "max"
assert "grow_left" not in ss_manager.c.layout.commands()

manager.c.layout.next_split()
assert manager.c.layout.info()["current_layout"] == "columns"
ss_manager.c.layout.next_split()
assert ss_manager.c.layout.info()["current_layout"] == "columns"

manager.test_window("one")
assert_dimensions(manager, 0, 300, 800, 300)
manager.test_window("two")
assert_dimensions(manager, 400, 300, 396, 296)
ss_manager.test_window("one")
assert_dimensions(ss_manager, 0, 300, 800, 300)
ss_manager.test_window("two")
assert_dimensions(ss_manager, 400, 300, 396, 296)

assert "grow_left" in manager.c.layout.commands()
assert "grow_left" in ss_manager.c.layout.commands()
# Grow window by 40 pixels
manager.c.layout.grow_left()
assert_dimensions(manager, 360, 300, 436, 296)


@screensplit_config
def test_move_window_to_split(manager):
assert manager.c.layout.info()["current_layout"] == "max"
manager.test_window("one")
assert_dimensions(manager, 0, 0, 800, 300)

manager.c.layout.move_window_to_next_split()
assert manager.c.layout.info()["current_layout"] == "columns"
assert_dimensions(manager, 0, 300, 800, 300)

manager.c.layout.move_window_to_previous_split()
assert manager.c.layout.info()["current_layout"] == "max"
assert_dimensions(manager, 0, 0, 800, 300)
ss_manager.c.layout.grow_left()
assert_dimensions(ss_manager, 360, 300, 436, 296)


@ss_config()
def test_move_window_to_split(ss_manager):
assert ss_manager.c.layout.info()["current_layout"] == "max"
ss_manager.test_window("one")
assert_dimensions(ss_manager, 0, 0, 800, 300)

ss_manager.c.layout.move_window_to_next_split()
assert ss_manager.c.layout.info()["current_layout"] == "columns"
assert_dimensions(ss_manager, 0, 300, 800, 300)

ss_manager.c.layout.move_window_to_previous_split()
assert ss_manager.c.layout.info()["current_layout"] == "max"
assert_dimensions(ss_manager, 0, 0, 800, 300)


@ss_config(
splits=[
{
"name": "no_match",
"rect": (0, 0, 1, 0.5),
"layout": layout.Max(),
},
{
"name": "match",
"rect": (0, 0.5, 1, 0.5),
"layout": layout.Spiral(),
"matches": [Match(title="test")],
},
]
)
def test_match_window(ss_manager):
assert ss_manager.c.layout.info()["current_layout"] == "max"
ss_manager.test_window("one")
assert ss_manager.c.layout.info()["current_layout"] == "max"

ss_manager.test_window("test")
assert ss_manager.c.layout.info()["current_layout"] == "spiral"


def test_invalid_splits():
Expand Down

0 comments on commit 2da82cc

Please sign in to comment.