arranging windows from the gnu/linux command line with wmctrl

A reboot of my computer recently caused me several hours of work. Nothing went wrong; the machine and Ubuntu started fine. No, I had to spend the time to save time. I was just trying to make things easier and more efficient, you see.

I rarely restart my home computer. If an occasional software update wants me to do it, I mentally cringe because it will mean several minutes of starting and arranging windows. I always have a collection of terminal, editor, and browser windows open and arranged just so. Things are coordinated between left and right monitor and a double-decker taskbar list. I can quickly move between windows and have everything lined up conveniently side by side and top and bottom, and all is well with the world. But then comes the reboot.

More frequently there is the need to restart Firefox. I like Firefox, but it leaks like a sieve on my machine. Maybe it’s all the plugins that are to blame, but in any case, after running for two to three days it takes over a gigabyte of memory and grows progressively slower as it passes the 1.5 GB mark. Even if it only takes a couple of minutes to start and position new browser windows, the mental wind resistance is strong.

Clearly this is a situation that calls for a scripting diversion. There’s nothing quite like the satisfaction of scripting away the tedium of a repetitive task, even if the time to learn and write the script adds up to months or years of doing the task itself. The resulting diminishment of psychic drag is liberating.

So, I looked for ways to automate or programmatically set window positions in GNU/Linux. The first thing I found was Devil’s Pie, which may have been suitable for the task, but later found and used wmctrl. (Both were available via apt-get in Ubuntu 9.10.)

Wmctrl provides command line access to EWMH/NetWM compatible X window managers. EWMH is the Extended Window Manager Hints specification. That didn’t mean much to me at the time, but I learned that window managers implementing this specification include GNOME’s Metacity and KDE’s KWin, among many others. You can use this program to get a list of virtual desktops and open windows, resize and move windows, switch between desktops, and more, more, more.

The wmctrl home page has useful information, and the man page is helpful, but I thought I’d throw a few examples and comments from my own experience out here, as always with the hope that I might contribute in some small way to the greater free software good.

You can get information about your virtual desktops (workspaces) with wmctrl -d:

0  - DG: 2944x1280  VP: N/A  WA: 0,25 2944x1004  [First]
1  * DG: 2944x1280  VP: 0,0  WA: 0,25 2944x1004  [Second]
2  - DG: 2944x1280  VP: N/A  WA: 0,25 2944x1004  [Third]

And list open windows with wmctrl -l. The -G option shows you the geometry of the windows:

0x042000af  0 1988 71   956  978  bigbird Unsaved Document 2 - gedit
0x03e00a84  1 0    46   1024 1256 bigbird Moving to Freedom - Mozilla Firefox
0x018225e4  1 1031 71   956  469  bigbird scarpent@bigbird: ~

Switch to a different virtual desktop with the -s option. For example, go to the first desktop with: wmctrl -s 0. I had some odd behavior at first when I used other methods of moving windows to different desktops. I’m not sure what that was all about, but using -s before starting and rearranging windows worked much better for me.

Note, 29 August 2010: I recently discovered after upgrading to Ubuntu 10.04 (“Lucid Lynx”) that if visual effects are enabled (in System » Preferences » Appearance), multiple desktops/workspaces will appear to wmctrl as one big area, like so:

0  * DG: 8832x1280  VP: 0,0  WA: 0,24 2944x1256  [First]

And the -s action will have no effect or will cause an error if something other than 0 is given. wmctrl will still work for launching windows, but it seems you have to already be in the desired workspace when running it.

You can specify a window by referencing its title or partial title after -r. -e is for moving and resizing:

wmctrl -r "Mozilla Firefox" -e <G>,<X>,<Y>,<W>,<H>

From the wmctrl documentation:

<G>: Gravity specified as a number. The numbers are defined in
     the EWMH specification. The value of zero is particularly
     useful, it means "use the default gravity of the window".
<X>,<Y>: Coordinates of new position of the window.
<W>,<H>: New width and height of the window.

So, to move a window to the upper left corner and make it 1000 pixels wide by 700 tall, you’d use 0,0,0,1000,700.

What if there is more than one window with the same title? For example, “Mozilla Firefox.” For that, I turned to the -l window list command. It seems that the list is in order with newly opened windows appearing at the bottom. I wrote a bash function to find the most recent one so that I could extract the unique numeric window ID:

function get_window_id() {
    window_id=$(wmctrl -l | grep "$1" | tail -1 | cut -f1 -d" ")
}

And then you can use the -i option to tell it to interpret the -r argument as a numeric window ID, like so:

get_window_id "Mozilla Firefox"
wmctrl -i -r "$window_id" -e 0,1025,0,953,100

In your script, you control when windows are created, so you can make assumptions about the most recent instance being the one you want to position.

On another Firefox note, I saw where people have struggled with it because Firefox will remember its window state from when it last closed. If it was maximized, it will start maximized, which can cause problems when you try to move/resize it. For that, I used the workaround of “unmaximizing” it first, using the -b option.

-b can be used to change the state of a window. There are many window state properties defined by the EWMH spec, not all of which made sense to me, or for which I could find good explanations. But I eventually figured out that you can restore a window to a non-maximized state with this command:

wmctrl -r "Mozilla Firefox" -b remove,maximized_vert,maximized_horz

If it’s already not maximized, then that seems to be fine. It has no effect. Then you can move/resize the window, and then maximize it again if you so desire, with:

wmctrl -r "Mozilla Firefox" -b add,maximized_vert,maximized_horz

In addition to the add and remove actions, there is also toggle.

Note that sometimes you “don’t need no stinkin’ helper programs.” For Gnome Terminal I used the built-in --geometry <width>x<height>+<x>+<y> option. In this case, width and height are given in terminal characters instead of pixels. To position a window on the upper left corner of my right monitor, I used gnome-terminal --geometry 117x26+1025+0.

sleep statements are helpful to make sure things have time to start or be ready for “unmaximization.” Don’t fret over the delay. If it takes a few more seconds, that’s just more time to bask in the glory of your new automated process. Example:

gedit --new-window &
sleep 1
get_window_id gedit
wmctrl -i -r "$window_id" -e 0,1025,0,953,1000

Don’t forget to use ampersands where necessary to background the process. With gedit, for example, I’m used to launching new windows in an existing process where it’s not necessary to background each one. But if you’re running a script and you launch the first instance, your script will halt if you don’t background it.

12 thoughts on “arranging windows from the gnu/linux command line with wmctrl

  1. I suggest trying a tiling window manager.
    I use StumpWM, but I hear good things about Xmonad.
    Then you can set up the layout before you start them.

    wmctrl seems to be a hack to give what this variety of managers has already.

  2. According to memory leaking Firefox – you can switch off memory cache (in about:config) – that may help. At least my Firefox doesn’t use so much memory event after few day usage (Debian here), and I always turn off memory cache (IMHO it’s waste of resources to cache pages in memory – here is disk cache in the system already…).

  3. Great little tutorial. Thanks for the examples. Now I am off to write my own shell-based window arranger!

  4. Also.. I use this command to right-align my the active window (half screen width and maximized vertically):

    wmctrl -r :ACTIVE: -b remove,maximized_horz,fullscreen && WIDTH=`xdpyinfo | awk ‘/dimensions:/ {print $2}’ | cut -f1 -d’x’` && wmctrl -r :ACTIVE: -b add,maximized_vert && WDT=$(($WIDTH/2)) && wmctrl -r :ACTIVE: -e 0,$WDT,0,$WDT,-1

  5. Good tutorial. Was searching for a way to position gnome-terminal. Knew how to size it. But got the syntax for positioning it. The gnome-terminal help doesn’t mention this. Thanks

Comments are closed.