Wednesday, June 4, 2008

xstartonce: Boost your productivity

I've grown accustomed to a way of working on my Desktop which greatly enhances the speed and therefore productivity of working by accelerating switching to certain applications. There are relatively few applications which I use on a daily basis. I'll mention just a few examples here: I use Firefox (well, now it's Arora) for browsing, Vim to edit files, and a shell for doing various stuff. I have to switch between those frequently. Often when coding stuff in Vim, I have to look up information on the net, so I have to switch to Firefox. When I'm done looking up stuff I'll try it out on the console and then switch back to Vim to integrate it into the program. Switching back and forth between applications can be quite a hassle because of the "most recently visited"-paradigm usual implementations of Alt+Tab (or similar) use. The most recently visited window is the one that'll appear first when switching windows. This works great if you have only two windows. It'll get irritating and slow when you have more than two windows and switch back and forth in an unstructured order.


So I've invented this methodology of work: Every regularly used application is assigned a shortcut. It's Ctrl+Alt+F for Firefox, Ctrl+Alt+V for Vim and Ctrl+Alt+C for the console. The program I use for shortcut is selfmade, because it needs one special feature: When the shortcut is activated, the program looks whether there's already a running instance of the application I want to switch to. If there is none, it'll be started (and automatically get the focus). If it is already running, the existing instance will be focused. This works great. When I need my browser, I don't have to think about whether I've already started it, and if so, where have I started it or anything. I just press Ctrl+Alt+F and have a Firefox or Arora window activated.
I have shortcuts for about 8 applications at work, including one or multiple local and several remote consoles, the aforementioned Arora and Vim, Delphi, Microsoft Visual Studio, InstallShield, the production-copy of the application I'm writing and a few more.
Without my shortcut-application I'm really at a loss and struggling with cycling through windows with Alt+Tab.


Until now, there was only one unreleased, Windows-based program which would enable this work-methodoligy: It's called KeyboardGuy, and it's written by me and exclusively used by me.


When I switched to Linux recently, I was really missing that comfort. So I looked for a way to accomplish this with as little work as possible.


The very first try was a shell-script that uses wmctrl to find out the Process- and Window-IDs that I needed. It looked up the process-name via ps and would activate the window if the basename of the specified application and the process-name in ps matched. With my relatively limited knowledge of shell-scripting, I came up with a script like this:

#!/bin/sh

PROCESSES=`wmctrl -l -p | awk '{print $3}'`
DOEXIT=
ps h -p $PROCESSES | while read i;
do
ID=`echo $i | awk '{print $1}'`;
NAME=`echo $i | awk '{print $5}'`;
NAME="`basename "$NAME"`";
if [ "$NAME" = "$1" ]; then
wmctrl -l -p | while read WID;
do
WPID=`echo "$WID"|awk '{print $3}'`;
if [ "$WPID" = "$ID" ]; then
wmctrl -i -a `echo $WID|awk '{print $1}'`
exit
fi
done
fi;
done

echo $DOEXIT
"$1"


There exists one problem, however: The script needs to completely terminate after wmctrl -a is executed. The call of exit that should accomplish this, however, did not work as expected and the line "$1" (which starts the application given as the first parameter) is always executed, even when the window was activated first. Because I was rather unsatisfied with the whole thing and couldn't get it to work, I decided to rewrite it in C++, using Qt (because Qt makes many things much easier for me here, and I wanted to get this done quickly).
The final result is the application which I call xstartonce.

xstartonce


The current version is the second iteration of the C++/Qt-version. The first version would match the basenames of the given application and the path found in ps's output. This leaves one big limitation, though: You can't assign shortcuts to one and the same program. I need this, for example, because I want shortcuts for a local and several remote consoles. Those would look like "urxvt" for the local console and "urxvt -e ssh melchior" for the remote console. Because the basenames match (both are urxvt), the shortcut-application would not be able to switch between those two distinct consoles.

Configuration file


That's why I invented the "named shortcuts". This needs a configuration file (~/.xstartonce), which has a very simple structure: It's <shortcut-name>=<command --param>. My ~/.xstartonce looks like this:

urxvt-local    = urxvt
urxvt-melchior = urxvt -e ssh melchior
firefox = firefox
assistant = assistant
gvim = gvim
vim = urxvt -e vim


Currently, only named shortcuts are possible. This means that for each application you want to launch, you need a configuration-file entry. I've totally abandoned the formerly discussed algorithm to match the basenames of the processes in favor of this approach. I will, however, make both possible in the future. This has an advantage that was bugging me with the Windows-version already: When opening firefox from anything else but my shortcut-app, it'll not get "recognized" by it and a second instance will be opened when using the shortcut next time. With the basename-matching algorithm, I can use apps that I don't want to open twice with distinct shortcuts better.

Temporary Process-ID list


xstartonce creates an entry in /tmp/xstartonce-db.<user-name> for each started named shortcut. The structure is like the configuration-file: <name>=<process-id>. When executing a shortcut, first the name is searched in the configuration. If it is found, the xstartonce-db is searched for the name, and if it is found there, the window-id matching the process is looked up via wmctrl -l -p. If a window is found, it is activated. If either no window or no process is found, the command is executed.

Getting xstartonce


xstartonce has tree dependencies: A C++-compiler, Qt and a UNIX-like operating system with the X window system running. If you meet those criteria, you can download the source-code in my github-repository.

Notice:I'll clean up this blog-post and correct spelling and grammar errors tomorrow. It's already past bedtime, so I'm off to get some sleep :-)


Using keyboard-shortcuts


What I haven't mentioned, yet, is how this all works together with keyboard-shortcuts. Well, the answer is easy: Use whatever tool you know for executing keyboard-shortcuts and run xstartonce instead of the application you want to launch. I'm currently using KDE's shortcut-enabled menus together with xstartonce. You can edit KDE's menu by right-clicking it and choosing "Edit menu". Then you can add new menu-items and assign a shortcut to them.
Here's a screenshot how I do this:
Assigning shortcuts in KDE's menu

No comments:

Post a Comment