Soma's Blog

December 2, 2009

Window Shortcuts for Linux

Filed under: Linux,Python,Ubuntu — somanov @ 22:14

One thing that has bugged me for a long time ( no matter on what operating system) is the overhead for task-switching.

On my typical desktop there are a lot of open applications (these include Eclipse/KDevelop, some simple Text Editor like Kate or PSPad, Firefox, SSH sessions in consoles, QGis, a chat client etc.) and I typically do a lot of switching between them.

Naturally there are various ways for task-switching built into the Desktop.  These include the taskbar, the ALT-TAB shortcut or the (admitteldy great-looking) Expose Feature (“Present Windows”) many of the newer Linux Desktops are offering. But I find all of these methods counter-intuitive because they require me to visually search for the window and recognize it by its name or appearance.  The situation gets even worse when you have several instances of the same program -probably spread over multiple Desktops- and you need to find the correct one (as it is often the case with file-managers for example).

Long story short: I find the process of visual task-switching unecessarily complicated and overall disruptive for my concentration.

At this point I have to confess that I am a sucker for keyboard shortcuts. Sure they require a little extra effort to memorize, but once that is done they are real time-savers.

A task switching behavior that much better fits my way of thinking would look like this: Assign a Keyboard shortcuts to the most used applications. (eg.: WIN+f–>firefox) If this shortcut is pressed…

  • ..and no instance of firefox is currently running then start a new one
  • .. and a firefox instance is running then switch to it (no matter on which desktop it might currently be hiding)
  • .. and several instances of firefox are running then cylcle through them (pressing the shortcut repeatedly)

I am aware of the different Window Shortcut features that are built in various Linux desktops, but as far as I could find out none of them fit all the above requirements. After a lot of googling I stumbled upon this gem which nearly perfectly does what I want, except for the “cycling through windows” feature. To customize it to my exact needs I decided to do a rewrite of the script in Python. The result works beautifully for my needs on recent Ubuntu versions.

The script makes use of the wmctrl utility which can easily be installed with

sudo aptitude install wmctrl

Here is the “focus” script:

#!/usr/bin/env python
import os
import sys
import commands

program_name = sys.argv[1] # the program to be focused

# get all windows which contain "program_name" from wmcontrol
candidates = sorted([x.strip() for x in commands.getoutput(""" wmctrl -l -x | awk -v win="%s" 'tolower($0) ~ win {print $1;}' """ % (program_name, )).split("\n") if x !=''])

if candidates : # at least one candidate found , we need to check if the active window is among the candidates (for cycling)

        # Get the id of the active window

        # Note: wmctrl currently does not support getting information about the active window.  In order to realize this
        #       we use xprop here. Unfortunately xprop gives us the window id of the active window in a different format:
        #       Window ids from wmctrl always begin with 0x followed by 8 digits (leading zeroes for padding). xprop
        #       does not do the padding and might give a window id starting with 0x followed by only 6 digits. The
        #       lines below get the id of the current window and make the id returned by xprop comaptible with
        #       the window ids returned by wmctrl.
        active_window_string = commands.getoutput("""xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)" """)
        active_window_string =  active_window_string[active_window_string.find("#")+4:].strip()
        active_window = "0x" + "0" * (8-len(active_window_string)) + active_window_string

        next_window = None # the window to display. (one of the windows in candidates)
        if active_window not in candidates: # if the active window is not among the candidate windows
                next_window = candidates[0] # ..just show the first candidate window
        else:# we are already showing one of the candidate windows
                next_window = candidates[ (candidates.index(active_window)+1) % len(candidates)] # show the *next* candidate in the list (cycling)

        if next_window:
                os.system(""" wmctrl -i -a "%s" """ % (next_window,) ) # tell wmcontrol to display the next_window
else : # no windows open which fit the pattern of program_name
    os.system("%s &" % (program_name,)) # open new window

You can put it in your PATH and then use xbindkeys (or some other keyboard shortcut utility of your choice) to create mappings like

WIN+f –> focus firefox

I have defined shortcuts for my 5 most used applications, and have been using them for about half a year now. I feel this has really helped me to streamline my interaction with the UI.

Advertisement

3 Comments »

  1. This is amazing! I just moved over from windows to Ubuntu and used keyboard shortcuts for everything and was feeling handicapped till I came across your post.

    Comment by Anonymous — January 11, 2010 @ 18:41 | Reply

  2. Here is a slightly enhanced version:
    http://blog.pyte.hu/2010/04/window-shortcuts-for-linux.html

    Comment by Adam — April 13, 2010 @ 09:42 | Reply

  3. Great, thanks! I have been wanting to fix this problem for a long time but never got to it 🙂

    Comment by somanov — April 13, 2010 @ 10:33 | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: