Skip to content

Commit

Permalink
Make MonadWide up/down focus navigation behave like MonadTall left/right
Browse files Browse the repository at this point in the history
MonadTall exposes left/right commands to focus the closest window to the
left/right, allowing easy navigation between columns. MonadWide had no similar
override for up/down focus commands, instead it inherited the next/previous =
down/up overrides of MonadTall, making directional navigation between rows more
cumbersome by requiring cycling amongst all windows. The result is inconsistent
window navigation between MonadTall and MonadWide.

This change retains the original navigation commands and behavior of
MonadTall (including left/right), while adding a symmetric up/down command to
MonadWide.
  • Loading branch information
holocronweaver authored and elParaguayo committed Oct 22, 2024
1 parent 928a044 commit 0d8e521
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Qtile x.xx.x, released xxxx-xx-xx:
* features
- Add `SwayNC` widget to interact with Sway Notification Centre (wayland only)
* bugfixes
- Make MonadWide layout up/down focus navigation behave like MonadTall's left/right

Qtile 0.29.0, released 2024-10-19:
* features
Expand Down
42 changes: 40 additions & 2 deletions libqtile/layout/xmonad.py
Original file line number Diff line number Diff line change
Expand Up @@ -756,11 +756,11 @@ def _shrink_secondary(self, amt):
# shrink client by total change
self.relative_sizes[self.focused - 1] -= self._get_relative_size_from_absolute(change)

@expose_command("down")
@expose_command()
def next(self) -> None:
_SimpleLayoutBase.next(self)

@expose_command("up")
@expose_command()
def previous(self) -> None:
_SimpleLayoutBase.previous(self)

Expand Down Expand Up @@ -858,6 +858,16 @@ def right(self):
self.clients.current_client = self._get_closest(x, y, candidates)
self.group.focus(self.clients.current_client)

@expose_command()
def up(self):
"""Focus on the closest window above the current window"""
self.previous()

@expose_command()
def down(self):
"""Focus on the closest window below the current window"""
self.next()


class MonadWide(MonadTall):
"""Emulate the behavior of XMonad's horizontal tiling scheme.
Expand Down Expand Up @@ -1123,6 +1133,34 @@ def swap_main(self):
elif self.align == self._down:
self.swap_left()

@expose_command()
def left(self):
"""Focus on the closest window to the left of the current window"""
self.previous()

@expose_command()
def right(self):
"""Focus on the closest window to the right of the current window"""
self.next()

@expose_command()
def up(self):
"""Focus on the closest window above the current window"""
win = self.clients.current_client
x, y = win.x, win.y
candidates = [c for c in self.clients if c.info()["y"] < y]
self.clients.current_client = self._get_closest(x, y, candidates)
self.group.focus(self.clients.current_client)

@expose_command()
def down(self):
"""Focus on the closest window below the current window"""
win = self.clients.current_client
x, y = win.x, win.y
candidates = [c for c in self.clients if c.info()["y"] > y]
self.clients.current_client = self._get_closest(x, y, candidates)
self.group.focus(self.clients.current_client)


class MonadThreeCol(MonadTall):
"""Emulate the behavior of XMonad's ThreeColumns layout.
Expand Down
84 changes: 84 additions & 0 deletions test/layouts/test_xmonad.py
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,90 @@ def test_wide_window_focus_cycle(manager):
assert_focus_path(manager, "float1", "float2", "one", "two", "three")


@monadtall_config
def test_tall_window_directional_focus(manager):
# setup 3 tiled and two floating clients
manager.test_window("one")
manager.test_window("two")
manager.test_window("float1")
manager.c.window.toggle_floating()
manager.test_window("float2")
manager.c.window.toggle_floating()
manager.test_window("three")

# test preconditions
assert manager.c.layout.info()["clients"] == ["one", "two", "three"]
# last added window has focus
assert_focused(manager, "three")

# starting from the last tiled client, test that left/right focus changes go
# to the closest window in that direction (no cycling), and up/down cycles
# focus
manager.c.layout.left()
assert_focused(manager, "one")
manager.c.layout.left()
assert_focused(manager, "one")
manager.c.layout.right()
assert_focused(manager, "two")
manager.c.layout.right()
assert_focused(manager, "two")

manager.c.layout.down()
assert_focused(manager, "three")
manager.c.layout.down()
assert_focused(manager, "one")
manager.c.layout.down()
assert_focused(manager, "two")
manager.c.layout.up()
assert_focused(manager, "one")
manager.c.layout.up()
assert_focused(manager, "three")
manager.c.layout.up()
assert_focused(manager, "two")


@monadwide_config
def test_wide_window_directional_focus(manager):
# setup 3 tiled and two floating clients
manager.test_window("one")
manager.test_window("two")
manager.test_window("float1")
manager.c.window.toggle_floating()
manager.test_window("float2")
manager.c.window.toggle_floating()
manager.test_window("three")

# test preconditions
assert manager.c.layout.info()["clients"] == ["one", "two", "three"]
# last added window has focus
assert_focused(manager, "three")

# starting from the last tiled client, test that up/down focus changes go to
# the closest window in that direction (no cycling), and left/right cycles
# focus
manager.c.layout.up()
assert_focused(manager, "one")
manager.c.layout.up()
assert_focused(manager, "one")
manager.c.layout.down()
assert_focused(manager, "two")
manager.c.layout.down()
assert_focused(manager, "two")

manager.c.layout.left()
assert_focused(manager, "one")
manager.c.layout.left()
assert_focused(manager, "three")
manager.c.layout.left()
assert_focused(manager, "two")
manager.c.layout.right()
assert_focused(manager, "three")
manager.c.layout.right()
assert_focused(manager, "one")
manager.c.layout.right()
assert_focused(manager, "two")


# MonadThreeCol
class MonadThreeColConfig(Config):
auto_fullscreen = True
Expand Down

0 comments on commit 0d8e521

Please sign in to comment.