Alt+Tab sucks; here's a solution

NOTE: I mostly use single application instances with tabbed UIs or similar (Firefox, Emacs + escreen.el, Terminator,
Zathura PDF viewer + Tabbed, SpaceFM), so this method works flawlessly for me. If you like having separate windows inside every program and hate tabbed interfaces, this won't work so well. But you can still use it for things like your browser, which only runs a single instance.

The Problem with Alt+Tab

The thing that's always ticked me off about the standard desktop metaphor is the inefficiency of Alt+Tab (at any point of time, you cannot be sure of where a particular application is, in the most-recently-used order). For so fundamental an operation as switching applications, which users perform many hundreds of times a day, making them tediously scan a (constantly-changing) list sorted by recently-used order seems like an awful idea to me, in many cases. Sure, toggling between two windows is dead simple, but when you have to switch to some other task, you're left with no choice but to go window-hunting.

The problem is especially chronic, for example, when I'm working on some web development stuff. I have 3 or more applications open (editor, browser, command line, at the very least, often with another browser for looking up documentation), and I have to switch among them very often. In such a situation, Alt+Tab is plain frustrating.

Turns out there is a 100x better solution, called run-or-raise. But first...

"Why don't you use workspaces?"

  • I always end up forgetting that I do in fact have the desired application running, only it's not on the current workspace.

  • I have to make sure applications are always running on their designated workspaces, otherwise the strategy breaks down.

  • Consider what happens when I have more than one application on a workspace. I've to switch to the correct workspace, and then switch to the target application if it's not already on top.

run-or-raise does better than workspaces on all counts.

run-or-raise

The idea is to have each frequently-used application one key combination away at all times, irrespective of which workspace it is on, or how recently it has been used, or even whether it's running or not. That way you can get down to actually using it in a jiffy.

run-or-raise is borrowed from my very brief experience with Awesome Window Manager (it used to be a Lua customization there, but recently an implementation has been added to Awesome's master branch by Anurag Priyam). Its concept is very intuitive. Calling run-or-raise on an application does the following:

  • "run": if the application is not running, launch it, and focus on it, or

  • "raise": if the application is already running, just switch to its workspace and raise it.

It may not sound like much, but it's been hugely productive for me. There's a strange satisfaction in knowing that Super+E will always take me straight to Emacs :)

Making it work (on WMs other than awesome)

Now with all that out of the way, let's look at how to get a crude but effective implementation working in pretty much any window manager (the only requirement is that the WM must be compatible with the EWMH specification). Turns out a one-liner shell script will suffice (make sure you have wmctrl installed, it should be in your distro's default repositories):

#!/bin/bash
wmctrl -x -a "$1" || $2

For reference, here are some extracts from wmctrl --help:

-a <WIN>    Activate the window <WIN> by switching to its desktop
            and raising it.
-x          Include WM_CLASS in the window list or
            interpret <WIN> as the WM_CLASS name.

How does this work? The part before the || checks if a running application's class name (or any case-insensitive substring of it) matches the string given by $1; if yes, it raises that application. If not, it simply runs the command given by $2, so we'll pass in a command that runs our application. Pretty straightforward.

However, if you have multiple windows for an application open, then this will only be able to switch to one of the windows; there is no way to cycle between them, like the Awesome WM implementation.

Now, in most cases, the first and second arguments ($1 and $2) will be the same. In the rare case when it does not work, you need to find out what class name to pass as $1. Run your application and check the output of wmctrl -l -x. The third column should give you the application class (it's always of the form *.*). Here's wmctrl --help on the -l switch:

-l          List windows managed by the window manager.

Let's see how to use it. Save the script as /usr/local/bin/run-or-raise, then make it executable:

$ sudo chmod a+x /usr/local/bin/run-or-raise

Finally, bind keyboard shortcuts to specific invocations of run-or-raise for your favourite applications. Sample invocations:

$ run-or-raise firefox firefox
$ run-or-raise emacs "emacsclient -a '' -c"

Note how, in the first invocation, even though the WM_CLASS for Firefox is "Navigator.Firefox", we can pass a case-insensitive substring of it.

On my setup I have the following keys set to run or raise specific applications:

  • Super+F => Firefox
  • Super+C => Chromium
  • Super+E => Emacs
  • Super+T => Terminator
  • Super+G => PDF viewer
  • Super+S => File Manager

Another alternative

There's another, easily scalable alternative to Alt+Tab: incremental filtering on a window list. No matter how many windows you have open, it should work reasonably well. It essentially changes the behaviour of Alt+Tab from sequential access through a most-recently-used stack to random access in a list of applications. Hence the easy scalability. I know of only 2 pieces of software that do this: the "Scale Window Title Filter" plugin in Compiz, and "Switcher" for Windows, of which I have used the former.

This is similar to the searchable user interface concept from an earlier post. But it's still not in wide use. I guess I'll just have to wait for the future to arrive.

Thoughts, comments, questions?