X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=docs%2Fhacking-howto;h=73ae96335991d5312e1b61b5a0c265be8a16926f;hb=5a29e61a4605cb3a1a9333d8e85d9afdc6b51ab1;hp=58d2fed20bc733614c3f9a38d72106265b2e35e6;hpb=8d433ecc6bbf1496bd81ff57eb5c1f73cf060953;p=i3%2Fi3 diff --git a/docs/hacking-howto b/docs/hacking-howto index 58d2fed2..73ae9633 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -63,57 +63,22 @@ 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 +=== The layout tree -********************************************************************************* -This section has not been updated for v4.0 yet, sorry! We wanted to release on -time, but we will update this soon. Please talk to us on IRC if you need to -know stuff *NOW* :). -********************************************************************************* - -///////////////////////////////////////////////////////////////////////////////// -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). +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 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 -|======== +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. -When moving terminal 2 to the bottom, the table will be expanded again. - -[width="15%",cols="^,^"] -|======== -| T1 | -| | 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 similarly. Below, -you see an example of colspan=2 for the first container (which has T1 as -window). - -[width="15%",cols="^asciidoc"] -|======== -| T1 -| -[cols="^,^",frame="none"] -!======== -! T2 ! T3 -!======== -|======== - -Furthermore, you can freely resize table cells. -///////////////////////////////////////////////////////////////////////////////// +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. == Files @@ -299,7 +264,7 @@ content (workspaces) of this output. A workspace is identified by its name. Basically, you could think of workspaces as different desks in your office, if you like the desktop -methaphor. They just contain different sets of windows and are completely +metaphor. They just contain different sets of windows and are completely separate of each other. Other window managers also call this ``Virtual desktops''. @@ -406,8 +371,9 @@ 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 needs to be reserved for the window, -the `_NET_WM_STRUT_PARTIAL` property is used. +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. 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, @@ -492,7 +458,7 @@ container) to the bottom. === Rendering the root container -The i3 root container (+con->type == CT_ROOT+) represents the X11 root window. +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. @@ -511,7 +477,7 @@ only called for the global fullscreen window. === Rendering an output -Output containers (+con->layout == L_OUTPUT+) represent a hardware output like +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. @@ -519,7 +485,7 @@ containers. The rendering happens in the function +render_l_output()+ in the following steps: -1. Find the content container (+con->type == CT_CON+) +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 @@ -527,22 +493,22 @@ steps: 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). + 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 +`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 +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. @@ -706,41 +672,123 @@ floating windows: ///////////////////////////////////////////////////////////////////////////////// -== User commands / commandmode (src/cmdparse.{l,y}) - -********************************************************************************* -This section has not been updated for v4.0 yet, sorry! We wanted to release on -time, but we will update this soon. Please talk to us on IRC if you need to -know stuff *NOW* :). -********************************************************************************* - -///////////////////////////////////////////////////////////////////////////////// - - -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 :: -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. - -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. - -///////////////////////////////////////////////////////////////////////////////// +== 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 +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 :: + 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 :: + 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 @@ -888,6 +936,11 @@ Without much ado, here is the list of cases which need to be considered: leads to code which looks like it works fine but which does not work under certain conditions. +* Forgetting to call `floating_fix_coordinates(con, old_rect, new_rect)` after + moving workspaces across outputs. Coordinates for floating containers are + not relative to workspace boundaries, so you must correct their coordinates + or those containers will show up in the wrong workspace or not at all. + == Using git / sending patches For a short introduction into using git, see