]> git.sur5r.net Git - i3/i3/blobdiff - docs/hacking-howto
Merge branch 'master' into next
[i3/i3] / docs / hacking-howto
index 3a448537ab7ce023b2794387854bc505a9585175..836d5701acff304f68aa7b3e3c7ca346f9425df0 100644 (file)
 Hacking i3: How To
 ==================
 Michael Stapelberg <michael+i3@stapelberg.de>
-May 2009
+July 2011
 
-This document is intended to be the first thing you read before looking and/or touching
-i3’s source code. It should contain all important information to help you understand
-why things are like they are. If it does not mention something you find necessary, please
-do not hesitate to contact me.
+This document is intended to be the first thing you read before looking and/or
+touching i3’s source code. It should contain all important information to help
+you understand why things are like they are. If it does not mention something
+you find necessary, please do not hesitate to contact me.
 
 == Window Managers
 
-A window manager is not necessarily needed to run X, but it is usually used in combination
-to facilitate some things. The window manager's job is to take care of the placement of
-windows, to provide the user some mechanisms to change the position/size of windows and
-to communicate with clients to a certain extent (for example handle fullscreen requests
-of clients such as MPlayer).
+A window manager is not necessarily needed to run X, but it is usually used in
+combination with X to facilitate some things. The window manager's job is to
+take care of the placement of windows, to provide the user with some mechanisms
+to change the position/size of windows and to communicate with clients to a
+certain extent (for example handle fullscreen requests of clients such as
+MPlayer).
 
-There are no different contexts in which X11 clients run, so a window manager is just another
-client, like all other X11 applications. However, it handles some events which normal clients
-usually don’t handle.
+There are no different contexts in which X11 clients run, so a window manager
+is just another client, like all other X11 applications. However, it handles
+some events which normal clients usually don’t handle.
 
 In the case of i3, the tasks (and order of them) are the following:
 
 . Grab the key bindings (events will be sent upon keypress/keyrelease)
-. Iterate through all existing windows (if the window manager is not started as the first
-  client of X) and manage them (= reparent them, create window decorations)
+. Iterate through all existing windows (if the window manager is not started as
+  the first client of X) and manage them (reparent them, create window
+  decorations, etc.)
 . When new windows are created, manage them
 . Handle the client’s `_WM_STATE` property, but only the `_WM_STATE_FULLSCREEN`
 . Handle the client’s `WM_NAME` property
 . Handle the client’s size hints to display them proportionally
+. Handle the client’s urgency hint
 . Handle enter notifications (focus follows mouse)
 . Handle button (as in mouse buttons) presses for focus/raise on click
 . Handle expose events to re-draw own windows such as decorations
 . React to the user’s commands: Change focus, Move windows, Switch workspaces,
-Change the layout mode of a container (default/stacking), Start a new application,
-Restart the window manager
+  Change the layout mode of a container (default/stacking/tabbed), start a new
+  application, restart the window manager
 
-In the following chapters, each of these tasks and their implementation details will be discussed.
+In the following chapters, each of these tasks and their implementation details
+will be discussed.
 
 === Tiling window managers
 
-Traditionally, there are two approaches to managing windows: The most common one nowadays is
-floating, which means the user can freely move/resize the windows. The other approach is called
-tiling, which means that your window manager distributing windows to use as much space as
-possible while not overlapping.
+Traditionally, there are two approaches to managing windows: The most common
+one nowadays is floating, which means the user can freely move/resize the
+windows. The other approach is called tiling, which means that your window
+manager distributes windows to use as much space as possible while not
+overlapping each other.
+
+The idea behind tiling is that you should not need to waste your time
+moving/resizing windows while you usually want to get some work done. After
+all, most users sooner or later tend to lay out their windows in a way which
+corresponds to tiling or stacking mode in i3. Therefore, why not let i3 do this
+for you? Certainly, it’s faster than you could ever do it.
+
+The problem with most tiling window managers is that they are too unflexible.
+In my opinion, a window manager is just another tool, and similar to vim which
+can edit all kinds of text files (like source code, HTML, …) and is not limited
+to a specific file type, a window manager should not limit itself to a certain
+layout (like dwm, awesome, …) but provide mechanisms for you to easily create
+the layout you need at the moment.
+
+=== The layout tree
+
+The data structure which i3 uses to keep track of your windows is a tree. Every
+node in the tree is a container (type +Con+). Some containers represent actual
+windows (every container with a +window != NULL+), some represent split
+containers and a few have special purposes: they represent workspaces, outputs
+(like VGA1, LVDS1, …) or the X11 root window.
+
+So, when you open a terminal and immediately open another one, they reside in
+the same split container, which uses the default layout. In case of an empty
+workspace, the split container we are talking about is the workspace.
+
+To get an impression of how different layouts are represented, just play around
+and look at the data structures -- they are exposed as a JSON hash. See
+http://i3wm.org/docs/ipc.html#_get_tree_reply for documentation on that and an
+example.
 
-The idea behind tiling is that you should not need to waste your time moving/resizing windows
-while you usually want to get some work done. After all, most users sooner or later tend to
-lay out their windows in a way which corresponds to tiling or stacking mode in i3. Therefore,
-why not let i3 do this for you? Certainly, it’s faster than you could ever do it.
-
-The problem with most tiling window managers is that they are too unflexible. In my opinion, a
-window manager is just another tool, and similar to vim which can edit all kinds of text files
-(like source code, HTML, …) and is not limited to a specific file type, a window manager should
-not limit itself to a certain layout (like dwm, awesome, …) but provide mechanisms for you to
-easily create the layout you need at the moment.
-
-=== The layout table
-
-To accomplish flexible layouts, we decided to simply use a table. The table grows and shrinks
-as you need it. Each cell holds a container which then holds windows (see picture below). You
-can use different layouts for each container (default layout and stacking layout).
-
-So, when you open a terminal and immediately open another one, they reside in the same container,
-in default layout. The layout table has exactly one column, one row and therefore one cell.
-When you move one of the terminals to the right, the table needs to grow. It will be expanded
-to two columns and one row. This enables you to have different layouts for each container.
-The table then looks like this:
-
-[width="15%",cols="^,^"]
-|========
-| T1 | T2
-|========
-
-When moving terminal 2 to the bottom, the table will be expanded again.
+== Files
 
-[width="15%",cols="^,^"]
-|========
-| T1 |
-|    | T2
-|========
+include/atoms.xmacro::
+A file containing all X11 atoms which i3 uses. This file will be included
+various times (for defining, requesting and receiving the atoms), each time
+with a different definition of xmacro().
 
-You can really think of the layout table like a traditional HTML table, if you’ve ever
-designed one. Especially col- and rowspan work equally. Below you see an example of
-colspan=2 for the first container (which has T1 as window).
+include/data.h::
+Contains data definitions used by nearly all files. You really need to read
+this first.
 
-[width="15%",cols="^asciidoc"]
-|========
-| T1
-|
-[cols="^,^",frame="none"]
-!========
-! T2 ! T3
-!========
-|========
+include/*.h::
+Contains forward definitions for all public functions, as well as
+doxygen-compatible comments (so if you want to get a bit more of the big
+picture, either browse all header files or use doxygen if you prefer that).
 
-Furthermore, you can freely resize table cells.
+src/cfgparse.l::
+Contains the lexer for i3’s configuration file, written for +flex(1)+.
 
-== Files
+src/cfgparse.y::
+Contains the parser for i3’s configuration file, written for +bison(1)+.
 
-include/data.h::
-Contains data definitions used by nearly all files. You really need to read this first.
+src/click.c::
+Contains all functions which handle mouse button clicks (right mouse button
+clicks initiate resizing and thus are relatively complex).
 
-include/*.h::
-Contains forward definitions for all public functions, aswell as doxygen-compatible
-comments (so if you want to get a bit more of the big picture, either browse all
-header files or use doxygen if you prefer that).
+src/cmdparse.l::
+Contains the lexer for i3 commands, written for +flex(1)+.
 
-src/client.c::
-Contains all functions which are specific to a certain client (make it
-fullscreen, see if its class/name matches a pattern, kill it, …).
+src/cmdparse.y::
+Contains the parser for i3 commands, written for +bison(1)+.
 
-src/commands.c::
-Parsing commands and actually execute them (focussing, moving, …).
+src/con.c::
+Contains all functions which deal with containers directly (creating
+containers, searching containers, getting specific properties from containers,
+…).
 
 src/config.c::
-Parses the configuration file.
+Contains all functions handling the configuration file (calling the parser
+(src/cfgparse.y) with the correct path, switching key bindings mode).
 
 src/debug.c::
 Contains debugging functions to print unhandled X events.
 
+src/ewmh.c::
+Functions to get/set certain EWMH properties easily.
+
 src/floating.c::
 Contains functions for floating mode (mostly resizing/dragging).
 
 src/handlers.c::
-Contains all handlers for all kind of X events (new window title, new hints,
+Contains all handlers for all kinds of X events (new window title, new hints,
 unmapping, key presses, button presses, …).
 
 src/ipc.c::
 Contains code for the IPC interface.
 
-src/layout.c::
-Renders your layout (screens, workspaces, containers).
+src/load_layout.c::
+Contains code for loading layouts from JSON files.
+
+src/log.c::
+Handles the setting of loglevels, contains the logging functions.
 
-src/mainx.c::
+src/main.c::
 Initializes the window manager.
 
 src/manage.c::
 Looks at existing or new windows and decides whether to manage them. If so, it
 reparents the window and inserts it into our data structures.
 
-src/resize.c::
-Contains the functions to resize columns/rows in the table.
+src/match.c::
+A "match" is a data structure which acts like a mask or expression to match
+certain windows or not. For example, when using commands, you can specify a
+command like this: [title="*Firefox*"] kill. The title member of the match
+data structure will then be filled and i3 will check each window using
+match_matches_window() to find the windows affected by this command.
+
+src/move.c::
+Contains code to move a container in a specific direction.
+
+src/output.c::
+Functions to handle CT_OUTPUT cons.
+
+src/randr.c::
+The RandR API is used to get (and re-query) the configured outputs (monitors,
+…).
+
+src/render.c::
+Renders the tree data structure by assigning coordinates to every node. These
+values will later be pushed to X11 in +src/x.c+.
 
 src/resize.c::
-Contains the functions to resize columns/rows in the table.
+Contains the functions to resize containers.
+
+src/sighandler.c::
+Handles +SIGSEGV+, +SIGABRT+ and +SIGFPE+ by showing a dialog that i3 crashed.
+You can chose to let it dump core, to restart it in-place or to restart it
+in-place but forget about the layout.
 
-src/table.c::
-Manages the most important internal data structure, the design table.
+src/tree.c::
+Contains functions which open or close containers in the tree, change focus or
+cleanup ("flatten") the tree. See also +src/move.c+ for another similar
+function, which was moved into its own file because it is so long.
 
 src/util.c::
 Contains useful functions which are not really dependant on anything.
 
+src/window.c::
+Handlers to update X11 window properties like +WM_CLASS+, +_NET_WM_NAME+,
++CLIENT_LEADER+, etc.
+
 src/workspace.c::
 Contains all functions related to workspaces (displaying, hiding, renaming…)
 
+src/x.c::
+Transfers our in-memory tree (see +src/render.c+) to X11.
+
 src/xcb.c::
 Contains wrappers to use xcb more easily.
 
+src/xcursor.c::
+XCursor functions (for cursor themes).
+
 src/xinerama.c::
-(Re-)initializes the available screens and converts them to virtual screens (see below).
+Legacy support for Xinerama. See +src/randr.c+ for the preferred API.
 
 == Data structures
 
-See include/data.h for documented data structures. The most important ones are explained
-right here.
+
+See include/data.h for documented data structures. The most important ones are
+explained right here.
+
+/////////////////////////////////////////////////////////////////////////////////
+// TODO: update image
 
 image:bigpicture.png[The Big Picture]
 
+/////////////////////////////////////////////////////////////////////////////////
+
 So, the hierarchy is:
 
-. *Virtual screens* (Screen 0 in this example)
-. *Workspaces* (Workspace 1 in this example)
-. *Table* (There can only be one table per Workspace)
-. *Container* (left and right in this example)
-. *Client* (The two clients in the left container)
+. *X11 root window*, the root container
+. *Output container* (LVDS1 in this example)
+. *Content container* (there are also containers for dock windows)
+. *Workspaces* (Workspace 1 in this example, with horizontal orientation)
+. *Split container* (vertically split)
+. *X11 window containers*
 
-=== Virtual screens
+The data type is +Con+, in all cases.
 
-A virtual screen (type `i3Screen`) is generated from the connected screens obtained
-through Xinerama. The difference to the raw Xinerama monitors as seen when using +xrandr(1)+
-is that it falls back to the lowest common resolution of the logical screens.
+=== X11 root window
 
-For example, if your notebook has 1280x800 and you connect a video projector with
-1024x768, set up in clone mode (+xrandr \--output VGA \--mode 1024x768 \--same-as LVDS+),
-i3 will have one virtual screen.
+The X11 root window is a single window per X11 display (a display is identified
+by +:0+ or +:1+ etc.). The root window is what you draw your background image
+on. It spans all the available outputs, e.g. +VGA1+ is a specific part of the
+root window and +LVDS1+ is a specific part of the root window.
 
-However, if you configure it using +xrandr \--output VGA \--mode 1024x768 \--right-of LVDS+,
-i3 will generate two virtual screens. For each virtual screen, a new workspace will be
-assigned. New workspaces are created on the screen you are currently on.
+=== Output container
 
-=== Workspace
+Every active output obtained through RandR is represented by one output
+container. Outputs are considered active when a mode is configured (meaning
+something is actually displayed on the output) and the output is not a clone.
 
-A workspace is identified by its number. Basically, you could think of workspaces
-as different desks in your bureau, if you like the desktop methaphor. They just contain
-different sets of windows and are completely separate of each other. Other window
-managers also call this ``Virtual desktops''.
+For example, if your notebook has a screen resolution of 1280x800 px and you
+connect a video projector with a resolution of 1024x768 px, set it up in clone
+mode (+xrandr \--output VGA1 \--mode 1024x768 \--same-as LVDS1+), i3 will
+reduce the resolution to the lowest common resolution and disable one of the
+cloned outputs afterwards.
+
+However, if you configure it using +xrandr \--output VGA1 \--mode 1024x768
+\--right-of LVDS1+, i3 will set both outputs active. For each output, a new
+workspace will be assigned. New workspaces are created on the output you are
+currently on.
+
+=== Content container
+
+Each output has multiple children. Two of them are dock containers which hold
+dock clients. The other one is the content container, which holds the actual
+content (workspaces) of this output.
+
+=== Workspace
 
-=== The layout table
+A workspace is identified by its name. Basically, you could think of
+workspaces as different desks in your office, if you like the desktop
+metaphor. They just contain different sets of windows and are completely
+separate of each other. Other window managers also call this ``Virtual
+desktops''.
 
-Each workspace has a table, which is just a two-dimensional dynamic array containing
-Containers (see below). This table grows and shrinks as you need it (by moving windows
-to the right you can create a new column in the table, by moving them to the bottom
-you create a new row).
+=== Split container
 
-=== Container
+A split container is a container which holds an arbitrary amount of split
+containers or X11 window containers. It has an orientation (horizontal or
+vertical) and a layout.
 
-A container is the content of a table’s cell. It holds an arbitrary amount of windows
-and has a specific layout (default layout or stack layout). Containers can consume
-multiple table cells by modifying their colspan/rowspan attribute.
+Split containers (and X11 window containers, which are a subtype of split
+containers) can have different border styles.
 
-=== Client
+=== X11 window container
 
-A client is x11-speak for a window.
+An X11 window container holds exactly one X11 window. These are the leaf nodes
+of the layout tree, they cannot have any children.
 
 == List/queue macros
 
-i3 makes heavy use of the list macros defined in BSD operating systems. To ensure
-that the operating system on which i3 is compiled has all the awaited features,
-i3 comes with `include/queue.h`. On BSD systems, you can use man `queue(3)`. On Linux,
-you have to use google.
+i3 makes heavy use of the list macros defined in BSD operating systems. To
+ensure that the operating system on which i3 is compiled has all the expected
+features, i3 comes with `include/queue.h`. On BSD systems, you can use man
+`queue(3)`. On Linux, you have to use google (or read the source).
 
-The lists used are `SLIST` (single linked lists) and `CIRCLEQ` (circular queues).
-Usually, only forward traversal is necessary, so an `SLIST` works fine. However,
-for the windows inside a container, a `CIRCLEQ` is necessary to go from the currently
+The lists used are +SLIST+ (single linked lists), +CIRCLEQ+ (circular
+queues) and +TAILQ+ (tail queues). Usually, only forward traversal is necessary,
+so an `SLIST` works fine. If inserting elements at arbitrary positions or at
+the end of a list is necessary, a +TAILQ+ is used instead. However, for the
+windows inside a container, a +CIRCLEQ+ is necessary to go from the currently
 selected window to the window above/below.
 
 == Naming conventions
 
-There is a row of standard variables used in many events. The following names should be
-chosen for those:
+There is a row of standard variables used in many events. The following names
+should be chosen for those:
 
  * ``conn'' is the xcb_connection_t
  * ``event'' is the event of the particular type
- * ``container'' names a container
- * ``client'' names a client, for example when using a +CIRCLEQ_FOREACH+
+ * ``con'' names a container
+ * ``current'' is a loop variable when using +TAILQ_FOREACH+ etc.
 
 == Startup (src/mainx.c, main())
 
  * Establish the xcb connection
- * Check for XKB extension on the separate X connection
- * Check for Xinerama screens
+ * Check for XKB extension on the separate X connection, load Xcursor
+ * Check for RandR screens (with a fall-back to Xinerama)
  * Grab the keycodes for which bindings exist
  * Manage all existing windows
  * Enter the event loop
@@ -249,214 +319,721 @@ chosen for those:
 
 === Grabbing the bindings
 
-Grabbing the bindings is quite straight-forward. You pass X your combination of modifiers and
-the keycode you want to grab and whether you want to grab them actively or passively. Most
-bindings (everything except for bindings using Mode_switch) are grabbed passively, that is,
-just the window manager gets the event and cannot replay it.
-
-We need to grab bindings that use Mode_switch actively because of a bug in X. When the window
-manager receives the keypress/keyrelease event for an actively grabbed keycode, it has to decide
-what to do with this event: It can either replay it so that other applications get it or it
-can prevent other applications from receiving it.
-
-So, why do we need to grab keycodes actively? Because X does not set the state-property of
-keypress/keyrelease events properly. The Mode_switch bit is not set and we need to get it
-using XkbGetState. This means we cannot pass X our combination of modifiers containing Mode_switch
-when grabbing the key and therefore need to grab the keycode itself without any modiffiers.
-This means, if you bind Mode_switch + keycode 38 ("a"), i3 will grab keycode 38 ("a") and
-check on each press of "a" if the Mode_switch bit is set using XKB. If yes, it will handle
-the event, if not, it will replay the event.
+Grabbing the bindings is quite straight-forward. You pass X your combination of
+modifiers and the keycode you want to grab and whether you want to grab them
+actively or passively. Most bindings (everything except for bindings using
+Mode_switch) are grabbed passively, that is, just the window manager gets the
+event and cannot replay it.
+
+We need to grab bindings that use Mode_switch actively because of a bug in X.
+When the window manager receives the keypress/keyrelease event for an actively
+grabbed keycode, it has to decide what to do with this event: It can either
+replay it so that other applications get it or it can prevent other
+applications from receiving it.
+
+So, why do we need to grab keycodes actively? Because X does not set the
+state-property of keypress/keyrelease events properly. The Mode_switch bit is
+not set and we need to get it using XkbGetState. This means we cannot pass X
+our combination of modifiers containing Mode_switch when grabbing the key and
+therefore need to grab the keycode itself without any modifiers. This means,
+if you bind Mode_switch + keycode 38 ("a"), i3 will grab keycode 38 ("a") and
+check on each press of "a" if the Mode_switch bit is set using XKB. If yes, it
+will handle the event, if not, it will replay the event.
 
 === Handling a keypress
 
-As mentioned in "Grabbing the bindings", upon a keypress event, i3 first gets the correct state.
+As mentioned in "Grabbing the bindings", upon a keypress event, i3 first gets
+the correct state.
 
-Then, it looks through all bindings and gets the one which matches the received event.
+Then, it looks through all bindings and gets the one which matches the received
+event.
 
-The bound command is parsed directly in command mode.
+The bound command is parsed by the cmdparse lexer/parser, see +parse_cmd+ in
++src/cmdparse.y+.
 
-== Manage windows (src/mainx.c, manage_window() and reparent_window())
+== Manage windows (src/main.c, manage_window() and reparent_window())
 
-`manage_window()` does some checks to decide whether the window should be managed at all:
+`manage_window()` does some checks to decide whether the window should be
+managed at all:
 
  * Windows have to be mapped, that is, visible on screen
- * The override_redirect must not be set. Windows with override_redirect shall not be
-   managed by a window manager
+ * The override_redirect must not be set. Windows with override_redirect shall
+   not be managed by a window manager
+
+Afterwards, i3 gets the intial geometry and reparents the window (see
+`reparent_window()`) if it wasn’t already managed.
 
-Afterwards, i3 gets the intial geometry and reparents the window if it wasn’t already
-managed.
+Reparenting means that for each window which is reparented, a new window,
+slightly larger than the original one, is created. The original window is then
+reparented to the bigger one (called "frame").
 
-Reparenting means that for each window which is reparented, a new window, slightly larger
-than the original one, is created. The original window is then reparented to the bigger one
-(called "frame").
+After reparenting, the window type (`_NET_WM_WINDOW_TYPE`) is checked to see
+whether this window is a dock (`_NET_WM_WINDOW_TYPE_DOCK`), like dzen2 for
+example. Docks are handled differently, they don’t have decorations and are not
+assigned to a specific container. Instead, they are positioned at the bottom
+or top of the screen (in the appropriate dock area containers). To get the
+height which needs to be reserved for the window, the `_NET_WM_STRUT_PARTIAL`
+property is used.
 
-After reparenting, the window type (`_NET_WM_WINDOW_TYPE`) is checked to see whether this
-window is a dock (`_NET_WM_WINDOW_TYPE_DOCK`), like dzen2 for example. Docks are handled
-differently, they don’t have decorations and are not assigned to a specific container.
-Instead, they are positioned at the bottom of the screen. To get the height which needsd
-to be reserved for the window, the `_NET_WM_STRUT_PARTIAL` property is used.
+Furthermore, the list of assignments (to other workspaces, which may be on
+other screens) is checked. If the window matches one of the user’s criteria,
+it may either be put in floating mode or moved to a different workspace. If the
+target workspace is not visible, the window will not be mapped.
 
 == What happens when an application is started?
 
-i3 does not care for applications. All it notices is when new windows are mapped (see
-`src/handlers.c`, `handle_map_notify_event()`). The window is then reparented (see section
-"Manage windows").
+i3 does not care for applications. All it notices is when new windows are
+mapped (see `src/handlers.c`, `handle_map_request()`). The window is then
+reparented (see section "Manage windows").
 
-After reparenting the window, `render_layout()` is called which renders the internal
-layout table. The window was placed in the currently focused container and
-therefore the new window and the old windows (if any) need te be moved/resized
-so that the currently active layout (default mode/stacking mode) is rendered
-correctly. To move/resize windows, a window is ``configured'' in X11-speak.
+After reparenting the window, `render_tree()` is called which renders the
+internal layout table. The new window has been placed in the currently focused
+container and therefore the new window and the old windows (if any) need to be
+moved/resized so that the currently active layout (default/stacking/tabbed mode)
+is rendered correctly. To move/resize windows, a window is ``configured'' in
+X11-speak.
 
-Some applications, such as MPlayer obivously assume the window manager is stupid
-and therefore configure their windows by themselves. This generates an event called
-configurenotify. i3 handles these events and pushes the window back to its position/size.
+Some applications, such as MPlayer obviously assume the window manager is
+stupid and try to configure their windows by themselves. This generates an
+event called configurerequest. i3 handles these events and tells the window the
+size it had before the configurerequest (with the exception of not yet mapped
+windows, which get configured like they want to, and floating windows, which
+can reconfigure themselves).
 
 == _NET_WM_STATE
 
-Only the _NET_WM_STATE_FULLSCREEN atom is handled. It calls ``toggle_fullscreen()'' for the
-specific client which just configures the client to use the whole screen on which it
-currently is. Also, it is set as fullscreen_client for the i3Screen.
+Only the _NET_WM_STATE_FULLSCREEN atom is handled. It calls
+``toggle_fullscreen()'' for the specific client which just configures the
+client to use the whole screen on which it currently is. Also, it is set as
+fullscreen_client for the i3Screen.
 
 == WM_NAME
 
-When the WM_NAME property of a window changes, its decoration (containing the title)
-is re-rendered.
+When the WM_NAME property of a window changes, its decoration (containing the
+title) is re-rendered. Note that WM_NAME is in COMPOUND_TEXT encoding which is
+totally uncommon and cumbersome. Therefore, the _NET_WM_NAME atom will be used
+if present.
+
+== _NET_WM_NAME
+
+Like WM_NAME, this atom contains the title of a window. However, _NET_WM_NAME
+is encoded in UTF-8. i3 will recode it to UCS-2 in order to be able to pass it
+to X. Using an appropriate font (ISO-10646), you can see most special
+characters (every special character contained in your font).
 
 == Size hints
 
-Size hints specify the minimum/maximum size for a given window aswell as its aspect ratio.
-At the moment, as i3 does not have a floating mode yet, only the aspect ratio is parsed.
-This is important for clients like mplayer, who only set the aspect ratio and resize their
-window to be as small as possible (but only with some video outputs, for example in Xv,
-while when using x11, mplayer does the necessary centering for itself).
+Size hints specify the minimum/maximum size for a given window as well as its
+aspect ratio.  This is important for clients like mplayer, who only set the
+aspect ratio and resize their window to be as small as possible (but only with
+some video outputs, for example in Xv, while when using x11, mplayer does the
+necessary centering for itself).
 
-So, when an aspect ratio was specified, i3 adjusts the height of the window until the
-size maintains the correct aspect ratio. For the code to do this, see src/layout.c,
-function resize_client().
+So, when an aspect ratio was specified, i3 adjusts the height of the window
+until the size maintains the correct aspect ratio. For the code to do this, see
+src/layout.c, function resize_client().
 
 == Rendering (src/layout.c, render_layout() and render_container())
 
-There are two entry points to rendering: render_layout() and render_container(). The
-former one renders all virtual screens, the currently active workspace of each virtual
-screen and all containers (inside the table cells) of these workspaces using
-render_container(). 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 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 that’s 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 output’s 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 window’s 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
+
+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
+
+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
+the table layout working and consistent.
+
+The resizing works similarly to the resizing of floating windows or movement of
+floating windows:
+
+* A new, invisible window with the size of the root window is created
+  (+grabwin+)
+* Another window, 2px width and as high as your screen (or vice versa for
+  horizontal resizing) is created. Its background color is the border color and
+  it is only there to inform the user how big the container will be (it
+  creates the impression of dragging the border out of the container).
+* The +drag_pointer+ function of +src/floating.c+ is called to grab the pointer
+  and enter its own event loop which will pass all events (expose events) but
+  motion notify events. This function then calls the specified callback
+  (+resize_callback+) which does some boundary checking and moves the helper
+  window. As soon as the mouse button is released, this loop will be
+  terminated.
+* The new width_factor for each involved column (respectively row) will be
+  calculated.
+
+/////////////////////////////////////////////////////////////////////////////////
+
+== User commands (parser-specs/commands.spec)
+
+In the configuration file and when using i3 interactively (with +i3-msg+, for
+example), you use commands to make i3 do things, like focus a different window,
+set a window to fullscreen, and so on. An example command is +floating enable+,
+which enables floating mode for the currently focused window. See the
+appropriate section in the link:userguide.html[User’s Guide] for a reference of
+all commands.
+
+In earlier versions of i3, interpreting these commands was done using lex and
+yacc, but experience has shown that lex and yacc are not well suited for our
+command language. Therefore, starting from version 4.2, we use a custom parser
+for user commands (not yet for the configuration file).
+The input specification for this parser can be found in the file
++parser-specs/commands.spec+. Should you happen to use Vim as an editor, use
+:source parser-specs/highlighting.vim to get syntax highlighting for this file
+(highlighting files for other editors are welcome).
+
+.Excerpt from commands.spec
+-----------------------------------------------------------------------
+state INITIAL:
+  '[' -> call cmd_criteria_init(); CRITERIA
+  'move' -> MOVE
+  'exec' -> EXEC
+  'workspace' -> WORKSPACE
+  'exit' -> call cmd_exit()
+  'restart' -> call cmd_restart()
+  'reload' -> call cmd_reload()
+-----------------------------------------------------------------------
+
+The input specification is written in an extremely simple format. The
+specification is then converted into C code by the Perl script
+generate-commands-parser.pl (the output file names begin with GENERATED and the
+files are stored in the +include+ directory). The parser implementation
++src/commands_parser.c+ includes the generated C code at compile-time.
+
+The above excerpt from commands.spec illustrates nearly all features of our
+specification format: You describe different states and what can happen within
+each state. State names are all-caps; the state in the above excerpt is called
+INITIAL. A list of tokens and their actions (separated by an ASCII arrow)
+follows. In the excerpt, all tokens are literals, that is, simple text strings
+which will be compared with the input. An action is either the name of a state
+in which the parser will transition into, or the keyword 'call', followed by
+the name of a function (and optionally a state).
+
+=== Example: The WORKSPACE state
+
+Let’s have a look at the WORKSPACE state, which is a good example of all
+features. This is its definition:
+
+.WORKSPACE state (commands.spec)
+----------------------------------------------------------------
+# workspace next|prev|next_on_output|prev_on_output
+# workspace back_and_forth
+# workspace <name>
+state WORKSPACE:
+  direction = 'next_on_output', 'prev_on_output', 'next', 'prev'
+      -> call cmd_workspace($direction)
+  'back_and_forth'
+      -> call cmd_workspace_back_and_forth()
+  workspace = string
+      -> call cmd_workspace_name($workspace)
+----------------------------------------------------------------
+
+As you can see from the commands, there are multiple different valid variants
+of the workspace command:
+
+workspace <direction>::
+       The word 'workspace' can be followed by any of the tokens 'next',
+       'prev', 'next_on_output' or 'prev_on_output'. This command will
+       switch to the next or previous workspace (optionally on the same
+       output). +
+       There is one function called +cmd_workspace+, which is defined
+       in +src/commands.c+. It will handle this kind of command. To know which
+       direction was specified, the direction token is stored on the stack
+       with the name "direction", which is what the "direction = " means in
+       the beginning. +
+
+NOTE: Note that you can specify multiple literals in the same line. This has
+       exactly the same effect as if you specified `direction =
+       'next_on_output' -> call cmd_workspace($direction)` and so forth. +
+
+NOTE: Also note that the order of literals is important here: If 'next' were
+       ordered before 'next_on_output', then 'next_on_output' would never
+       match.
+
+workspace back_and_forth::
+       This is a very simple case: When the literal 'back_and_forth' is found
+       in the input, the function +cmd_workspace_back_and_forth+ will be
+       called without parameters and the parser will return to the INITIAL
+       state (since no other state was specified).
+workspace <name>::
+       In this case, the workspace command is followed by an arbitrary string,
+       possibly in quotes, for example "workspace 3" or "workspace bleh". +
+       This is the first time that the token is actually not a literal (not in
+       single quotes), but just called string. Other possible tokens are word
+       (the same as string, but stops matching at a whitespace) and end
+       (matches the end of the input).
+
+=== Introducing a new command
+
+The following steps have to be taken in order to properly introduce a new
+command (or possibly extend an existing command):
+
+1. Define a function beginning with +cmd_+ in the file +src/commands.c+. Copy
+   the prototype of an existing function.
+2. After adding a comment on what the function does, copy the comment and
+   function definition to +include/commands.h+. Make the comment in the header
+   file use double asterisks to make doxygen pick it up.
+3. Write a test case (or extend an existing test case) for your feature, see
+   link:testsuite.html[i3 testsuite]. For now, it is sufficient to simply call
+   your command in all the various possible ways.
+4. Extend the parser specification in +parser-specs/commands.spec+. Run the
+   testsuite and see if your new function gets called with the appropriate
+   arguments for the appropriate input.
+5. Actually implement the feature.
+6. Document the feature in the link:userguide.html[User’s Guide].
+
+== Moving containers
+
+The movement code is pretty delicate. You need to consider all cases before
+making any changes or before being able to fully understand how it works.
+
+=== Case 1: Moving inside the same container
+
+The reference layout for this case is a single workspace in horizontal
+orientation with two containers on it. Focus is on the left container (1).
+
+
+[width="15%",cols="^,^"]
+|========
+| 1 | 2
+|========
+
+When moving the left window to the right (command +move right+), tree_move will
+look for a container with horizontal orientation and finds the parent of the
+left container, that is, the workspace. Afterwards, it runs the code branch
+commented with "the easy case": it calls TAILQ_NEXT to get the container right
+of the current one and swaps both containers.
+
+=== Case 2: Move a container into a split container
+
+The reference layout for this case is a horizontal workspace with two
+containers. The right container is a v-split with two containers. Focus is on
+the left container (1).
+
+[width="15%",cols="^,^"]
+|========
+1.2+^.^| 1 | 2
+| 3
+|========
+
+When moving to the right (command +move right+), i3 will work like in case 1
+("the easy case"). However, as the right container is not a leaf container, but
+a v-split, the left container (1) will be inserted at the right position (below
+2, assuming that 2 is focused inside the v-split) by calling +insert_con_into+.
 
-Rendering consists of two steps: In the first one, in render_layout(), each container
-gets its position (screen offset + offset in the table) and size (container's width
-times colspan/rowspan). Then, render_container() is called:
++insert_con_into+ detaches the container from its parent and inserts it
+before/after the given target container. Afterwards, the on_remove_child
+callback is called on the old parent container which will then be closed, if
+empty.
 
-render_container() then takes different approaches, depending on the mode the container
-is in.
+Afterwards, +con_focus+ will be called to fix the focus stack and the tree will
+be flattened.
 
-=== Common parts
+=== Case 3: Moving to non-existant top/bottom
 
-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 don’t completely
-fit into the frame.
+Like in case 1, the reference layout for this case is a single workspace in
+horizontal orientation with two containers on it. Focus is on the left
+container:
 
-=== Default mode
+[width="15%",cols="^,^"]
+|========
+| 1 | 2
+|========
 
-Each clients gets the container’s width and an equal amount of height.
+This time however, the command is +move up+ or +move down+. tree_move will look
+for a container with vertical orientation. As it will not find any,
++same_orientation+ is NULL and therefore i3 will perform a forced orientation
+change on the workspace by creating a new h-split container, moving the
+workspace contents into it and then changing the workspace orientation to
+vertical. Now it will again search for parent containers with vertical
+orientation and it will find the workspace.
 
-=== Stack mode
+This time, the easy case code path will not be run as we are not moving inside
+the same container. Instead, +insert_con_into+ will be called with the focused
+container and the container above/below the current one (on the level of
++same_orientation+).
 
-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.
+Now, +con_focus+ will be called to fix the focus stack and the tree will be
+flattened.
 
-=== Window decorations
+=== Case 4: Moving to existant top/bottom
 
-The window decorations consist of a rectangle in the appropriate color (depends on whether
-this window is the currently focused one or 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.
+The reference layout for this case is a vertical workspace with two containers.
+The bottom one is a h-split containing two containers (1 and 2). Focus is on
+the bottom left container (1).
+
+[width="15%",cols="^,^"]
+|========
+2+| 3
+| 1 | 2
+|========
 
-=== Fullscreen windows
+This case is very much like case 3, only this time the forced workspace
+orientation change does not need to be performed because the workspace already
+is in vertical orientation.
 
-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.
+=== Case 5: Moving in one-child h-split
 
-=== Resizing containers
+The reference layout for this case is a horizontal workspace with two
+containers having a v-split on the left side with a one-child h-split on the
+bottom. Focus is on the bottom left container (2(h)):
 
-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 the table
-layout working and consistent.
+[width="15%",cols="^,^"]
+|========
+| 1 1.2+^.^| 3
+| 2(h)
+|========
 
-Currently, only vertical resizing is implemented.
+In this case, +same_orientation+ will be set to the h-split container around
+the focused container. However, when trying the easy case, the next/previous
+container +swap+ will be NULL. Therefore, i3 will search again for a
++same_orientation+ container, this time starting from the parent of the h-split
+container.
 
-The resizing works similarly to the resizing of floating windows or movement of floating
-windows:
+After determining a new +same_orientation+ container (if it is NULL, the
+orientation will be force-changed), this case is equivalent to case 2 or case
+4.
 
-* A new, invisible window with the size of the root window is created (+grabwin+)
-* Another window, 2px width and as high as your screen (or vice versa for horizontal
-  resizing) is created. Its background color is the border color and it is only
-  there to signalize the user how big the container will be (it creates the impression
-  of dragging the border out of the container).
-* The +drag_pointer+ function of +src/floating.c+ is called to grab the pointer and
-  enter an own event loop which will pass all events (expose events) but motion notify
-  events. This function then calls the specified callback (+resize_callback+) which
-  does some boundary checking and moves the helper window. As soon as the mouse
-  button is released, this loop will be terminated.
-* The new width_factor for each involved column (respectively row) will be calculated.
 
-== User commands / commandmode (src/commands.c)
+=== Case 6: Floating containers
 
-Like in vim, you can control i3 using commands. They are intended to be a powerful
-alternative to lots of shortcuts, because they can be combined. There are a few special
-commands, which are the following:
+The reference layout for this case is a horizontal workspace with two
+containers plus one floating h-split container. Focus is on the floating
+container.
 
-exec <command>::
-Starts the given command by passing it to `/bin/sh`.
+TODO: nice illustration. table not possible?
 
-restart::
-Restarts i3 by executing `argv[0]` (the path with which you started i3) without forking.
+When moving up/down, the container needs to leave the floating container and it
+needs to be placed on the workspace (at workspace level). This is accomplished
+by calling the function +attach_to_workspace+.
 
-w::
-"With". This is used to select a bunch of windows. Currently, only selecting the whole
-container in which the window is in, is supported by specifying "w".
+== Click handling
 
-f, s, d::
-Toggle fullscreen, stacking, default mode for the current window/container.
+Without much ado, here is the list of cases which need to be considered:
 
-The other commands are to be combined with a direction. The directions are h, j, k and l,
-like in vim (h = left, j = down, k = up, l = right). When you just specify the direction
-keys, i3 will move the focus in that direction. You can provide "m" or "s" before the
-direction to move a window respectively or snap.
+* click to focus (tiling + floating) and raise (floating)
+* click to focus/raise when in stacked/tabbed mode
+* floating_modifier + left mouse button to drag a floating con
+* floating_modifier + right mouse button to resize a floating con
+* click on decoration in a floating con to either initiate a resize (if there
+  is more than one child in the floating con) or to drag the
+  floating con (if it’s the one at the top).
+* click on border in a floating con to resize the floating con
+* floating_modifier + right mouse button to resize a tiling con
+* click on border/decoration to resize a tiling con
 
 == Gotchas
 
-* Forgetting to call `xcb_flush(conn);` after sending a request. This usually leads to
-  code which looks like it works fine but which does not work under certain conditions.
+* Forgetting to call `xcb_flush(conn);` after sending a request. This usually
+  leads to code which looks like it works fine but which does not work under
+  certain conditions.
 
 == Using git / sending patches
 
-For a short introduction into using git, see http://www.spheredev.org/wiki/Git_for_the_lazy
-or, for more documentation, see http://git-scm.com/documentation
+For a short introduction into using git, see
+http://www.spheredev.org/wiki/Git_for_the_lazy or, for more documentation, see
+http://git-scm.com/documentation
 
-When you want to send a patch because you fixed a bug or implemented a cool feature (please
-talk to us before working on features to see whether they are maybe already implemented, not
-possible because of some reason or don’t fit into the concept), please use git to create
-a patchfile.
+When you want to send a patch because you fixed a bug or implemented a cool
+feature (please talk to us before working on features to see whether they are
+maybe already implemented, not possible for some some reason, or don’t fit
+into the concept), please use git to create a patchfile.
 
-First of all, update your working copy to the latest version of the master branch:
+First of all, update your working copy to the latest version of the master
+branch:
 
 --------
 git pull
 --------
 
-Afterwards, make the necessary changes for your bugfix/feature. Then, review the changes
-using +git diff+ (you might want to enable colors in the diff using +git config diff.color auto+).
-When you are definitely done, use +git commit -a+ to commit all changes you’ve made.
+Afterwards, make the necessary changes for your bugfix/feature. Then, review
+the changes using +git diff+ (you might want to enable colors in the diff using
++git config diff.color auto+).  When you are definitely done, use +git commit
+-a+ to commit all changes you’ve made.
 
-Then, use the following command to generate a patchfile which we can directly apply to
-the branch, preserving your commit message and name:
+Then, use the following command to generate a patchfile which we can directly
+apply to the branch, preserving your commit message and name:
 
 -----------------------
 git format-patch origin
 -----------------------
 
-Just send us the generated file via mail.
+Just send us the generated file via email.
+
+== Thought experiments
+
+In this section, we collect thought experiments, so that we don’t forget our
+thoughts about specific topics. They are not necessary to get into hacking i3,
+but if you are interested in one of the topics they cover, you should read them
+before asking us why things are the way they are or why we don’t implement
+things.
+
+=== Using cgroups per workspace
+
+cgroups (control groups) are a linux-only feature which provides the ability to
+group multiple processes. For each group, you can individually set resource
+limits, like allowed memory usage. Furthermore, and more importantly for our
+purposes, they serve as a namespace, a label which you can attach to processes
+and their children.
+
+One interesting use for cgroups is having one cgroup per workspace (or
+container, doesn’t really matter). That way, you could set different priorities
+and have a workspace for important stuff (say, writing a LaTeX document or
+programming) and a workspace for unimportant background stuff (say,
+JDownloader). Both tasks can obviously consume a lot of I/O resources, but in
+this example it doesn’t really matter if JDownloader unpacks the download a
+minute earlier or not. However, your compiler should work as fast as possible.
+Having one cgroup per workspace, you would assign more resources to the
+programming workspace.
+
+Another interesting feature is that an inherent problem of the workspace
+concept could be solved by using cgroups: When starting an application on
+workspace 1, then switching to workspace 2, you will get the application’s
+window(s) on workspace 2 instead of the one you started it on. This is because
+the window manager does not have any mapping between the process it starts (or
+gets started in any way) and the window(s) which appear.
+
+Imagine for example using dmenu: The user starts dmenu by pressing Mod+d, dmenu
+gets started with PID 3390. The user then decides to launch Firefox, which
+takes a long time. So he enters firefox into dmenu and presses enter. Firefox
+gets started with PID 4001. When it finally finishes loading, it creates an X11
+window and uses MapWindow to make it visible. This is the first time i3
+actually gets in touch with Firefox. It decides to map the window, but it has
+no way of knowing that this window (even though it has the _NET_WM_PID property
+set to 4001) belongs to the dmenu the user started before.
+
+How do cgroups help with this? Well, when pressing Mod+d to launch dmenu, i3
+would create a new cgroup, let’s call it i3-3390-1. It launches dmenu in that
+cgroup, which gets PID 3390. As before, the user enters firefox and Firefox
+gets launched with PID 4001. This time, though, the Firefox process with PID
+4001 is *also* member of the cgroup i3-3390-1 (because fork()ing in a cgroup
+retains the cgroup property). Therefore, when mapping the window, i3 can look
+up in which cgroup the process is and can establish a mapping between the
+workspace and the window.
+
+There are multiple problems with this approach:
+
+. Every application has to properly set +_NET_WM_PID+. This is acceptable and
+  patches can be written for the few applications which don’t set the hint yet.
+. It does only work on Linux, since cgroups are a Linux-only feature. Again,
+  this is acceptable.
+. The main problem is that some applications create X11 windows completely
+  independent of UNIX processes. An example for this is Chromium (or
+  gnome-terminal), which, when being started a second time, communicates with
+  the first process and lets the first process open a new window. Therefore, if
+  you have a Chromium window on workspace 2 and you are currently working on
+  workspace 3, starting +chromium+ does not lead to the desired result (the
+  window will open on workspace 2).
+
+Therefore, my conclusion is that the only proper way of fixing the "window gets
+opened on the wrong workspace" problem is in the application itself. Most
+modern applications support freedesktop startup-notifications  which can be
+used for this.