Scoped Alt Tab
23 Sep 2025
Like many developers, I like configuring and optimizing my computer setup for my needs. I want my setup to be as seamless as possible, mostly to make using a computer be fun. A few weeks ago I took on the task of figuring out the best possible way to switch windows.
I use a single monitor and most of the time I only have one window visible with no other UI on the screen. I do that to give as much space as possible to the window I’m currently using. Sometimes I use two side-by-side when needed, but however I have my windows laid out, I need a way to change focus between them.
How my screen typically looks. I
swear I use the right side too.
For a long time I used i3 with a configuration that’s typical of it: I had a different i3 workspace for each window I typically used. For me, that’s a shell, an editor, a browser, and a communication app like Slack. I had one key on my keyboard to switch to each of these workspaces which took up the entire screen. This is essentially the setup that ThePrimeagen describes in this video. I imagine this is a popular way to use i3 because it is essentially uses the its defaults.
That way of managing windows has a few shortcomings though. The biggest is that when I want to have two windows of a type that I frequently use, such as if I want to have two shell windows open, I would have to move the new window to a workspace I didn’t normally use for that app. Part of the point of assigning apps to their own shortcut key is to develop the muscle memory of pressing that key when I want to go to that app, which doesn’t work when the app is on a different workspace than usual. That setup also does not handle moving focus between two windows that are visible at the same time. There needs to be different keys to switch between windows in the same workspace which doesn’t achieve the “press this button to go to this window” behavior I really want.
When I finally got around to improving this in my i3 setup, I was limited by what I could express in its configuration language. At that time I was also using lua to do more complex things in my neovim configuration so I decided what I really want is a proper programming language for configuration. I switched to Awesome window manager mainly to use lua for configuration but also since dynamic tiling was more what I wanted over i3’s manual tiling.
Wish Awesome, I started with a setup similar to default. I still used one app per workspace, or rather per tag as it is called in Awesome. Then I moved to putting multiple apps on each tag and having a key to switch to different apps within the current tag. Then I could use different tags to work on one task that required a particular set of windows and then switch tags to a different set of windows when doing I was something else.
Still, I wasn’t satisfied with how it all worked. I thought about the problem some more and summarized what I needed.
When I want to switch windows, I want to do so as quickly as possible. Having a particular key to switch to a particular window is good. That point I had working in all setups so far. Having multiple windows of the same app needs to work, so I can’t just have one key per app. This didn’t work in my previous setups. I decided that the one key for an app should cycle through the windows of that app so that I can access them all. This has the downside that the one key to switch apps is not idempotent if there are multiple windows, but I know which window has focus anyway so I wouldn’t press the key if I didn’t need to. Then it’s fine to have a key for each app I know I use frequently such as my browser, but what if I want to switch to some app I don’t usually use, one that I don’t have a dedicated key for? To solve that I added a key that switches between windows that don’t already have a dedicated key.
One other consideration is the iteration order. When I first implemented something like this, I had the key that switches through windows always cycle through them in the same order starting from the currently focused window. So for example, if I have two shell windows open and I have focus on the browser, pressing the shell key once would move focus to the first shell window and pressing it again would move focus to the second. If I then moved focus back to the browser, the key would behave exactly the same way it did the first time, moving focus to the first shell window on the first key press. This makes navigation consistent, but it does not work well when switching between two windows if one of them appears at the back of the list. In the previous example, I would have to press the shell key twice to get to the second shell window every time I switched to it. If I frequently wanted to switch to the second shell window instead of the first one, I would constantly have to switch to the first window on my way to it.
The solution to the problem of iteration order would be to iterate through windows most recently focused first, like alt-tabbing in traditional desktop navigation. Alt-tabbing iterates through windows in the order of most recently focused first. It figures that the window you most likely want to get to is the one you most recently used. A problem with traditional alt-tabbing though is it is less consistent than pressing a dedicated key for each window you want to go to; if you’re working with more than two windows, you don’t know which window will be selected after pressing alt-tab once, so would have to press it once, look at the pop-up UI to see what is selected, and then press alt-tab again until you select what you want. You can’t develop the muscle memory of what alt-tabbing does either since it changes every time you use it.
In my workflow, most of the switching is still between two windows that have dedicated keys for them. When I create a second window of some type I already have open, I don’t use the old as much as the new one. That means that I won’t frequently run into the situation where pressing my key to switch to a particular window switches to the incorrect one.
I call this navigation “scoped alt-tab”, because it is like traditional alt-tab navigation except I have four different keys for each of four different “scopes” in which to perform alt-tab. I have one key to alt-tab through only browser windows, one for shells, one for editors, and one for windows that aren’t one of those three. It is basically a hybrid of alt-tab and one-key-per-window navigation that takes the good parts of both and combines them into a solution that doesn’t take much conscious thought to use efficiently. When using it I usually just have to press one key to go too the window I want, but I can have multiple and use them just as well without doing any sort of manual arrangement.
You can check out my Awesome
config to see how this is
implemented. See the code involving awful.keygrabber. Designing software behavior for my own
use is always fun, although the best part of it is having a system I enjoy using.