hacking-howto: document v4 rendering

next
Michael Stapelberg 2011-11-22 23:54:54 +00:00
parent 2359c5049d
commit 5efb81250a
1 changed files with 111 additions and 40 deletions

View File

@ -469,54 +469,131 @@ src/layout.c, function resize_client().
== Rendering (src/layout.c, render_layout() and render_container())
*********************************************************************************
This section has not been updated for v4.0 yet, sorry! We wanted to release on
time, but we will update this soon. Please talk to us on IRC if you need to
know stuff *NOW* :).
*********************************************************************************
Rendering in i3 version 4 is the step which assigns the correct sizes for
borders, decoration windows, child windows and the stacking order of all
windows. In a separate step (+x_push_changes()+), these changes are pushed to
X11.
Keep in mind that all these properties (+rect+, +window_rect+ and +deco_rect+)
are temporary, meaning they will be overwritten by calling +render_con+.
Persistent position/size information is kept in +geometry+.
The entry point for every rendering operation (except for the case of moving
floating windows around) currently is +tree_render()+ which will re-render
everything thats necessary (for every output, only the currently displayed
workspace is rendered). This behavior is expected to change in the future,
since for a lot of updates, re-rendering everything is not actually necessary.
Focus was on getting it working correct, not getting it work very fast.
What +tree_render()+ actually does is calling +render_con()+ on the root
container and then pushing the changes to X11. The following sections talk
about the different rendering steps, in the order of "top of the tree" (root
container) to the bottom.
=== Rendering the root container
The i3 root container (+con->type == CT_ROOT+) represents the X11 root window.
It contains one child container for every output (like LVDS1, VGA1, …), which
is available on your computer.
Rendering the root will first render all tiling windows and then all floating
windows. This is necessary because a floating window can be positioned in such
a way that it is visible on two different outputs. Therefore, by first
rendering all the tiling windows (of all outputs), we make sure that floating
windows can never be obscured by tiling windows.
Essentially, though, this code path will just call +render_con()+ for every
output and +x_raise_con(); render_con()+ for every floating window.
In the special case of having a "global fullscreen" window (fullscreen mode
spanning all outputs), a shortcut is taken and +x_raise_con(); render_con()+ is
only called for the global fullscreen window.
=== Rendering an output
Output containers (+con->layout == L_OUTPUT+) represent a hardware output like
LVDS1, VGA1, etc. An output container has three children (at the moment): One
content container (having workspaces as children) and the top/bottom dock area
containers.
The rendering happens in the function +render_l_output()+ in the following
steps:
1. Find the content container (+con->type == CT_CON+)
2. Get the currently visible workspace (+con_get_fullscreen_con(content,
CF_OUTPUT)+).
3. If there is a fullscreened window on that workspace, directly render it and
return, thus ignoring the dock areas.
4. Sum up the space used by all the dock windows (they have a variable height
only).
5. Set the workspace rects (x/y/width/height) based on the position of the
output (stored in +con->rect+) and the usable space
(+con->rect.{width,height}+ without the space used for dock windows).
6. Recursively raise and render the outputs child containers (meaning dock
area containers and the content container).
=== Rendering a workspace or split container
From here on, there really is no difference anymore. All containers are of
+con->type == CT_CON+ (whether workspace or split container) and some of them
have a +con->window+, meaning they represent an actual window instead of a
split container.
==== Default layout
In default layout, containers are placed horizontally or vertically next to
each other (depending on the +con->orientation+). If a child is a leaf node (as
opposed to a split container) and has border style "normal", appropriate space
will be reserved for its window decoration.
==== Stacked layout
In stacked layout, only the focused window is actually shown (this is achieved
by calling +x_raise_con()+ in reverse focus order at the end of +render_con()+).
The available space for the focused window is the size of the container minus
the height of the window decoration for all windows inside this stacked
container.
If border style is "1pixel" or "none", no window decoration height will be
reserved (or displayed later on), unless there is more than one window inside
the stacked container.
==== Tabbed layout
Tabbed layout works precisely like stacked layout, but the window decoration
position/size is different: They are placed next to each other on a single line
(fixed height).
==== Dock area layout
This is a special case. Users cannot chose the dock area layout, but it will be
set for the dock area containers. In the dockarea layout (at the moment!),
windows will be placed above each other.
=== Rendering a window
A windows size and position will be determined in the following way:
1. Subtract the border if border style is not "none" (but "normal" or "1pixel").
2. Subtract the X11 border, if the window has an X11 border > 0.
3. Obey the aspect ratio of the window (think MPlayer).
4. Obey the height- and width-increments of the window (think terminal emulator
which can only be resized in one-line or one-character steps).
== Pushing updates to X11 / Drawing
TODO.
/////////////////////////////////////////////////////////////////////////////////
There are several entry points to rendering: `render_layout()`,
`render_workspace()` and `render_container()`. The former one calls
`render_workspace()` for every screen, which in turn will call
`render_container()` for every container inside its layout table. Therefore, if
you need to render only a single container, for example because a window was
removed, added or changed its title, you should directly call
render_container().
Rendering consists of two steps: In the first one, in `render_workspace()`, each
container gets its position (screen offset + offset in the table) and size
(container's width times colspan/rowspan). Then, `render_container()` is called,
which takes different approaches, depending on the mode the container is in:
=== Common parts
On the frame (the window which was created around the clients window for the
decorations), a black rectangle is drawn as a background for windows like
MPlayer, which do not completely fit into the frame.
=== Default mode
Each clients gets the containers width and an equal amount of height.
=== Stack mode
In stack mode, a window containing the decorations of all windows inside the
container is placed at the top. The currently focused window is then given the
whole remaining space.
=== Tabbed mode
Tabbed mode is like stack mode, except that the window decorations are drawn
in one single line at the top of the container.
=== Window decorations
The window decorations consist of a rectangle in the appropriate color (depends
@ -525,12 +602,6 @@ not focused container or not focused at all) forming the background.
Afterwards, two lighter lines are drawn and the last step is drawing the
windows title (see WM_NAME) onto it.
=== Fullscreen windows
For fullscreen windows, the `rect` (x, y, width, height) is not changed to
allow the client to easily go back to its previous position. Instead,
fullscreen windows are skipped when rendering.
=== Resizing containers
By clicking and dragging the border of a container, you can resize the whole