banner
Previous Page
PCLinuxOS Magazine
PCLinuxOS
Article List
Disclaimer
Next Page

Just Xdo It!


by critter

A few months ago my main machine died and I couldn't afford to fix it: the money was required more urgently for other purposes, as my wife reminded me. I was left with a five year old Lenovo laptop which, while perfectly serviceable, was prone to running hot. I had been using KDE but now I needed something a little lighter, something that used fewer resources and so did not push my poor laptop quite so hard.

After experimenting with all of the better supported desktop environments and window managers I settled for the PCLinuxOS Mate 64 bit offering. I wiped the hard drive, removing Windows and the recovery partition (this had been the laptop I used when I was working, and now I am free to choose).

Booting into this, I found that I had a fully operational desktop using just over 200MB of RAM and with both processor cores running at between 1% - 2%, processor clocked at half speed and the fan not even running yet - excellent!

But, and there had to be a but, Mate does not have all of the features of KDE, and some of those features I found really useful, so I started to search the internet for solutions. During my search I came across an article by a very resourceful young man named Eric Zhiqiang Ma which used a utility called xdotool (it's in the PCLinuxOS repositories) to pop up a gnome terminal on the desktop whenever a particular key combination was pressed. Now guake works similar to this as does KDE's yakuake, but this script allowed me to use my mate-terminal which is an excellent terminal emulator and requires no additional dependencies to be loaded. I could, of course, have chosen any terminal emulator application.

What follows is how I used this utility in the Mate Desktop Environment, but it should all work on almost any desktop (perhaps enlightenment may have problems, but I don't know, I haven't tried it). I installed xdotool then downloaded the script and changed the line

gnome-terminal --maximize &

to

mate-terminal --geometry 120x36+180+100 &

And set it to run when F12 was pressed (System-Preferences-Keyboard Shortcuts). It worked flawlessly. How it does it is explained in the article referenced by the link above.

Obviously if this technique works for a terminal then it should work for other applications. For many years I have used conky to monitor and display system usage and statistics. Conky is unusual in that it can sit on your desktop with a transparent background giving an unobtrusive report of whatever details you have decided it should display. This however has the disadvantages that the colors must be chosen to be visible against each background you display and that other running applications must moved or resized in order that it may be seen. By making the background opaque and selecting a color scheme that blends with my current desktop theme I can use this same method to attach conky to a hot key and have a "now you see me, now you don't" system monitor which I can refer to without interrupting my current desktop arrangement and that is also always perfectly legible whatever background image I use.





So, what else can this xdotool utility do? Quite a lot, as it happens. It can send keystrokes to applications, intercept and modify keystrokes before sending them. It can also send typed messages to any available window, even delaying the appearance of each letter as it would appear if typed in real time (or, for those who remember them, on the old teleprinters.). It can move the mouse pointer to any position, to any application or to any screen using absolute, relative or even polar coordinates. The mouse position can be retrieved, mouse clicks simulated and operations may be performed on such events as entering or leaving a particular window or the cursor hitting a screen edge or corner. It can retrieve the window name, geometry and status, move, resize, focus, show, hide or kill a window. You can also move to a different workspace or send a window there and add or remove workspaces. When an event occurs it can execute a command or script. The commands can be stored in a file and either redirected to xdotool or executed directly if a 'bash style' header is included as the first line:

#!/usr/bin/xdotool

Note: This only works if all of the commands in the script are xdotool commands.

So, although there is no mention of it curing the common cold, it does seem to be quite a useful tool to know about. One of the things that I missed from KDE was hot screen edges and corners but xdotool provides this and takes it a step further. I have a little home made application called launcher.sh that allows me to quickly select from my most common applications.



I thought that it would be nice to have instant access to this by activating a hot spot with the mouse cursor. To achieve this I set up an xdotool command to run on startup:

System-Preferences-Startup Applications

xdotool behave_screen_edge --delay 800 --quiesce 1500 bottom-right exec /bin/launcher.sh

The above is all one line and should be entered into the Startup Applications dialog 'command' box. This is what it means:

xdotool call the utility.
behave_screen_edge look for the mouse pointer hitting a screen edge or corner and perform the following actions.
- - delay 800 wait 800 milliseconds before triggering the event to avoid accidental triggers.
- - quiesce 1500 don't perform any other action for another 1500 milliseconds this prevents multiple instances being launched before you move the mouse away from the hot spot.
bottom-right the screen location to monitor.
exec execute something when the trigger is pulled.
/bin/launcher.sh the something to execute.

Using this hot-spot, I move the mouse to the bottom right corner, the application is launched (in this case my home brewed script but it could be any application you wanted), I then click the required icon and the relevant application is launched. This a lot quicker and more convenient than hunting through multiple menu layers. You may use any side or any corner as a hot spot: left, right, top, bottom, top-left, top-right, bottom-left or bottom-right as I have used here. The delays above work for me, but you may prefer to change them.

Virtual desktops or workspaces have been a feature of Linux for many years now and they are an excellent aid to productivity allowing you to flip rapidly between different sets of applications or to start a new task on a brand new, empty desktop. But how many desktops should you have? Too many and you lose track of where things are and have to hunt through them, too few and you run out of space.

I start with 2, the one I'm on and a spare. If I run out of space I press a key combination and xdotool creates a new one for me. When I want to remove the additional desktops a different key combo will tell xdotool to remove them, one at a time. Any applications still open on the removed desktop are not lost but moved to the desktop on the left.

The code to do this is:

xdotool set_num_desktops $(( $(xdotool get_num_desktops) + 1 ))

and

xdotool set_num_desktops $(( $(xdotool get_num_desktops) - 1 ))

Typing this every time to add or remove a desktop is obviously not good and so I store the code as two scripts simply adding a one line bash header at the beginning of each file. For example:

#!/bin/bash
xdotool set_num_desktops $(( $(xdotool get_num_desktops) + 1 ))

The scripts are saved as addwkspc and rmvwkspc, and are then made executable with:

chmod +x addwkspc
chmod +x rmvwkspc

The #!/bin/bash header is required, rather than the xdotool header mentioned previously, as some bash features (arithmetic expansion and sub shells) are included with the xdotool commands but you can use the scripts without having to understand the finer details. You can then assign each script to a keyboard shortcut (I use Ctrl+F7 and Ctrl+F8) making sure that you give the full path to the file, perhaps /home/me/addwkspc or similar.

Note: If you are using Mate there used to be an option in the workspace switcher preferences to set the number of desktops. In the current version -- 1.8.2 this seems to be missing.
To set this value permanently on startup, open
dconf-editor Applications>More Applications>Configuration>dconf Editor.
Navigate to
org>mate>marco>general
and change the num-workspaces value there, which defaults to 4.
Alternatively use xdotools set_num_desktops as a startup application.

Xdotool also gives you the ability to move between the various desktops in almost any manner that you can think of. As moving backwards and forwards one desktop at a time is already catered for in Mate, I haven't found it necessary to use much of this facility. I feel that this rather defeats the object of simplicity. However, the options are there if you want them.

Manipulating windows is one of the great strengths of xdotool, and it has allowed me to add some of KDE's functionality to Mate. In KDE it was possible for me to have a particular window or application startup on a particular desktop, in a predetermined position and of a chosen size meaning that I always knew where it would be. This is also possible in Mate with the help of xdotool, although there is a little more effort required to set it up. This only needs to be done once, however.

To perform operations on a window you have to know something about it: its window id, the window name (as it appears in the titlebar), the window class or the window classname for example. These are things that your window manager uses to refer to individual windows. The xdotool utility can get these details for you but I use another utility called xprop which, if not already installed, can also be found in the PCLinuxOS repositories.

If I want to have pluma, Mate's text editor, open in the same place and the same size whenever I open it, then I need to know how to refer to that window. The window id is assigned by the window manager and is not consistent across instances. When I first open pluma the window name (title) is "Unsaved Document 1 - pluma ", if I close the empty document tab it is a simple "pluma" but when I open or save a document this changes to incorporate the document name. The window class will however always be the same and to find this I open pluma and use the xprop command, piped to grep to display only the information I need as xprop is very verbose without this:

xprop | grep CLASS

Which waits for me to click inside the window for which I want the properties and then returns

WM_CLASS(STRING) = "pluma", "Pluma"

I can use either pluma or Pluma to refer to my pluma window, as both will work.

Alternatively, the class may be overridden by calling pluma with the GTK+ - -class option. To move and resize this window, I must tell xdotool to search for a window of class pluma and then to perform the operations on it. The code to move the window to the top left corner ( 0 0 ) and resize the window to 700 x 500 pixels becomes:

xdotool search --class Pluma windowsize %@ 700 500 windowmove %@ 0 0

However, this will only work if the application is already running. To launch an application and then apply xdotool commands to it requires a little more work. In a bash script launch the application and put it in the background by following it with &. Then issue the disown command which breaks the relationship between the bash script and the application allowing them both to continue running independently. Finally issue the xdotool statement with the - -sync option to the xdotool search command. This option tells xdotool to wait until the application window is visible before applying the size and move commands. Here is the script.

#!/bin/bash
/usr/bin/pluma &
disown
/usr/bin/xdotool search --sync --class Pluma windowsize %@ 700 500 windowmove %@ 0 0

The last line should be all on one line. This script is not the cleanest implementation of achieving these results as it briefly shows the application before moving and re-sizing it but that is a small price to pay for simplicity.

As your window manager may have several references to an application the %@ is required to ensure that xdotool catches the one that you need.

This may seem confusing, so by way of explanation I shall refer to an example from xdotools own documentation. By default, pluma allows only one instance to be displayed. If you try to open a new instance of pluma, a new tab will be opened. Other applications allow you to litter your screen with as many instances as you want. Mate-terminal is one such application. Each instance is referred to as a position on a stack of window ID's, which is how the window manager knows each window. The first window of the classname mate-terminal is referenced as %1, the second as %2 and so on, %@ refers to all of them. Similarly, the parameters passed to a script are referenced as $1, $2 … This script (I have named it fourterms) contains only xdotool commands, and so begins with the xdtool header rather than the bash header. This is more efficient, as bash is not required.

#!/usr/bin/xdotool
search --onlyvisible --classname $1
windowsize %@ $2 $3
windowmove %1 0 0
windowmove %2 $2 0
windowmove %3 0 $3
windowmove %4 $2 $3

Make it executable.

chmod +x fourterms

Open four terminal windows and then call the script with a command such as

./fourterms mate-terminal 800 500



Only windows that have the classname 'mate-terminal' (the first parameter passed to the scipt) and are visible will be acted upon.

The line that reads

windowmove %4 $2 $3

will move the fourth window (%4).

To position $2 (the second parameter -- 800) in the x direction and position $3 (the third parameter -- 500) in the y direction. 0 0 is the top left corner of the screen.

To simultaneously move the terminals to say desktop 3 (make sure that desktop 3 exists and notice that desktop numbering starts at 0 so this would be the fourth desktop) add the following lines to the script.

set_desktop_for_window %1 3
set_desktop_for_window %2 3
set_desktop_for_window %3 3
set_desktop_for_window %4 3

And you will get a nice array of terminals on that desktop.



If you frequently use the same set of applications arranged over a number of desktops to perform a task, then xdotool can be configured to perform all of the opening, re-sizing and moving around as well as setting up the correct number of desktops, all from a single key combination.

Sometimes you will want to do something with a window of your choice at the time rather than a particular, pre-chosen window. Perhaps you would like to have a hotkey that would instantly move a window that is cluttering your desktop, but that you have not actually finished with. Move it to perhaps the fourth desktop (number 3), which you can later jump to and continue using it. In this case, you can't know the window ID or window class or any of those things, and so xdotool has the selectwindow command. When xdotool is given this command, it knows to wait for you to click on a window and then performs any additional commands on that window.

xdotool selectwindow set_desktop_for_window 3

Adding that line to a keyboard shortcut, perhaps winkey+4, will send the next window that you click on to the fourth desktop.

Often, I have Firefox open somewhere or other and I suddenly need to access a particular website. The following line of code will find Firefox, move it to the desktop where I have placed it, give it the focus (activate it), move the cursor to the address bar (ctrl+l) and clear any text there (BackSpace) allowing me to instantly start typing the address of the required website.

xdotool search "Mozilla Firefox" windowactivate -sync key ctrl+l key BackSpace

All of this must be on one line, and can be hooked up to a shortcut key combination.

That then covers the basics of xdotool. The man page covers all of the available commands and options and with these few examples you should be able to make use of any that interest you. How much use you get from this utility depends upon your requirements and not from any ability to perform complex programming. For me it did a nice job of bridging the gap between the mighty but demanding KDE environment and my lean, mean Mate machine.



Previous Page              Top              Next Page