I just installed Xubuntu 12.04. I like it so far and am getting used to differences (was on Ubuntu 11.10 before). One thing that I had with Ubuntu by default was Compiz. It has a lot of plugins, one of which I used a lot was Compiz Put plugin. I could not find a similar thing in Xfce – there are shortcuts to move between workspaces, but not between the monitors that belong to one workspace.
Now I searched over the net and found some useful things – one of them is xdotool. It’s a nice utility that allows you to perform different operations on available X windows, such as move, hide, maximize, etc. Xfce has keyboard shortcuts readily available – Main menu / Settings / Settings Manager, Keyboard, Application Shortcuts tab. These allow you to bind a keyboard shortcut and run any application, including bash scripts, with it. Exactly what I need here – make a xdotool script that moves the window left or right, depending on the current position.
Searching for a window
To do something to a window, you first search for it. You can do this using the following command:
wid=`xdotool search --name Calculator|head -1`
The above will yield the window ID of the first found window that has “Calculator” in the default set of search categories (window class, window class name or window name / title).
Displaying the names of all windows
In case you don’t know the name of the window – for example, if you turned off the window decorations – you can use this script to show them:
wids=`xdotool search --name ""` for wid in $wids; do wname=`xdotool getwindowname $wid` if [ -n "$wname" ]; then echo $wid --- $wname fi done
which gives the output such as:
16777220 --- xfce4-panel 50331652 --- xfce4-verve-plugin 54525956 --- xfce4-cpugraph-plugin 37748740 --- xfce4-netload-plugin 52428804 --- xfce4-systemload-plugin 58720260 --- xfce4-xkb-plugin 56623108 --- wrapper ...
One thing you’ll notice is that it’s quite slow – that’s because it needs to spawn a shell and a xdotool instance for each of the window IDs it found in the first line.
Moving windows
Let’s say we wanted to move our calculator instance 10px to the left, just for fun. What we need to do is:
- Find the window ID of the calculator
- Find it’s geometry (position and size)
- Calculate the new value for position
- Move the window there
Here’s a script that does these steps:
wid=`xdotool search --name Calculator|head -1` eval `xdotool getwindowgeometry --shell $wid` X=$(($X - 10)) xdotool windowmove $wid $X $Y
You can test this easily – just run this in a terminal while you have a calculator instance running.
Maximized windows
Now, there’s a slight problem with the above – it doesn’t work with maximized windows. Although that’s not usually a problem (i.e. maximized windows are considered stationary for regular purposes), for the purpose of moving to the other monitor this will be a problem. There’s another utility – wmctrl – that can be used for this job:
wid=`xdotool search --name Calculator|head -1` wmctrl -ir $wid -b remove,maximized_vert,maximized_horz
Similarly, to maximize:
wid=`xdotool search --name Calculator|head -1` wmctrl -ir $wid -b add,maximized_vert,maximized_horz
You can even toggle:
wid=`xdotool search --name Calculator|head -1` wmctrl -ir $wid -b toggle,maximized_vert,maximized_horz
Now, we can use the third tool – xprop – to actually get the state:
wid=`xdotool search --name Calculator|head -1` xprop -id $wid _NET_WM_STATE
This should print something like this:
$ xprop -id $wid _NET_WM_STATE _NET_WM_STATE(ATOM) = $ xprop -id $wid _NET_WM_STATE _NET_WM_STATE(ATOM) = _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT
In the first case, the window is not maximized, in the second case it is (both vertically and horizontally).
Hiding windows
Another issue with this is – if we are to move the windows, it’s going to actually be very flickery. This is especially true if the difference between maximized and minimized versions of the window are great. So, we need to hide / show them before we do all the things. xdotool can do that:
wid=`xdotool search --name Calculator|head -1` xdotool windowunmap $wid
hides the window. To show it:
wid=`xdotool search --name Calculator|head -1` xdotool windowmap $wid
Unfortunately, this is not going to help due to the issue – when the window is shown (mapped), all the changes to its position / size seem to be lost.
Getting the current window
As this is going to be a keyboard shortcut, it needs to work on the current window – xdotool allows getting the current window ID like this:
wid=`xdotool getactivewindow`
Raising the window
When moved to the other monitor, the window may actually be below the other windows, depending on how their creation / switching happened, so we need to raise it – this can be done like this:
wid=`xdotool getactivewindow` xdotool windowraise $wid
Moving the active window to the other monitor (finally!)
Here’s what we need to do:
- Find the active window
- Get its maximized state and remember it
- Remove maximization
- Get its geometry
- Calculate the new position
- Move it
- Maximize based on the previous state
- Raise it
Here’s a script that does that:
wid=`xdotool getactivewindow` max_state=`xprop -id $wid _NET_WM_STATE` wmctrl -ir $wid -b remove,maximized_vert,maximized_horz eval `xdotool getwindowgeometry --shell $wid` new_x=1600 if [[ "$X" -ge "$new_x" ]]; then new_x=0 fi xdotool windowmove $wid $new_x $Y if [ -z "${max_state/*_NET_WM_STATE_MAXIMIZED_*/}" ]; then wmctrl -ir $wid -b add,maximized_vert,maximized_horz fi xdotool windowraise $wid
Some problems
There are some problems with the above that I’ve noticed:
- Obviously, as made works only with two horizontally located monitors side by side
- It’s a bit slow as it spawns a lot of shells / runs a lot of commands
- Although it’s not hard to get one, hard-coding the new_x to the half of your monitor setup speeds this up – a trade-off here
- When you have a panel on one monitor only, moving the windows slides below the panel if they are in the same position on the other monitor