Where does your window manager place new windows?

I'm not even sure this falls under the "an itch to scratch" category, it wasn't that much of an itch, but here we are.

Though I don't use the whole DE, I'm using lots of XFCE applications, such as their window manager, xfwm4 I really like it, but somewhat regularly I would get a little annoyed by where it would place new windows.

Typical case would be this: I have an application (e.g. file manager) maximized, then I have a gVim window on the left side (the window is about half my screen's size, so I can have two side by side). Then I would open a new terminal; my terminal window is 1/4th of the screen, so I could have 4 opened at the same time.

Naturally, I would expect my terminal window to go on the top-right corner, but it wouldn't go there. Instead, it was on the bottom-left one, i.e. on top of gVim. Now this might not seem to make sense, but it does (of course) if you know how xfwm4 actually works.

How xfwm4 works

It tries to find the best place, that is the one with less overlaps. It calculates such overlap by taking into account all visible windows, with importance that "visible" here doesn't mean that you can see it, but that it isn't hidden (e.g. minimized).

That is to say, a window that you cannot see because another window is on top of it will still count. In fact, in such a case and as far as xfwm4 goes, that would make 2 overlaps. Back to my case, knowing that I happen to have 2 terminals opened already, on the top-right and bottom-right corners (both below the maximized window), explains xfwm4's choice.

I know this, because Tyler knows this I looked into it, since for some reason I decided to spend time on this, and see if I couldn't improve things a bit (as far as my expectations for placement are, at least).

Since we're talking about how it works, for the curious let's go a bit more into details: what it actually does is basically place the window on the top-left corner, and calculate the overlaps. That is, how much of the window would overlap with other windows, again taking into consideration all windows on that area, even ones below other ones.

Once it's got the total overlapping area calculated, it moves the window by 8 pixels to the right, and calculates the overlaps. Repeat until you reached the right side, then back on the left, but 8 pixels lower, and start again. Until you've done the entire screen, and can figure out which position was the one with the least overlaps.

Note: of course it doesn't place/move the window, this is just to explain which calculations are done. Still, comments refer to this as "the good old CPU consuming algorithm" ;-)

Let's try to make xfwm4 smarter

So since I like to procrastinate or something, I decided to change how xfwm4 would place new windows, and wrote a patch that will hopefully make it place the window always where I'd expect it to.

So here's how things are now done :

  • First, it considers the entire screen, i.e. the place where it can potientally place the window (Note: this has already been limited to the current monitor, and excluding any panels/docks, prior to our function being called).

  • Then, it will look at windows on the stack in reverse order. What this means is: it will look at the last window to have been drawn/focused/activated, i.e. the one on top of all the other ones. It gets the area where that window is, and marks it as unusuable.

  • Moving on to the next window, i.e. the one right below it (Note that that means on the stack, the window doesn't have to actually be below the other one, it could simply be e.g. on the side); and do the same. Repeat this operation until there's no more screen space available, then go back one iteration.

  • It has now figured out the place where to put the window. Of course, it might not be a rectangle space, it could be a bit more complicated than that. For example, if that space comes from the maximized application you have below a few other windows, there might be a few rectangles where to put the new window.

    Example: you have a maximized window in the back, and then two windows on top of it. One in the top-middle of the screen, the other one on the bottom-middle. Depending on a few factors, we could see this as 5 rectangles, if we process things "horizontally" (on the left & right on the top window, then the middle part, then on the left & right of the bottom window), or only 3 if we do things vertically (in "columns" and assuming our two windows are the same size, and have the same X position). (In reality, it'll probably depend on the order each window was processed.)

    To handle this, each rectangle will be looked at, and every time xfwm4 will try to expand it the most (trying horizontal expansion then vertical expansion, then the other way around and keeping the largest one of the two). Once such a rectangle has been determined, obviously ones where the window can fit are favored.

    In case we only have multiple rectangles where the window can't fit, the largest one will be used. If we have more than one where it can fit, then the smallest one will be used (to try to not waste space as much as possible). And of course when the window didn't fit, it might move a little to make sure it is fully within the screen.

And... it works. :) At least for the few tries I've done with it, it works as expected. And that makes much more sense to me: I'd rather see less of a window I used some time ago than of the one I'm currently using, even if there are a few other windows below that other window, and none below the one I'm using now.

To come back to my original example: Now when I open a new terminal, it doesn't go over my gVim window but on the top-right corner, regardless of how many other window might be stacked on that very spot. Exactly what I'd expect, so I like it.

To illustrate how it works, let's keep opening windows: if I open a new terminal, it will naturally go in the bottom-left corner, the last I could see of the maximized file manager.

Now I have gVim on the left side, and two terminals on the right side. And if I open yet another terminal? It will go on top of gVim. It makes sense, since the last two windows I used where the terminals (In other words: gVim is now the oldest window I used (of the ones I can see)).

Now, what if before opening that new terminal, I had switched back to gVim? Well then the new terminal would have gone over the terminal on the top-right corner. Again, since gVim is the most recent used application, we shouln't put windows on top of it (unless we can't avoid it), and that terminal had become the oldest window used.

2013-04-05 edit: snap to borders

Little addendum: After using it a little more and trying out how it behaved in different situations, I realized that there was a case where things could possibly be improved a bit.

On occasions it might look like windows are snapped to the top and/or left borders, but this is just a side-effect of placing the window on the top-left corner of the selected rectangle.

It could also look like windows would be snapped on the bottom and/or right borders, but only when the top-left corner would have had the window not fully shown, and it was therefore moved just enough to be fully visible.

But why not actually try & snap to those borders? It usually feels like this might be the natural/expected behavior. So I decided to add just that, but made it dependant on an existing option : snap_to_border (You can find it under the window manager's settings, tab Advanced: "Snap windows to screen border")

While it wasn't exactly intended for this, I feel it makes sense that auto-placement of windows would follow this setting. (Also, I have one computer where I don't want this behavior, so I needed a way to disable it; This was the easiest.)

The code

This patch (alongside my old patch to have hover effects for inactive windows too) can be found on github (in separate branches). I've also submitted it upstream (even though there's already been a few issue asking for change in the placement over the years), feel free to comment there as well (or especially, if you do - or don't - want it merged).

Top of Page