Sunday, April 15, 2012
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
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.
And I’m not the only one who feels Alt-tab sucks.
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
“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.
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
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
my 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
installed, it should be in your distro’s default repositories):
#!/bin/bash wmctrl -x -a "$1" || $2
For reference, here are some extracts from
-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
$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.
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 (
$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
-x. The third column should give you the application class (it’s always of the
form *.*). Here’s
wmctrl --help on the
-l List windows managed by the window manager.
Let’s see how to use it. Save the script as
make it executable:
$ sudo chmod a+x /usr/local/bin/run-or-raise
Finally, bind keyboard shortcuts to specific invocations of
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+G=> PDF viewer
Super+S=> File Manager
There’s another, easily scalable alternative to
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. Guess I’ll just have to wait for the future to arrive.
Thoughts, comments, questions?