Hacking i3: How To
==================
Michael Stapelberg <michael+i3@stapelberg.de>
-May 2009
+December 2009
-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:
. 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
Change the layout mode of a container (default/stacking), 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.
-
-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.
+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.
+
+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).
+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:
+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="^,^"]
|========
| | T2
|========
-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).
+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).
[width="15%",cols="^asciidoc"]
|========
== Files
include/data.h::
-Contains data definitions used by nearly all files. You really need to read this first.
+Contains data definitions used by nearly all files. You really need to read
+this first.
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).
+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/cfgparse.l::
+Contains the lexer for i3’s configuration file, written for +flex(1)+.
+
+src/cfgparse.y::
+Contains the parser for i3’s configuration file, written for +bison(1)+.
+
+src/click.c::
+Contains all functions which handle mouse button clicks (right mouse button
+clicks initiate resizing and thus are relatively complex).
src/client.c::
Contains all functions which are specific to a certain client (make it
Contains wrappers to use xcb more easily.
src/xinerama.c::
-(Re-)initializes the available screens and converts them to virtual screens (see below).
+(Re-)initializes the available screens and converts them to virtual screens
+(see below).
== 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.
image:bigpicture.png[The Big Picture]
=== Virtual screens
-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.
+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.
-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.
+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.
-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.
+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.
=== Workspace
-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''.
+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''.
=== The layout table
-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).
+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).
=== Container
-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.
+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.
=== Client
== 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
=== 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 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.
=== 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.
== Manage windows (src/mainx.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
+of the screen. To get the height which needsd 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_request()`). 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 to 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_layout()` 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 mode/stacking 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 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).
+Some applications, such as MPlayer obivously 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 aswell 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().
+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_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:
-
-render_container() then takes different approaches, depending on the mode the container
-is in.
+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 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.
+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.
=== Default mode
=== 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.
+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 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 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.
=== 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.
+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 column
-(respectively row) which this container is in. This is necessary to keep the table
-layout working and consistent.
-
-Currently, only vertical resizing is implemented.
-
-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 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.
+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 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)
-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:
+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:
exec <command>::
Starts the given command by passing it to `/bin/sh`.
restart::
-Restarts i3 by executing `argv[0]` (the path with which you started i3) without forking.
+Restarts i3 by executing `argv[0]` (the path with which you started i3) without
+forking.
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".
+"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".
f, s, d::
Toggle fullscreen, stacking, default mode for the current window/container.
-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.
+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.
== 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 because of 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
+rit 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