hacking-howto: document X11 pushing/drawing
This commit is contained in:
parent
5efb81250a
commit
f91f6c52e9
|
@ -583,26 +583,104 @@ A window’s size and position will be determined in the following way:
|
||||||
|
|
||||||
== Pushing updates to X11 / Drawing
|
== Pushing updates to X11 / Drawing
|
||||||
|
|
||||||
TODO.
|
A big problem with i3 before version 4 was that we just sent requests to X11
|
||||||
|
anywhere in the source code. This was bad because nobody could understand the
|
||||||
|
entirety of our interaction with X11, it lead to subtle bugs and a lot of edge
|
||||||
|
cases which we had to consider all over again.
|
||||||
|
|
||||||
|
Therefore, since version 4, we have a single file, +src/x.c+, which is
|
||||||
|
responsible for repeatedly transferring parts of our tree datastructure to X11.
|
||||||
|
|
||||||
|
+src/x.c+ consists of multiple parts:
|
||||||
|
|
||||||
|
1. The state pushing: +x_push_changes()+, which calls +x_push_node()+.
|
||||||
|
2. State modification functions: +x_con_init+, +x_reinit+,
|
||||||
|
+x_reparent_child+, +x_move_win+, +x_con_kill+, +x_raise_con+, +x_set_name+
|
||||||
|
and +x_set_warp_to+.
|
||||||
|
3. Expose event handling (drawing decorations): +x_deco_recurse()+ and
|
||||||
|
+x_draw_decoration()+.
|
||||||
|
|
||||||
|
=== Pushing state to X11
|
||||||
|
|
||||||
|
In general, the function +x_push_changes+ should be called to push state
|
||||||
|
changes. Only when the scope of the state change is clearly defined (for
|
||||||
|
example only the title of a window) and its impact is known beforehand, one can
|
||||||
|
optimize this and call +x_push_node+ on the appropriate con directly.
|
||||||
|
|
||||||
|
+x_push_changes+ works in the following steps:
|
||||||
|
|
||||||
|
1. Clear the eventmask for all mapped windows. This leads to not getting
|
||||||
|
useless ConfigureNotify or EnterNotify events which are caused by our
|
||||||
|
requests. In general, we only want to handle user input.
|
||||||
|
2. Stack windows above each other, in reverse stack order (starting with the
|
||||||
|
most obscured/bottom window). This is relevant for floating windows which
|
||||||
|
can overlap each other, but also for tiling windows in stacked or tabbed
|
||||||
|
containers. We also update the +_NET_CLIENT_LIST_STACKING+ hint which is
|
||||||
|
necessary for tab drag and drop in Chromium.
|
||||||
|
3. +x_push_node+ will be called for the root container, recursively calling
|
||||||
|
itself for the container’s children. This function actually pushes the
|
||||||
|
state, see the next paragraph.
|
||||||
|
4. If the pointer needs to be warped to a different position (for example when
|
||||||
|
changing focus to a differnt output), it will be warped now.
|
||||||
|
5. The eventmask is restored for all mapped windows.
|
||||||
|
6. Window decorations will be rendered by calling +x_deco_recurse+ on the root
|
||||||
|
container, which then recursively calls itself for the children.
|
||||||
|
7. If the input focus needs to be changed (because the user focused a different
|
||||||
|
window), it will be updated now.
|
||||||
|
8. +x_push_node_unmaps+ will be called for the root container. This function
|
||||||
|
only pushes UnmapWindow requests. Separating the state pushing is necessary
|
||||||
|
to handle fullscreen windows (and workspace switches) in a smooth fashion:
|
||||||
|
The newly visible windows should be visible before the old windows are
|
||||||
|
unmapped.
|
||||||
|
|
||||||
|
+x_push_node+ works in the following steps:
|
||||||
|
|
||||||
|
1. Update the window’s +WM_NAME+, if changed (the +WM_NAME+ is set on i3
|
||||||
|
containers mainly for debugging purposes).
|
||||||
|
2. Reparents a child window into the i3 container if the container was created
|
||||||
|
for a specific managed window.
|
||||||
|
3. If the size/position of the i3 container changed (due to opening a new
|
||||||
|
window or switching layouts for example), the window will be reconfigured.
|
||||||
|
Also, the pixmap which is used to draw the window decoration/border on is
|
||||||
|
reconfigured (pixmaps are size-dependent).
|
||||||
|
4. Size/position for the child window is adjusted.
|
||||||
|
5. The i3 container is mapped if it should be visible and was not yet mapped.
|
||||||
|
When mapping, +WM_STATE+ is set to +WM_STATE_NORMAL+. Also, the eventmask of
|
||||||
|
the child window is updated and the i3 container’s contents are copied from
|
||||||
|
the pixmap.
|
||||||
|
6. +x_push_node+ is called recursively for all children of the current
|
||||||
|
container.
|
||||||
|
|
||||||
|
+x_push_node_unmaps+ handles the remaining case of an i3 container being
|
||||||
|
unmapped if it should not be visible anymore. +WM_STATE+ will be set to
|
||||||
|
+WM_STATE_WITHDRAWN+.
|
||||||
|
|
||||||
|
|
||||||
|
=== Drawing window decorations/borders/backgrounds
|
||||||
|
|
||||||
|
+x_draw_decoration+ draws window decorations. It is run for every leaf
|
||||||
|
container (representing an actual X11 window) and for every non-leaf container
|
||||||
|
which is in a stacked/tabbed container (because stacked/tabbed containers
|
||||||
|
display a window decoration for split containers, which at the moment just says
|
||||||
|
"another container").
|
||||||
|
|
||||||
|
Then, parameters are collected to be able to determine whether this decoration
|
||||||
|
drawing is actually necessary or was already done. This saves a substantial
|
||||||
|
number of redraws (depending on your workload, but far over 50%).
|
||||||
|
|
||||||
|
Assuming that we need to draw this decoration, we start by filling the empty
|
||||||
|
space around the child window (think of MPlayer with a specific aspect ratio)
|
||||||
|
in the user-configured client background color.
|
||||||
|
|
||||||
|
Afterwards, we draw the appropriate border (in case of border styles "normal"
|
||||||
|
and "1pixel") and the top bar (in case of border style "normal").
|
||||||
|
|
||||||
|
The last step is drawing the window title on the top bar.
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
== Resizing containers
|
||||||
=== Common parts
|
|
||||||
|
|
||||||
On the frame (the window which was created around the client’s window for the
|
|
||||||
decorations), a black rectangle is drawn as a background for windows like
|
|
||||||
MPlayer, which do not completely fit into the frame.
|
|
||||||
|
|
||||||
=== Window decorations
|
|
||||||
|
|
||||||
The window decorations consist of a rectangle in the appropriate color (depends
|
|
||||||
on whether this window is the currently focused one, the last focused one in a
|
|
||||||
not focused container or not focused at all) forming the background.
|
|
||||||
Afterwards, two lighter lines are drawn and the last step is drawing the
|
|
||||||
window’s title (see WM_NAME) onto it.
|
|
||||||
|
|
||||||
=== Resizing containers
|
|
||||||
|
|
||||||
By clicking and dragging the border of a container, you can resize the whole
|
By clicking and dragging the border of a container, you can resize the whole
|
||||||
column (respectively row) which this container is in. This is necessary to keep
|
column (respectively row) which this container is in. This is necessary to keep
|
||||||
|
|
Loading…
Reference in New Issue