Scripted Window Actions
Tutorial – Devilspie2
Stop battling your window manager to position things as you like – make scripts do all the hard work!
How many window managers (WMs) and desktop environments can you name? If you've been around the Linux or BSD scene for a while, you can probably come up with 10 or 20 – and there are even more. For new users, this sheer variety may seem perplexing. After all, a WM just lets you shove windows around on the screen, right? Why not just make a single WM to rule them all?
Well, as you know, different WMs and desktop environments target very different types of users. Some prefer minimalistic WMs with tiny window borders, driven primarily by keyboard shortcuts – whereas others want all-singing, all-dancing showcases of beauty and functionality. In any case, they all have limitations, especially in terms of automation.
Now, why would you want to automate a WM? Don't they already do some tasks automatically, like putting new windows in certain places to reduce overlap? Well, yes, but that's about it. Wouldn't it be awesome if you could create custom scripts to move, resize, minimize, or maximize windows automatically when they pop up? Or move them to specific workspaces or virtual desktops? Or even make them sticky across all desktops?
That's what Devilspie2 [1] does. It's a "window matching utility, allowing the user to perform scripted actions on windows as they are created." As the name suggests, it's a follow-up to an older program called Devilspie that did a similar job but used its own custom scripting syntax. Devilspie2, however, uses the popular Lua scripting language [2], letting you create powerful setups for almost any purpose.
Over the next few pages, I'll show you how to get started with Devilspie2, perform basic window operations, and build up more complex scripts. You'll see how tedious, everyday window management tasks can be automated, letting you focus on getting things done instead of trying to grab teensy little window borders with the mouse (or remembering a bunch of keyboard shortcuts).
Fire It Up
Before starting to using Devilspie2, you might be thinking: Which WM or desktop environment is most suitable for this program? Ultimately, it works with pretty much every WM out there, but if you want to focus on getting things done quickly, it's worth also investigating a lightweight WM or desktop environment such as Openbox, LXDE, or even Xfce. The good thing is that Devilspie2 works independently, so the techniques you learn here can be applied to other WMs, even if you change further down the road.
Devilspie2 is available in the package repositories of most distributions, so just fire up your package manager to grab it, or get it from the command line on Debian/Ubuntu-based distros like so:
sudo apt-get install devilspie2
Make sure to specify the 2 at the end, though, because the older version is still provided in many repositories – but it won't work with this tutorial! If you can't find a binary package for your distro, you can compile the source code, which is available on the program's website; it doesn't have many dependencies.
In a terminal window, enter devilspie2
to start it, and you'll be greeted with:
No script files found in the script folder - exiting.
You'll land back at the command prompt. That's not very friendly, is it? Well, Devilspie2 on its own doesn't do anything in particular – you need to give it some actions (via scripts) before it becomes a useful tool. But where do you place these scripts?
If you go to .config/devilspie2/
in your home directory – which was created when you ran Devilspie2 the first time a moment ago – you'll see that it's empty, so create a simple script to give Devilspie2 something to do. Before you can start working with windows, you need to learn how to identify them, so create a plain text file called debug.lua
with the following content:
debug_print("Application: " .. get_application_name()) debug_print("Window: " .. get_window_name());
Save this in .config/devilspie2/
and then run the program:
devilspie2 --debug
With this command, Devilspie2 loads the debug.lua
script you created and also interprets the debug_print
commands you added. Leave Devilspie2 running in the terminal, and try clicking around in other windows on your desktop and starting new programs. Each time you open a new window (e.g., by starting a program), you'll see some output in the terminal – this shows how Devilspie2 is identifying each window (see Figure 1).
This output will be important when you begin writing scripts. By taking note of the application and window names, you can use them to tell Devilspie2 to work with specific programs and windows. Usually the program name is the same as you'd find in your menu or package manager – but sometimes there are subtle differences, which is why it's important to do this step.
For instance, if you start the Thunderbird email client and write a new message, you end up with two windows: one for the main Thunderbird view, and one for the message you're writing. As you can see in the Devilspie2 output, they both come under Thunderbird for the app name, but the window names vary. You can stop Devilspie2 from running by pressing Ctrl+C in the terminal window.
I Like To Move It
Now that you can identify apps and windows, you can do things with them! Say that you want to set the exact position and size of new Firefox windows as they're opened. Using the debugging script you created before, you can see that the main window of Firefox is called, sensibly enough, Mozilla Firefox. But how do you tell Devilspie2 to select this window? Try adding this to the debug.lua
file, and run Devilspie2 again:
if (get_window_name() == "Mozilla Firefox") then set_window_geometry(50, 100, 800, 600); end
If you're not familiar with Lua, you can see that the syntax is a bit like a mixture between C and Bash scripting. In any case, for Devilspie2, you're not going to be making very complex scripts – so this syntax is all you need to know.
And as you've probably guessed, you ask Devilspie2 to check whether the currently selected window has the title Mozilla Firefox, and if so, you set its geometry. But what do these four numbers mean? In this case, they refer to x, y, width, and height values, so you tell Devilspie2 to place newly created Mozilla Firefox windows at 50 pixels from the left of the screen and 100 from the top and to set the window at 800 pixels wide and 600 pixels high.
Try running Devilspie2 and opening and closing Firefox, resizing and repositioning the window each time. Whatever you do, when you restart Firefox, it always appears at the exact same position with the exact same size. This is very useful if your favorite WM tries to be "clever" by automatically shuffling things around, but you really want a certain app always to be in a specific place and with a specific size.
Many programs remember their window size when you close them and, indeed, whether they were running in a maximized state. Some apps don't pay attention to this, however, but Devilspie2 can help out here as well. Say you always want LibreOffice Writer to start in maximized mode, regardless of what it remembers from last time (or what the WM wants to do with it). Using the debugging info, you see a potential problem: The window names for LibreOffice Writer can change (Figure 2).
For instance, with a blank new document it's Untitled 1 – LibreOffice Writer, but if you create another document or open an existing one, then the name will change. This means that a direct match with the Devilspie2 get_window_name()
routine isn't possible – you need to be a bit more flexible. Fortunately, Lua lets you do this by using string.match()
, like so:
if string.match(get_window_name(), "LibreOffice Writer") then maximize(); end
In this case, you're just checking to see whether the string "LibreOffice Writer"
can be found somewhere in the output of get_window_name()
– the strings don't have to be identical, but if there's a match, you use maximize()
to make the window fill up the screen (but not covering docks or menus).
Try it – every time you open a new LibreOffice Writer window, it will start maximized, regardless of the window geometry from the last execution of the program. Note that some extra maximize functions are available in Devilspie2, such as maximize_vertically()
and maximize_horizontally()
, along with unmaximize()
, which you can use if an app stubbornly refuses to start in anything but a maximized mode. If you always want a certain program to start minimized, you can do that with the minimize()
routine, as well.
Working with Workspaces
Here's another scenario: You always want to open a specific app on a specific workspace. Some more advanced WMs provide facilities to do this, but Devilspie2 lets you do it regardless of the WM or desktop environment you're using. Starting with the LibreOffice example, again, say you always want LibreOffice windows – whether Writer, Calc, or the options or save dialogs – to open in the second workspace.
You can try to do a match using get_window_name()
again, but if you open LibreOffice and do various tasks, you can see that they all come under the app name LibreOffice 5.4. (Of course, if you're running an earlier version of the suite, you will see a different number there.) Instead of trying to match windows by name, just tell Devilspie2 to put everything under "LibreOffice 5.4"
on the second workspace:
if (get_application_name() == "LibreOffice 5.4") then set_window_workspace(2); end
Now try launching various LibreOffice components, such as Writer, Calc, and Impress; you'll see that they all get placed automatically on the second workspace, thanks to Devilspie2. (If the splash screen appears elsewhere, you might need to set up an additional rule covering just "LibreOffice"
for the app name, alongside "LibreOffice 5.4"
.)
One problem here is, you might find it a bit jarring that certain apps start up on other workspaces – wouldn't it make more sense to switch to that workspace beforehand? This is also possible using change_workspace()
and placing a numerical value between the brackets.
There are some other useful things you can do regarding workspaces as well. For instance, with the pin_window()
routine, you can tell Devilspie2 to make a window appear across all workspaces; that is, it's always visible, even when you switch to a different workspace. This setting is useful for certain small widgets like system monitors or music players that you always want to have visible in the corner of the screen.
Similarly, Devilspie2 provides ways to add and remove "decorations" from windows. In X Window System parlance, these decorations refer to the titlebar and handles around the outside of the window. If you have a cool little applet or monitor that you want to put in a specific place on the screen, without the WM adding extra fluff around it, Devilspie2 is a godsend: Use it to position the window exactly on the screen, make it available on all desktops with pin_window()
, and then remove its decorations.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.