Tile windows

As I said before, I spend most much of my life in terminal windows, being a sysadmin or a programmer or anything else like that. So naturally, where my terminal windows are positioned on the screen is kind of a big deal to me.

Back when I ran XFCE, I got used to using its keyboard shortcuts to position windows. They were pretty simple: you could tap keys to make a window use the left half, right half or entire screen. Not maximize, but more like what you’d get if you used the mouse to resize the window.

I would also set it up so that Super-F1 would open a new terminal window. Taken together, it became really easy to open a new window, throw it to the correct position and use it straight away, without taking my hands off the keyboard.

(No screen or tmux? Nope. I could never get into them. No tabs in terminal windows? Nope. I want everything flat; I need to be able to move around workspaces and quickly see what’s happening).

When I switched to macOS, a friend recommended Hammerspoon. This exposes a ton of the operating system to a Lua runtime, letting you write your own scripts to do things. This was my main form of customisation for macOS, and one of the first things I did was to reimplement my window layout shortcuts via a script called gravity_windows. Later I started using Miro, another Hammerspoon script that did the same thing but had more features, including cycling quarter widths and half-height windows.

elementary OS and its Gala window manager didn’t have much to offer me here unfortunately. There are keyboard shortcuts to tile left, tile right and maximise but they’re … weird. They work, but they sort of remove the window from the normal layout, and lock them in place until you explicitly un-remove them, which leads me to a bunch of mucking around trying to figure out why the window won’t move. It’s more than I want to think about.

I did look around to see if there’s anything like Hammerspoon available. Surprisingly, there isn’t. I think perhaps DBus interfaces are the place where most things that a similar thing would operate against, but I spent some time poking around and there’s no where near the depth or breadth of functionality exposed that way. And most importantly for this, window manipulation primitives weren’t available.

Fortunately, X has always had the ability to “remotely” manipulate windows in various ways. I started reading some of the X11 protocol elements available for this sort of thing, but it turned out to be easier to just use xdotool. This is a program that lets you move and resize windows, fake keyboard and mouse input and other stuff.

And so on top of this I wrote tiler. Its function is pretty straightforward in concept: get the currently active window, compute new size and position for it based on the requested options, and resize and move it.

xdotool does most of the heavy lifting for this program: finding the active window, getting its dimensions, getting the dimensions of other things (screen, panel) and setting the new size and position of the window.

The calculations are surprisingly complicated. The point of this program is to expand the window horizontally or vertically to the width or height of the desktop (or some even division). Windows are positioned relative to the screen, so we end up having to get the size of the screen and subtract the size of the panel to find the available size.

Even more fun is that we’re operating against X windows, which are quite low-level. GTK+ windows actually sit inside a much larger X window, with surrounding space available to render the (mostly transparent) drop shadow. So when computing the position and size that shadow area needs to be considered too. xdotool has no idea about it, so we have to resort to window manager hints on the window to find out what’s going on (the _GTK_FRAME_EXTENTS property).

That took a while to understand as the information for all these things are strewn haphazardly throughout documentation and code, but it all came together and is working really well. I set up a pile of shortcuts based around holding Ctrl+Super+Alt and then an arrow key to move. I’ve got a few combos running now: pull left, pull right, full screen (like the old days), pull top half, bottom half, cycle multiple widths, etc. It was fun to make too, and I’m using it a lot every day and it feels almost exactly like the layout I’ve been using for years.

Three terminal windows, arranged in a grid, one larger one to the left, two smaller ones to the right

I’m glad this was possible (Unix is a gigantic script engine so not surprising) but it would have been a lot easier and nicer if the upper layers of the UI (all the GNOME stuff and Gala) actually assisted. Maybe there’s more API available than I realise, but I don’t think so. A Hammerspoon-alike would be very welcome, one way or another.