Hacking i3: How To
==================
-Michael Stapelberg <michael+i3@stapelberg.de>
-July 2011
+Michael Stapelberg <michael@i3wm.org>
+February 2013
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
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_STATE` property, but only `_WM_STATE_FULLSCREEN` and
+ `_NET_WM_STATE_DEMANDS_ATTENTION`
. Handle the client’s `WM_NAME` property
. Handle the client’s size hints to display them proportionally
. Handle the client’s urgency hint
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.
+The problem with most tiling window managers is that they are too inflexible.
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
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/config_parser.c::
+Contains a custom configuration parser. See src/command_parser.c for rationale
+ on why we use a custom parser.
src/click.c::
Contains all functions which handle mouse button clicks (right mouse button
clicks initiate resizing and thus are relatively complex).
-src/cmdparse.l::
-Contains the lexer for i3 commands, written for +flex(1)+.
-
-src/cmdparse.y::
-Contains the parser for i3 commands, written for +bison(1)+.
+src/command_parser.c::
+Contains a hand-written parser to parse commands (commands are what
+you bind on keys and what you can send to i3 using the IPC interface, like
+'move left' or 'workspace 4').
src/con.c::
Contains all functions which deal with containers directly (creating
src/config.c::
Contains all functions handling the configuration file (calling the parser
-(src/cfgparse.y) with the correct path, switching key bindings mode).
+src/config_parser.c) with the correct path, switching key bindings mode).
src/debug.c::
Contains debugging functions to print unhandled X events.
src/resize.c::
Contains the functions to resize containers.
+src/restore_layout.c::
+Everything for restored containers that is not pure state parsing (which can be
+found in load_layout.c).
+
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
* 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
+Afterwards, i3 gets the initial geometry and reparents the window (see
`reparent_window()`) if it wasn’t already managed.
Reparenting means that for each window which is reparented, a new window,
== What happens when an application is started?
-i3 does not care for applications. All it notices is when new windows are
+i3 does not care about 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").
== _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 and _NET_WM_STATE_DEMANDS_ATTENTION atoms
+are handled.
+
+The former 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.
+
+The latter is used to set, read and display urgency hints.
== WM_NAME
==== Dock area layout
-This is a special case. Users cannot chose the dock area layout, but it will be
+This is a special case. Users cannot choose 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.
+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").
+display a window decoration for split containers, which consists of a representation
+of the child container's names.
Then, parameters are collected to be able to determine whether this decoration
drawing is actually necessary or was already done. This saves a substantial
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).
+for user commands and 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
++parser-specs/*.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).
# workspace next|prev|next_on_output|prev_on_output
# workspace back_and_forth
# workspace <name>
+# workspace number <number>
state WORKSPACE:
direction = 'next_on_output', 'prev_on_output', 'next', 'prev'
-> call cmd_workspace($direction)
'back_and_forth'
-> call cmd_workspace_back_and_forth()
+ 'number'
+ -> WORKSPACE_NUMBER
workspace = string
-> call cmd_workspace_name($workspace)
----------------------------------------------------------------
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).
+workspace number <number>::
+ The workspace command has to be followed by the keyword +number+. It
+ then transitions into the state +WORKSPACE_NUMBER+, where the actual
+ parameter will be read.
=== Introducing a new command
== Using git / sending patches
+=== Introduction
+
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
+http://web.archive.org/web/20121024222556/http://www.spheredev.org/wiki/Git_for_the_lazy
+or, for more documentation, see http://git-scm.com/documentation
+
+Please talk to us before working on new features to see whether they will be
+accepted. A good way for this is to open an issue and asking for opinions on it.
+Even for accepted features, this can be a good way to refine an idea upfront. However,
+we don't want to see certain features in i3, e.g., switching window focus in an
+Alt+Tab like way.
-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.
+When working on bugfixes, please make sure you mention that you are working on
+it in the corresponding bug report at https://github.com/i3/i3/issues. In case
+there is no bug report yet, please create one.
-First of all, update your working copy to the latest version of the master
-branch:
+After you are done, please submit your work for review as a pull request at
+https://github.com/i3/i3.
---------
-git pull
---------
+Do not send emails to the mailing list or any author directly, and don’t submit
+them in the bugtracker, since all reviews should be done in public at
+https://github.com/i3/i3. In order to make your review go as fast as possible, you
+could have a look at previous reviews and see what the common mistakes are.
-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.
+=== Which branch to use?
-Then, use the following command to generate a patchfile which we can directly
-apply to the branch, preserving your commit message and name:
+Work on i3 generally happens in two branches: “master” and “next” (the latter
+being the default branch, the one that people get when they check out the git
+repository).
------------------------
-git format-patch origin
------------------------
+The contents of “master” are always stable. That is, it contains the source code
+of the latest release, plus any bugfixes that were applied since that release.
-Just send us the generated file via email.
+New features are only found in the “next” branch. Therefore, if you are working
+on a new feature, use the “next” branch. If you are working on a bugfix, use the
+“next” branch, too, but make sure your code also works on “master”.
== Thought experiments
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
+takes a long time. So they enter firefox into dmenu and press 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