Scripted Window Actions

Tutorial – Devilspie2

Article from Issue 205/2017

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).

Figure 1: In debug mode, Devilspie2 shows how it identifies apps and windows, so you can use those names in your scripts.

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);

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).

Figure 2: Here, you tell Devilspie2 always to start LibreOffice Writer in maximized mode, regardless of the window geometry when it was closed.

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

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

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

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Brightside and Devil’s Pie

    If the no-frills Metacity window manager doesn’t give you the functio nality you need, try the Metacity add-ons Brightside and Devil’s Pie.

  • Introduction

    This month in Linux Voice.

  • Pipelight: Using Silverlight on Linux

    Video-on-demand services often don't play well with Linux because they depend on Microsoft's Silverlight browser plugin. Luckily, you can call on the Wine offshoot Pipelight to rescue your next home movie night.

  • Flash Plugins in Linux

    PPAPI, NPAPI, Pepper Flash, Fresh Player – just a lot of gibberish? We check out the background of Flash in Linux and provide tips on how to rule out the worst bugs in the technology.

  • Conky System Monitor

    This light-weight system monitor keeps you informed about your computer's performance.

comments powered by Disqus
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.

Learn More