Update and reformat the hacking howto
This commit is contained in:
parent
1a53cc067b
commit
6abf70895d
|
@ -1,24 +1,25 @@
|
||||||
Hacking i3: How To
|
Hacking i3: How To
|
||||||
==================
|
==================
|
||||||
Michael Stapelberg <michael+i3@stapelberg.de>
|
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
|
This document is intended to be the first thing you read before looking and/or
|
||||||
i3’s source code. It should contain all important information to help you understand
|
touching i3’s source code. It should contain all important information to help
|
||||||
why things are like they are. If it does not mention something you find necessary, please
|
you understand why things are like they are. If it does not mention something
|
||||||
do not hesitate to contact me.
|
you find necessary, please do not hesitate to contact me.
|
||||||
|
|
||||||
== Window Managers
|
== Window Managers
|
||||||
|
|
||||||
A window manager is not necessarily needed to run X, but it is usually used in combination
|
A window manager is not necessarily needed to run X, but it is usually used in
|
||||||
to facilitate some things. The window manager's job is to take care of the placement of
|
combination with X to facilitate some things. The window manager's job is to
|
||||||
windows, to provide the user some mechanisms to change the position/size of windows and
|
take care of the placement of windows, to provide the user with some mechanisms
|
||||||
to communicate with clients to a certain extent (for example handle fullscreen requests
|
to change the position/size of windows and to communicate with clients to a
|
||||||
of clients such as MPlayer).
|
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
|
There are no different contexts in which X11 clients run, so a window manager
|
||||||
client, like all other X11 applications. However, it handles some events which normal clients
|
is just another client, like all other X11 applications. However, it handles
|
||||||
usually don’t handle.
|
some events which normal clients usually don’t handle.
|
||||||
|
|
||||||
In the case of i3, the tasks (and order of them) are the following:
|
In the case of i3, the tasks (and order of them) are the following:
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ 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_STATE` property, but only the `_WM_STATE_FULLSCREEN`
|
||||||
. Handle the client’s `WM_NAME` property
|
. Handle the client’s `WM_NAME` property
|
||||||
. Handle the client’s size hints to display them proportionally
|
. Handle the client’s size hints to display them proportionally
|
||||||
|
. Handle the client’s urgency hint
|
||||||
. Handle enter notifications (focus follows mouse)
|
. Handle enter notifications (focus follows mouse)
|
||||||
. Handle button (as in mouse buttons) presses for focus/raise on click
|
. Handle button (as in mouse buttons) presses for focus/raise on click
|
||||||
. Handle expose events to re-draw own windows such as decorations
|
. Handle expose events to re-draw own windows such as decorations
|
||||||
|
@ -36,37 +38,43 @@ In the case of i3, the tasks (and order of them) are the following:
|
||||||
Change the layout mode of a container (default/stacking), Start a new application,
|
Change the layout mode of a container (default/stacking), Start a new application,
|
||||||
Restart the window manager
|
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
|
=== Tiling window managers
|
||||||
|
|
||||||
Traditionally, there are two approaches to managing windows: The most common one nowadays is
|
Traditionally, there are two approaches to managing windows: The most common
|
||||||
floating, which means the user can freely move/resize the windows. The other approach is called
|
one nowadays is floating, which means the user can freely move/resize the
|
||||||
tiling, which means that your window manager distributing windows to use as much space as
|
windows. The other approach is called tiling, which means that your window
|
||||||
possible while not overlapping.
|
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
|
The idea behind tiling is that you should not need to waste your time
|
||||||
while you usually want to get some work done. After all, most users sooner or later tend to
|
moving/resizing windows while you usually want to get some work done. After
|
||||||
lay out their windows in a way which corresponds to tiling or stacking mode in i3. Therefore,
|
all, most users sooner or later tend to lay out their windows in a way which
|
||||||
why not let i3 do this for you? Certainly, it’s faster than you could ever do it.
|
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
|
The problem with most tiling window managers is that they are too unflexible.
|
||||||
window manager is just another tool, and similar to vim which can edit all kinds of text files
|
In my opinion, a window manager is just another tool, and similar to vim which
|
||||||
(like source code, HTML, …) and is not limited to a specific file type, a window manager should
|
can edit all kinds of text files (like source code, HTML, …) and is not limited
|
||||||
not limit itself to a certain layout (like dwm, awesome, …) but provide mechanisms for you to
|
to a specific file type, a window manager should not limit itself to a certain
|
||||||
easily create the layout you need at the moment.
|
layout (like dwm, awesome, …) but provide mechanisms for you to easily create
|
||||||
|
the layout you need at the moment.
|
||||||
|
|
||||||
=== The layout table
|
=== The layout table
|
||||||
|
|
||||||
To accomplish flexible layouts, we decided to simply use a table. The table grows and shrinks
|
To accomplish flexible layouts, we decided to simply use a table. The table
|
||||||
as you need it. Each cell holds a container which then holds windows (see picture below). You
|
grows and shrinks as you need it. Each cell holds a container which then holds
|
||||||
can use different layouts for each container (default layout and stacking layout).
|
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,
|
So, when you open a terminal and immediately open another one, they reside in
|
||||||
in default layout. The layout table has exactly one column, one row and therefore one cell.
|
the same container, in default layout. The layout table has exactly one column,
|
||||||
When you move one of the terminals to the right, the table needs to grow. It will be expanded
|
one row and therefore one cell. When you move one of the terminals to the
|
||||||
to two columns and one row. This enables you to have different layouts for each container.
|
right, the table needs to grow. It will be expanded to two columns and one row.
|
||||||
The table then looks like this:
|
This enables you to have different layouts for each container. The table then
|
||||||
|
looks like this:
|
||||||
|
|
||||||
[width="15%",cols="^,^"]
|
[width="15%",cols="^,^"]
|
||||||
|========
|
|========
|
||||||
|
@ -81,9 +89,9 @@ When moving terminal 2 to the bottom, the table will be expanded again.
|
||||||
| | T2
|
| | T2
|
||||||
|========
|
|========
|
||||||
|
|
||||||
You can really think of the layout table like a traditional HTML table, if you’ve ever
|
You can really think of the layout table like a traditional HTML table, if
|
||||||
designed one. Especially col- and rowspan work equally. Below you see an example of
|
you’ve ever designed one. Especially col- and rowspan work equally. Below you
|
||||||
colspan=2 for the first container (which has T1 as window).
|
see an example of colspan=2 for the first container (which has T1 as window).
|
||||||
|
|
||||||
[width="15%",cols="^asciidoc"]
|
[width="15%",cols="^asciidoc"]
|
||||||
|========
|
|========
|
||||||
|
@ -100,12 +108,23 @@ Furthermore, you can freely resize table cells.
|
||||||
== Files
|
== Files
|
||||||
|
|
||||||
include/data.h::
|
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::
|
include/*.h::
|
||||||
Contains forward definitions for all public functions, aswell as doxygen-compatible
|
Contains forward definitions for all public functions, aswell as
|
||||||
comments (so if you want to get a bit more of the big picture, either browse all
|
doxygen-compatible comments (so if you want to get a bit more of the big
|
||||||
header files or use doxygen if you prefer that).
|
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::
|
src/client.c::
|
||||||
Contains all functions which are specific to a certain client (make it
|
Contains all functions which are specific to a certain client (make it
|
||||||
|
@ -159,12 +178,13 @@ src/xcb.c::
|
||||||
Contains wrappers to use xcb more easily.
|
Contains wrappers to use xcb more easily.
|
||||||
|
|
||||||
src/xinerama.c::
|
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
|
== Data structures
|
||||||
|
|
||||||
See include/data.h for documented data structures. The most important ones are explained
|
See include/data.h for documented data structures. The most important ones are
|
||||||
right here.
|
explained right here.
|
||||||
|
|
||||||
image:bigpicture.png[The Big Picture]
|
image:bigpicture.png[The Big Picture]
|
||||||
|
|
||||||
|
@ -178,37 +198,40 @@ So, the hierarchy is:
|
||||||
|
|
||||||
=== Virtual screens
|
=== Virtual screens
|
||||||
|
|
||||||
A virtual screen (type `i3Screen`) is generated from the connected screens obtained
|
A virtual screen (type `i3Screen`) is generated from the connected screens
|
||||||
through Xinerama. The difference to the raw Xinerama monitors as seen when using +xrandr(1)+
|
obtained through Xinerama. The difference to the raw Xinerama monitors as seen
|
||||||
is that it falls back to the lowest common resolution of the logical screens.
|
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
|
For example, if your notebook has 1280x800 and you connect a video projector
|
||||||
1024x768, set up in clone mode (+xrandr \--output VGA \--mode 1024x768 \--same-as LVDS+),
|
with 1024x768, set up in clone mode (+xrandr \--output VGA \--mode 1024x768
|
||||||
i3 will have one virtual screen.
|
\--same-as LVDS+), i3 will have one virtual screen.
|
||||||
|
|
||||||
However, if you configure it using +xrandr \--output VGA \--mode 1024x768 \--right-of LVDS+,
|
However, if you configure it using +xrandr \--output VGA \--mode 1024x768
|
||||||
i3 will generate two virtual screens. For each virtual screen, a new workspace will be
|
\--right-of LVDS+, i3 will generate two virtual screens. For each virtual
|
||||||
assigned. New workspaces are created on the screen you are currently on.
|
screen, a new workspace will be assigned. New workspaces are created on the
|
||||||
|
screen you are currently on.
|
||||||
|
|
||||||
=== Workspace
|
=== Workspace
|
||||||
|
|
||||||
A workspace is identified by its number. Basically, you could think of workspaces
|
A workspace is identified by its number. Basically, you could think of
|
||||||
as different desks in your bureau, if you like the desktop methaphor. They just contain
|
workspaces as different desks in your bureau, if you like the desktop
|
||||||
different sets of windows and are completely separate of each other. Other window
|
methaphor. They just contain different sets of windows and are completely
|
||||||
managers also call this ``Virtual desktops''.
|
separate of each other. Other window managers also call this ``Virtual
|
||||||
|
desktops''.
|
||||||
|
|
||||||
=== The layout table
|
=== The layout table
|
||||||
|
|
||||||
Each workspace has a table, which is just a two-dimensional dynamic array containing
|
Each workspace has a table, which is just a two-dimensional dynamic array
|
||||||
Containers (see below). This table grows and shrinks as you need it (by moving windows
|
containing Containers (see below). This table grows and shrinks as you need it
|
||||||
to the right you can create a new column in the table, by moving them to the bottom
|
(by moving windows to the right you can create a new column in the table, by
|
||||||
you create a new row).
|
moving them to the bottom you create a new row).
|
||||||
|
|
||||||
=== Container
|
=== Container
|
||||||
|
|
||||||
A container is the content of a table’s cell. It holds an arbitrary amount of windows
|
A container is the content of a table’s cell. It holds an arbitrary amount of
|
||||||
and has a specific layout (default layout or stack layout). Containers can consume
|
windows and has a specific layout (default layout or stack layout). Containers
|
||||||
multiple table cells by modifying their colspan/rowspan attribute.
|
can consume multiple table cells by modifying their colspan/rowspan attribute.
|
||||||
|
|
||||||
=== Client
|
=== Client
|
||||||
|
|
||||||
|
@ -216,20 +239,22 @@ A client is x11-speak for a window.
|
||||||
|
|
||||||
== List/queue macros
|
== List/queue macros
|
||||||
|
|
||||||
i3 makes heavy use of the list macros defined in BSD operating systems. To ensure
|
i3 makes heavy use of the list macros defined in BSD operating systems. To
|
||||||
that the operating system on which i3 is compiled has all the awaited features,
|
ensure that the operating system on which i3 is compiled has all the expected
|
||||||
i3 comes with `include/queue.h`. On BSD systems, you can use man `queue(3)`. On Linux,
|
features, i3 comes with `include/queue.h`. On BSD systems, you can use man
|
||||||
you have to use google.
|
`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).
|
The lists used are `SLIST` (single linked lists), `CIRCLEQ` (circular
|
||||||
Usually, only forward traversal is necessary, so an `SLIST` works fine. However,
|
queues) and TAILQ (tail queues). Usually, only forward traversal is necessary,
|
||||||
for the windows inside a container, a `CIRCLEQ` is necessary to go from the currently
|
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.
|
selected window to the window above/below.
|
||||||
|
|
||||||
== Naming conventions
|
== Naming conventions
|
||||||
|
|
||||||
There is a row of standard variables used in many events. The following names should be
|
There is a row of standard variables used in many events. The following names
|
||||||
chosen for those:
|
should be chosen for those:
|
||||||
|
|
||||||
* ``conn'' is the xcb_connection_t
|
* ``conn'' is the xcb_connection_t
|
||||||
* ``event'' is the event of the particular type
|
* ``event'' is the event of the particular type
|
||||||
|
@ -249,116 +274,138 @@ chosen for those:
|
||||||
|
|
||||||
=== Grabbing the bindings
|
=== Grabbing the bindings
|
||||||
|
|
||||||
Grabbing the bindings is quite straight-forward. You pass X your combination of modifiers and
|
Grabbing the bindings is quite straight-forward. You pass X your combination of
|
||||||
the keycode you want to grab and whether you want to grab them actively or passively. Most
|
modifiers and the keycode you want to grab and whether you want to grab them
|
||||||
bindings (everything except for bindings using Mode_switch) are grabbed passively, that is,
|
actively or passively. Most bindings (everything except for bindings using
|
||||||
just the window manager gets the event and cannot replay it.
|
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
|
We need to grab bindings that use Mode_switch actively because of a bug in X.
|
||||||
manager receives the keypress/keyrelease event for an actively grabbed keycode, it has to decide
|
When the window manager receives the keypress/keyrelease event for an actively
|
||||||
what to do with this event: It can either replay it so that other applications get it or it
|
grabbed keycode, it has to decide what to do with this event: It can either
|
||||||
can prevent other applications from receiving it.
|
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
|
So, why do we need to grab keycodes actively? Because X does not set the
|
||||||
keypress/keyrelease events properly. The Mode_switch bit is not set and we need to get it
|
state-property of keypress/keyrelease events properly. The Mode_switch bit is
|
||||||
using XkbGetState. This means we cannot pass X our combination of modifiers containing Mode_switch
|
not set and we need to get it using XkbGetState. This means we cannot pass X
|
||||||
when grabbing the key and therefore need to grab the keycode itself without any modiffiers.
|
our combination of modifiers containing Mode_switch when grabbing the key and
|
||||||
This means, if you bind Mode_switch + keycode 38 ("a"), i3 will grab keycode 38 ("a") and
|
therefore need to grab the keycode itself without any modiffiers. This means,
|
||||||
check on each press of "a" if the Mode_switch bit is set using XKB. If yes, it will handle
|
if you bind Mode_switch + keycode 38 ("a"), i3 will grab keycode 38 ("a") and
|
||||||
the event, if not, it will replay the event.
|
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
|
=== 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 directly in command mode.
|
||||||
|
|
||||||
== Manage windows (src/mainx.c, manage_window() and reparent_window())
|
== 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
|
* Windows have to be mapped, that is, visible on screen
|
||||||
* The override_redirect must not be set. Windows with override_redirect shall not be
|
* The override_redirect must not be set. Windows with override_redirect shall
|
||||||
managed by a window manager
|
not be managed by a window manager
|
||||||
|
|
||||||
Afterwards, i3 gets the intial geometry and reparents the window if it wasn’t already
|
Afterwards, i3 gets the intial geometry and reparents the window (see
|
||||||
managed.
|
`reparent_window()`) if it wasn’t already managed.
|
||||||
|
|
||||||
Reparenting means that for each window which is reparented, a new window, slightly larger
|
Reparenting means that for each window which is reparented, a new window,
|
||||||
than the original one, is created. The original window is then reparented to the bigger one
|
slightly larger than the original one, is created. The original window is then
|
||||||
(called "frame").
|
reparented to the bigger one (called "frame").
|
||||||
|
|
||||||
After reparenting, the window type (`_NET_WM_WINDOW_TYPE`) is checked to see whether this
|
After reparenting, the window type (`_NET_WM_WINDOW_TYPE`) is checked to see
|
||||||
window is a dock (`_NET_WM_WINDOW_TYPE_DOCK`), like dzen2 for example. Docks are handled
|
whether this window is a dock (`_NET_WM_WINDOW_TYPE_DOCK`), like dzen2 for
|
||||||
differently, they don’t have decorations and are not assigned to a specific container.
|
example. Docks are handled differently, they don’t have decorations and are not
|
||||||
Instead, they are positioned at the bottom of the screen. To get the height which needsd
|
assigned to a specific container. Instead, they are positioned at the bottom
|
||||||
to be reserved for the window, the `_NET_WM_STRUT_PARTIAL` property is used.
|
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?
|
== What happens when an application is started?
|
||||||
|
|
||||||
i3 does not care for applications. All it notices is when new windows are mapped (see
|
i3 does not care for applications. All it notices is when new windows are
|
||||||
`src/handlers.c`, `handle_map_request()`). The window is then reparented (see section
|
mapped (see `src/handlers.c`, `handle_map_request()`). The window is then
|
||||||
"Manage windows").
|
reparented (see section "Manage windows").
|
||||||
|
|
||||||
After reparenting the window, `render_layout()` is called which renders the internal
|
After reparenting the window, `render_layout()` is called which renders the
|
||||||
layout table. The window was placed in the currently focused container and
|
internal layout table. The new window has been placed in the currently focused
|
||||||
therefore the new window and the old windows (if any) need to be moved/resized
|
container and therefore the new window and the old windows (if any) need to be
|
||||||
so that the currently active layout (default mode/stacking mode) is rendered
|
moved/resized so that the currently active layout (default mode/stacking mode)
|
||||||
correctly. To move/resize windows, a window is ``configured'' in X11-speak.
|
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
|
Some applications, such as MPlayer obivously assume the window manager is
|
||||||
and try to configure their windows by themselves. This generates an event called
|
stupid and try to configure their windows by themselves. This generates an
|
||||||
configurerequest. i3 handles these events and tells the window the size it had
|
event called configurerequest. i3 handles these events and tells the window the
|
||||||
before the configurerequest (with the exception of not yet mapped windows, which
|
size it had before the configurerequest (with the exception of not yet mapped
|
||||||
get configured like they want to, and floating windows, which can reconfigure
|
windows, which get configured like they want to, and floating windows, which
|
||||||
themselves).
|
can reconfigure themselves).
|
||||||
|
|
||||||
== _NET_WM_STATE
|
== _NET_WM_STATE
|
||||||
|
|
||||||
Only the _NET_WM_STATE_FULLSCREEN atom is handled. It calls ``toggle_fullscreen()'' for the
|
Only the _NET_WM_STATE_FULLSCREEN atom is handled. It calls
|
||||||
specific client which just configures the client to use the whole screen on which it
|
``toggle_fullscreen()'' for the specific client which just configures the
|
||||||
currently is. Also, it is set as fullscreen_client for the i3Screen.
|
client to use the whole screen on which it currently is. Also, it is set as
|
||||||
|
fullscreen_client for the i3Screen.
|
||||||
|
|
||||||
== WM_NAME
|
== WM_NAME
|
||||||
|
|
||||||
When the WM_NAME property of a window changes, its decoration (containing the title)
|
When the WM_NAME property of a window changes, its decoration (containing the
|
||||||
is re-rendered.
|
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
|
||||||
|
|
||||||
Size hints specify the minimum/maximum size for a given window aswell as its aspect ratio.
|
Size hints specify the minimum/maximum size for a given window aswell as its
|
||||||
At the moment, as i3 does not have a floating mode yet, only the aspect ratio is parsed.
|
aspect ratio. This is important for clients like mplayer, who only set the
|
||||||
This is important for clients like mplayer, who only set the aspect ratio and resize their
|
aspect ratio and resize their window to be as small as possible (but only with
|
||||||
window to be as small as possible (but only with some video outputs, for example in Xv,
|
some video outputs, for example in Xv, while when using x11, mplayer does the
|
||||||
while when using x11, mplayer does the necessary centering for itself).
|
necessary centering for itself).
|
||||||
|
|
||||||
So, when an aspect ratio was specified, i3 adjusts the height of the window until the
|
So, when an aspect ratio was specified, i3 adjusts the height of the window
|
||||||
size maintains the correct aspect ratio. For the code to do this, see src/layout.c,
|
until the size maintains the correct aspect ratio. For the code to do this, see
|
||||||
function resize_client().
|
src/layout.c, function resize_client().
|
||||||
|
|
||||||
== Rendering (src/layout.c, render_layout() and render_container())
|
== Rendering (src/layout.c, render_layout() and render_container())
|
||||||
|
|
||||||
There are two entry points to rendering: render_layout() and render_container(). The
|
There are several entry points to rendering: `render_layout()`,
|
||||||
former one renders all virtual screens, the currently active workspace of each virtual
|
`render_workspace()` and `render_container()`. The former one calls
|
||||||
screen and all containers (inside the table cells) of these workspaces using
|
`render_workspace()` for every screen, which in turn will call
|
||||||
render_container(). Therefore, if you need to render only a single container, for
|
`render_container()` for every container inside its layout table. Therefore, if
|
||||||
example because a window was removed, added or changed its title, you should directly
|
you need to render only a single container, for example because a window was
|
||||||
call render_container().
|
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
|
Rendering consists of two steps: In the first one, in `render_workspace()`, each
|
||||||
gets its position (screen offset + offset in the table) and size (container's width
|
container gets its position (screen offset + offset in the table) and size
|
||||||
times colspan/rowspan). Then, render_container() is called:
|
(container's width times colspan/rowspan). Then, `render_container()` is called,
|
||||||
|
which takes different approaches, depending on the mode the container is in:
|
||||||
render_container() then takes different approaches, depending on the mode the container
|
|
||||||
is in.
|
|
||||||
|
|
||||||
=== Common parts
|
=== Common parts
|
||||||
|
|
||||||
On the frame (the window which was created around the client’s window for the decorations),
|
On the frame (the window which was created around the client’s window for the
|
||||||
a black rectangle is drawn as a background for windows like MPlayer, which don’t completely
|
decorations), a black rectangle is drawn as a background for windows like
|
||||||
fit into the frame.
|
MPlayer, which do not completely fit into the frame.
|
||||||
|
|
||||||
=== Default mode
|
=== Default mode
|
||||||
|
|
||||||
|
@ -366,97 +413,109 @@ Each clients gets the container’s width and an equal amount of height.
|
||||||
|
|
||||||
=== Stack mode
|
=== Stack mode
|
||||||
|
|
||||||
In stack mode, a window containing the decorations of all windows inside the container
|
In stack mode, a window containing the decorations of all windows inside the
|
||||||
is placed at the top. The currently focused window is then given the whole remaining
|
container is placed at the top. The currently focused window is then given the
|
||||||
space.
|
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
|
=== Window decorations
|
||||||
|
|
||||||
The window decorations consist of a rectangle in the appropriate color (depends on whether
|
The window decorations consist of a rectangle in the appropriate color (depends
|
||||||
this window is the currently focused one or the last focused one in a not focused container
|
on whether this window is the currently focused one, the last focused one in a
|
||||||
or not focused at all) forming the background. Afterwards, two lighter lines are drawn
|
not focused container or not focused at all) forming the background.
|
||||||
and the last step is drawing the window’s title (see WM_NAME) onto it.
|
Afterwards, two lighter lines are drawn and the last step is drawing the
|
||||||
|
window’s title (see WM_NAME) onto it.
|
||||||
|
|
||||||
=== Fullscreen windows
|
=== Fullscreen windows
|
||||||
|
|
||||||
For fullscreen windows, the `rect` (x, y, width, height) is not changed to allow the client
|
For fullscreen windows, the `rect` (x, y, width, height) is not changed to
|
||||||
to easily go back to its previous position. Instead, fullscreen windows are skipped
|
allow the client to easily go back to its previous position. Instead,
|
||||||
when rendering.
|
fullscreen windows are skipped when rendering.
|
||||||
|
|
||||||
=== Resizing containers
|
=== Resizing containers
|
||||||
|
|
||||||
By clicking and dragging the border of a container, you can resize the whole column
|
By clicking and dragging the border of a container, you can resize the whole
|
||||||
(respectively row) which this container is in. This is necessary to keep the table
|
column (respectively row) which this container is in. This is necessary to keep
|
||||||
layout working and consistent.
|
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:
|
||||||
|
|
||||||
The resizing works similarly to the resizing of floating windows or movement of floating
|
* A new, invisible window with the size of the root window is created
|
||||||
windows:
|
(+grabwin+)
|
||||||
|
* Another window, 2px width and as high as your screen (or vice versa for
|
||||||
* A new, invisible window with the size of the root window is created (+grabwin+)
|
horizontal resizing) is created. Its background color is the border color and
|
||||||
* Another window, 2px width and as high as your screen (or vice versa for horizontal
|
it is only there to signalize the user how big the container will be (it
|
||||||
resizing) is created. Its background color is the border color and it is only
|
creates the impression of dragging the border out of the container).
|
||||||
there to signalize the user how big the container will be (it creates the impression
|
* The +drag_pointer+ function of +src/floating.c+ is called to grab the pointer
|
||||||
of dragging the border out of the container).
|
and enter an own event loop which will pass all events (expose events) but
|
||||||
* The +drag_pointer+ function of +src/floating.c+ is called to grab the pointer and
|
motion notify events. This function then calls the specified callback
|
||||||
enter an own event loop which will pass all events (expose events) but motion notify
|
(+resize_callback+) which does some boundary checking and moves the helper
|
||||||
events. This function then calls the specified callback (+resize_callback+) which
|
window. As soon as the mouse button is released, this loop will be
|
||||||
does some boundary checking and moves the helper window. As soon as the mouse
|
terminated.
|
||||||
button is released, this loop will be terminated.
|
* The new width_factor for each involved column (respectively row) will be
|
||||||
* The new width_factor for each involved column (respectively row) will be calculated.
|
calculated.
|
||||||
|
|
||||||
== User commands / commandmode (src/commands.c)
|
== User commands / commandmode (src/commands.c)
|
||||||
|
|
||||||
Like in vim, you can control i3 using commands. They are intended to be a powerful
|
Like in vim, you can control i3 using commands. They are intended to be a
|
||||||
alternative to lots of shortcuts, because they can be combined. There are a few special
|
powerful alternative to lots of shortcuts, because they can be combined. There
|
||||||
commands, which are the following:
|
are a few special commands, which are the following:
|
||||||
|
|
||||||
exec <command>::
|
exec <command>::
|
||||||
Starts the given command by passing it to `/bin/sh`.
|
Starts the given command by passing it to `/bin/sh`.
|
||||||
|
|
||||||
restart::
|
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::
|
w::
|
||||||
"With". This is used to select a bunch of windows. Currently, only selecting the whole
|
"With". This is used to select a bunch of windows. Currently, only selecting
|
||||||
container in which the window is in, is supported by specifying "w".
|
the whole container in which the window is in, is supported by specifying "w".
|
||||||
|
|
||||||
f, s, d::
|
f, s, d::
|
||||||
Toggle fullscreen, stacking, default mode for the current window/container.
|
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,
|
The other commands are to be combined with a direction. The directions are h,
|
||||||
like in vim (h = left, j = down, k = up, l = right). When you just specify the direction
|
j, k and l, like in vim (h = left, j = down, k = up, l = right). When you just
|
||||||
keys, i3 will move the focus in that direction. You can provide "m" or "s" before the
|
specify the direction keys, i3 will move the focus in that direction. You can
|
||||||
direction to move a window respectively or snap.
|
provide "m" or "s" before the direction to move a window respectively or snap.
|
||||||
|
|
||||||
== Gotchas
|
== Gotchas
|
||||||
|
|
||||||
* Forgetting to call `xcb_flush(conn);` after sending a request. This usually leads to
|
* Forgetting to call `xcb_flush(conn);` after sending a request. This usually
|
||||||
code which looks like it works fine but which does not work under certain conditions.
|
leads to code which looks like it works fine but which does not work under
|
||||||
|
certain conditions.
|
||||||
|
|
||||||
== Using git / sending patches
|
== Using git / sending patches
|
||||||
|
|
||||||
For a short introduction into using git, see http://www.spheredev.org/wiki/Git_for_the_lazy
|
For a short introduction into using git, see
|
||||||
or, for more documentation, see http://git-scm.com/documentation
|
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
|
When you want to send a patch because you fixed a bug or implemented a cool
|
||||||
talk to us before working on features to see whether they are maybe already implemented, not
|
feature (please talk to us before working on features to see whether they are
|
||||||
possible because of some reason or don’t fit into the concept), please use git to create
|
maybe already implemented, not possible because of some reason or don’t fit
|
||||||
a patchfile.
|
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
|
Afterwards, make the necessary changes for your bugfix/feature. Then, review
|
||||||
using +git diff+ (you might want to enable colors in the diff using +git config diff.color auto+).
|
the changes using +git diff+ (you might want to enable colors in the diff using
|
||||||
When you are definitely done, use +git commit -a+ to commit all changes you’ve made.
|
+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
|
Then, use the following command to generate a patchfile which we can directly
|
||||||
the branch, preserving your commit message and name:
|
apply to the branch, preserving your commit message and name:
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
git format-patch origin
|
git format-patch origin
|
||||||
|
|
Loading…
Reference in New Issue