Wayland Window Management Proposal
Bill Spitzak
spitzak at gmail.com
Tue May 10 17:35:16 PDT 2011
With all the discussion about client side decorations, I thought I would
try to write how window management could actually be done in Wayland.
This is a really serious attempt to get the simplest system I could come
up with, while still allowing for some of the legitimate gripes, in
particular to make it not be impossible to do tiled window management.
This I hope is in enough detail that it that it is not ambiguous whether
this design does something or fails to do it. Too much of the client
side decoration argument is making false assumptions about what the
system will do.
= Wayland Window Management proposal =
== Object Parent ==
All Wayland objects have a single "parent", which is another object or
NULL. When an object is first created it's parent is NULL, but it can
be set to any other object afterwards. If the attempt to set the
parent produces a loop that is an error and the parent is
unchanged. If a parent is deleted the child's parent is set to
NULL. All parent changes produce events.
The purpose is to build hierarchies that task managers need in order
to display everything in a useful way to users. This has no effect on
the display or how windows act.
== Object Name ==
All objects have a single UTF-8 string attached to them that is the
"name". The purpose of the name is to provide something to show the
user when a program can't or does not want to display an image.
== Task objects ==
Task objects are windows but their purpose is to appear in a "task
list". They probably don't have an actual image allocated.
There is a global task created by the compositor, tasks that should be
visible are attached to this as children. Below that can be a
hierarchy of more tasks and then actual windows (i'm not sure if there
will need to be a way to distinguish tasks from windows).
The image that appears in the task list may be the surface attached to
the task object, or maybe some children with specific names. Not sure
exactly how to do this but it would be nice if clients could control
this to draw indicators, etc. Compositors can fall back to showing the
name if no other image is found.
== Multiple-surface windows ==
What appears to be a single window to the user may be several Wayland
windows. In particlar a video-playback program may have a YUV surface
resized on screen to zoom the pixels, overlaid with a "frame" window
which is an unscaled RGBA image of all the controls around and
overlaid on the video. It is important that window management support
this and them move and resize in exact lock.
To indicate this the YUV surface should be a child of the frame
and below the frame.
== Client side decorations ==
The client is responsible for drawing every single pixel in a window
that the user would click on and expect to go to the client. This
includes the window title and the borders on all sides of the window.
Non-rectangular windows are done by leaving the portion between the
window and the rectangle transparent black (all zero).
"shadows" are done by the compositor as the pixels they occupy belong
to the windows the shadows fall on. It can produce shadows for
non-rectangular windows by using the alpha to create the shadow.
"blurry opacity" is done by the compositor. It must not blur video
playback children and not blur 100% transparent areas or the
antialiased edges of these areas. I don't know how clients can control
the blur, but perhaps color values greater than alpha can indicate
blurring.
== Compositor Window Management ==
The compositor can produce events that clients are expected to respond
to and update their windows appropriately. The compositor *NEVER*
moves or does anything to the windows, as this would produce
asynchronous updates. The clients must do this so they can immediatly
draw the new contents.
These events are produced by task manager windows, or by Alt+mouse
style overrides, NOT by the user clicking on the window borders or
contents. Clicks actually in the windows are expected to be handled by
the clients or by the filtering described below.
=== Close ===
Sent to a task or window indicating that the user wants it to go
away. A typical response is to ask the user if they are sure, to
destroy or unmap the window, to destroy or unmap other child windows,
and for the client to exit.
=== Hide ===
Sent to a task or window indicating that the user wants it off the
screen but wants to bring it back later. Typical response is to unmap
windows.
=== Show ===
Sent to a task or window indicating that the user wants it on the
screen. Typical response is to map windows.
=== Activate ===
Sent to a task or window, includes a non-pointer input device (usually
the keyboard). Indicates that the device's events will be sent to that
task or window. Typical response is to change the graphics to show
this and to make toolboxes appear. Note that the events may be sent to
the task, not a visible window, the client is responsible for figuring
out where they should go.
=== Deactivate ===
Sent to a task or window that got Activate before when another object
is sent Activate. Might not be sent until the other object confirms it
took the event. Typical response is to change the graphics to show this
and make toolboxes disappear.
=== Raise/Lower ===
Sent to a task or window. An id of a visible object is passed that
this object should be placed under, or None if it should be placed on
top. May include a hint as to whether this is a raise or
lower. Typical response is to reorder the window to that position,
reorder other surfaces to be adjacent, and to raise, if necessary,
toolboxes so they are atop the window.
To avoid blinking the client should raise the top-most window first
and place each lower window below it. Lowering must be done in the
opposite order. It may be useful for Wayland to provide a "put A below
B if not above B" api to avoid a lot of round-trip queries to
determine if it needs to move a window.
=== Move/Resize ===
Sent only to windows. Includes the rectangle the entire window contents
is expected to fit into, and also four "edge" flags, and a "title" flag.
Expected result is that the client resizes the window to the desired
size, though it can choose a smaller size that fits in the area as
long as opposite "edge" flags are not on, and it moves and resizes
other windows, such as the multiple surface windows I described
above.
The "edge" flags indicate if the border should not be drawn on that
side. It indicates alignment with some graphic the compositor draws
(as in a tiled window manager) or with a screen edge. The client can
then skip drawing this border, making the contents go all the way to
the edge of the window. It can also shift the opposite edge of the
window over (provided it does have the edge flag set) so that the
contents do not change size.
The "title" flag indicates that the client should not draw a title
bar. Note that in typical window designs the top of the window has a
flat area that is this title bar, outside of which is a few pixels of
shaded top border that the edge controls.
== Client Window Management ==
Clients can directly do anything they want to their
windows. Compositors should be prepared for this.
To allow cooperation a client can also send a few messages to the
compositor so that the compositor does not have to guess what happened.
=== Close ===
Clients can send this with a task or window to indicate the close
action was performed. This includes an internal pop up of an "are your
sure" that the user dismissed, ie the program did not really
close. May be useful if the compositor keeps track of close attempts.
=== Hide/Show ===
Clients can send this with a task or window to indicate they performed
the results of that message. Allows direct control over the state of
tasks, rather than the compositor guessing it from the visibility of
windows.
=== Activate ===
Indicate that the client is in control of a given input device. The
compositor will send the Deactivate to whatever had it before.
A client supports click-to-type by sending an activate when the mouse
is clicked in their window.
To support point-to-type it sends an activate when the mouse enters
the window. It can also warp the mouse to point at the correct window
when it receives an activate event, and warp the mouse out when it
receives a deactivate, so the mouse always matches the activation.
Note that both policies can co-exist and applications can choose.
This does not guarantee that the compositor will send events to this
client.
=== Deactivate ===
Done with an input device. The compositor should find some other
object to activate if it can.
=== Resize ===
Clients can send the same resize event they receive. The purpose is to
tell the compositor the settings of the edge and title flags. This is
needed so that fullscreen can be distinguished from maximize.
=== Move/Resize Interaction ===
A client can tell the compositor to take control of the mouse or other
input device and to start a move/resize action. This should be very
similar to how drag & drop is initiated.
The purpose is so that snapping and preview and tiling effects can be
done by the compositor. The client will start this up in response to
clicks on the borders and titles and resize handles, and perhaps on
inactive areas of the contents. It then will handle incoming
Move/Resize/Raise events from the compositor.
There are 4 flags indicating what edges are being moved. None
indicates a move. One edge indicates a one-direction resize. Two
adjacent edges represent a corner. Other combinations should produce
some reasonable result but the exact meaning is left up to the
compositor. There is a fifth title flag to indicate whether the click
was on a "titlebar" or on the contents of the window.
== Event Filtering ==
When the compositor sends events to the client, it can look for a
response back. This response indicates whether the client "ignored"
the event. If so the compositor can use it for another purpose.
The main reason for this is so that global shortcuts can require less
complex shift combinations, by giving clients the opportunity to use
the key if it wants (Compositors are also free to not send the event
in the first place if they don't want clients to override it).
Ignored mouse clicks should be treated as the above mouse grab where
the click is in the contents.
Ignored raise/lower/map/etc can be faked. All child windows
should have the same action done to them as the main window so they
all move as a unit.
Ignored resize probably should not change the size, just move the
window. Move lower children the same way.
Ignored close should kill the program (note that the client asking the
user if they want to quit means the client did use the close event).
Ignored activate means maybe it should try another window. (?)
Ignored deactive may want to unmap higher child windows as these are
probably modal dialogs.
== Fallback Window Management ==
After a timeout if the client does not send the response back, the
compositor can assume the client is locked up. The compositor can then
indicate this state (by changing the cursor to a wait indicator, or
graying the window, etc). It can then handle the event as though the
client ignored it (except any events this produced should immediatly
be acted on as though ignored, rather than sent).
If the user clicks enough times without the program responding, or if
a close event is ignored, it should pop up a dialog offering to kill
the process.
== END ==
More information about the wayland-devel
mailing list