Window stacking / raising design

Bill Spitzak spitzak at gmail.com
Mon Jan 16 19:14:20 PST 2012


Pekka Paalanen suggested I come up with a design for the Wayland 
compositor to control window stacking and raising.

I am pretty familiar with the failures of existing window management in 
this area and would certainly like to see Wayland do this correctly, and 
not copy the mistakes of the past.

I also more fully understand the design goals of Kristian, and so I hope 
I have a better intermediate solution, as opposed to my original goal of 
putting the client in absolute control. This seems to be a good 
compromise that will actually deliver correctly working user interfaces 
with overlapping windows, while allowing the compositor final say on things.

The basic idea is that clients must request raises of their windows and 
that windows are not reordered except when this happens. However the 
raise request contains multiple windows. The compositor can still 
overrule this and has a clearer idea what the client is requesting.

COMPOSITOR RAISING WINDOWS WILL NOT WORK

It appears the Wayland compositor is raising windows immediately on 
clicks. There are many reasons this is unworkable, at least if Wayland 
is to deliver the "glitch free" api that supposedly is wanted:

1. Modern drag & drop api requires that the window is not raised when 
the user starts a drag. A timeout or other kludge in the compositor to 
detect if a drag starts is pretty ugly, and would delay the raise 
response to clicks by this timeout period.

2. Dialog boxes / modal windows / control panels want to remain above 
raised windows. The usual attempt to solve this is for the client to 
communicate the desired stacking, but existing solutions only allow a 
limited and static description. The failure of Gimp to work with 
overlapping control panels is entirely due to the inability to 
communicate it's desired stacking to the window manager. What is 
actually needed is an arbitrary directed acyclic graph of every window 
owned by the client, and this graph must be *synchronously* updated in 
response to events, including the very click that raises a window. This 
is unworkably complex, and the synchronization would produce annoying 
slowdown in responses to clicks.

3. The user does not want the windows to raise on some clicks. Currently 
overlapping windows are quite useless because the user cannot do the 
most trivial operations, such as push a button, without the window 
raising. For api's based on X, the select + middle click is really 
identical to drag & drop, and therefore selection should also not raise 
the window. I think the proper behavior of clients is that they should 
*not* raise on click unless the click is in the window border, in a 
"dead" area where the click serves no purpose, or it is the start of a 
"paint" operation. My design does not enforce this, but it allows it.

I hope it is clear why I am convinced that any plan that involves raises 
happening without the approval of the client is unacceptable.

THE FULLSCREEN + PANEL PROBLEM

There is a desire for "fullscreen" windows to obscure "panels". The 
current proposal is for setting a window to fullscreen to raise it, 
which has the exact same problems as any automatic click to raise.

My proposal is that instead the compositor will *lower* the panels to be 
below the topmost fullscreen window. Thus the fullscreen window, and all 
windows that are above it, will be above the panel.

In normal use a client will also raise the window and dialog boxes. So 
the user will just see the panel and other windows vanish below the 
fullscreen window and it's dialog boxes, but will not see any dialog 
boxes "blink".

More formally: all windows have a "role", such as "desktop", "window", 
"panel" and "cursor". The compositor is not allowed to change the order 
of windows with the same role, except in response to a raise request. 
However it is allowed to enforce any rule for "shuffling" these roles 
together into the actual window list.

MAPPED / UNMAPPED

I am unclear if Wayland will provide any atomic grouping of client 
requests so that the user never sees any intermediate state of these 
requests.

If not, it looks like the ability to make an "unmapped" window is 
needed. This is because the code to add a surface to wayland is complex 
and it would otherwise have to be embedded into the "raise" request, so 
that new dialogs can be added as part of the raise and not temporarily 
appear in the wrong order.

Setting up a surface "unmapped" would have no visual effect until that 
window id is used in a raise request.

RAISE NOTIFY EVENT

The compositor can send this to clients to indicate it wants to raise a 
particular window for some reason other than a mouse click.

Notice that mouse clicks are just sent normally to the window. The 
client decides whether or not it is a raise.

RAISE REQUEST

This message from client to compositor indicates that the client wants 
windows reordered. It contains the following information:

   WINDOW ID: this is the window that is being raised, or null if this 
is only a request to obey the DAG.

   EVENT ID: the event that this is in response to. It should be a mouse 
click or a raise notify. The compositor might ignore the WINDOW ID if it 
is not these events or if it predates later responses, however it *must* 
still obey the WINDOW LIST.

   WINDOW LIST: A list of window id's, all must belong to the client and 
be the same "role". This indicates a stacking order from bottom to top. 
The compositor *must* end up with the windows in the order specified, 
though other windows may be shuffled between or above these.

   This list may actually define a Directed Acyclic Graph (DAG) by the 
following scheme: if a window id repeats, it indicates a new "branch" 
off that window. No ordering is enforced between two branches, then can 
be above/below or shuffled together.

   For instance if there is a main window W and three dialogs A,B,C, and 
the client wants the dialogs to remain above W but does not care what 
order they are in, the list would read:

	W, A, W, B, W, C

   While this indiates that C must be above B:

	W, A, W, B, C

   FLAGS: binary flags of the same size as the WINDOWS list. Modifies 
interpretation of this list (more may be added):

	STICK - Indicates that no window can be placed between this window and 
the one before it. The purpose is to stick a video playback window 
behind a "frame" window and not let other windows mistakenly appear 
between them, so the user is unaware there are multiple windows.

	UNMAP - Window should vanish from the screen, and the next window in 
the list is placed above the previous non-unmapped window

   Note that it may be possible to do "STICK" in another call, such as 
when one of the surfaces is assigned. If atomic request grouping is 
done, it also removes the need for UNMAP. Therefore it may be possible 
to eliminate the flags.



More information about the wayland-devel mailing list