serhii.net

In the middle of the desert you can say anything you want

08 Dec 2021

211208-1509 qtile WM first impressions

Qtile WM

Python tiling window manager, playing with it for a couple of days now.

It’s everything I expected from a tiling WM, except it’s completely configurable with Python, so basically unlimited options to do anything. Compared to my usual i3: speed is the same, documentation is a bit worse, but configuration is much more intuitive.

And it has a lot of stuff, I never heard of it but was surprised to learn it has a lot of widgets / layouts / etc., and it has  even a CLI-like shell qtile shell where you can use the standard bash commands to do stuff to anything (cd/ls/etc to layouts/groups/windows, run things like cd groups/F1/windows/213; down_opacity()).

Everything I customized in i3 via hacks can be done natively nicely and in python and I love it.

Notes

Checking configuration for errors before restarting

No easy way to check config for correctness I’ve found, but python3 config.py finds most errors.

Docu suggests python3 -m py_compile config.py but it returns no output regardless of errors. qtile shell’s test config also is quiet.

Layouts

A lot of them. Tried all. Favourites so far. Listed here: Built-in Layouts — Qtile 0.1.dev50+g9c583ed.d20211208 documentation

Main realization so far is that I’ve been using tiling WMs wrong, in i3 I kept manually splitting the window when I needed to have it split into smaller ones. Except that this should happen automatically, because I never want three windows side-by-side at the same time.

MonadTall / MonadWide

Probably my favourite one. Splits stuff nicely in one big and multiple smaller ones in a separate columns.

Added these bits to config:

Key([modkey], "i", lazy.layout.grow()),
Key([modkey], "m", lazy.layout.shrink()),
Key([modkey], "n", lazy.layout.normalize()),
Key([modkey], "o", lazy.layout.maximize()),
  • <mod+o> toggles between how big/main is the highlighted window. If it’s the big window, it gets narrower or wider, if it’s one of the smaller ones in a column, each becomes the biggest/smallest in that column.
  • <mod+i>/<mod+m> grows/shrinks the current window.
  • <mod+n> ’normalizes’ everything by resetting the layout.

Column

Nice intuitive etc, has N columns, moving windows to left-right does what I expect, including creating newer columns, or splitting existing ones as the window “travels” through it.

Bsp

The tree-thingy that splits each thing into two, ad infinitum.

These bindings use mod3 which is the physical ctrl key, that move the splits with all windows inside them (not individual windows). They seem to be used only for that layout.

    Key([mod3], "j", lazy.layout.flip_down()),
    Key([mod3], "k", lazy.layout.flip_up()),
    Key([mod3], "h", lazy.layout.flip_left()),
    Key([mod3], "l", lazy.layout.flip_right()),

Other

Tile

Two stacks, one with N “main” windows (1, but configurable), and a second stack for all the other ones. See no added value compared to the Monad ones. But add_after_last=True makes the behaviour more intuitive to me.

Max

One single window, the rest are hidden behind it (as a stack), no configs, no way to signal if it’s the only window or there are more behind it.

TreeTab

Only layout that I can get to show the titles of the windows inside the stack. You get one stack and window titles on the right.

Meant for browsers like uzbl, and it emulates almost exactly the setup I have for qutebrowser.

Random

  • From this1 sample command:
    • Doing stuff based on different layout:
          layout = qtile.current_layout
      	group = qtile.current_group
      
      	if layout.name == 'monadtall':
      		layout.cmd_maximize()
      		if len(group.windows) != 2:
      			return
      
    • Using python and sound software engineering like creating a class to keep constants for commands

Config bits / settings

Getting Obsidian to run in a Dropdown/Scratchpad

One of those two worked: - calling Obsidian directly as binary (instead of my runner shell script) - Using config.Match()to identify it .

TODO

  • Multiple screens/monitors
    • This shows how to detect number of screens and place groups in them: qtile-examples/groups.py at master · qtile/qtile-examples
      from libqtile.config import Screen
      from platforms import num_screens, hostname
      if num_screens[hostname] == 4:
      	from bars import chat_bar, main_bar, media_bar, code_bar
      	# ...
      	chat_screen = Screen(top=chat_bar)
      	# ...
      	screens = [main_screen, media_screen, code_screen, chat_screen]
      
  • All my usual shortcuts (volume, screenshots, etc. etc.)
  • I like the idea of splitting the configs in separate python files2, especially for constants1

What’s missing

  • How to have a sticky floating window? 3
Nel mezzo del deserto posso dire tutto quello che voglio.