diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 122927469..40fd8399f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -38,4 +38,4 @@ Note that bug reports and feature requests for related projects should be filed * Find a [reproducible bug](https://github.com/i3/i3/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Areproducible+label%3Abug+) from the issue tracker. These issues have been reviewed and confirmed by a project contributor. * Find an [accepted enhancement](https://github.com/i3/i3/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Aaccepted+label%3Aenhancement) from the issue tracker. These have been approved and are ok to start working on. -There's a very good [overview of the codebase](https://i3wm.org/docs/hacking-howto.html) available to get you started. +There's an [overview of the codebase](https://i3wm.org/docs/hacking-howto.html) available to get you started. diff --git a/RELEASE-NOTES-next b/RELEASE-NOTES-next index c52a49ad9..f8c21241b 100644 --- a/RELEASE-NOTES-next +++ b/RELEASE-NOTES-next @@ -17,6 +17,8 @@ strongly encouraged to upgrade. • make dock client order deterministic (sorted by class/instance) as a side effect, i3bars without an explicit bar-id will be sorted according to their definition order in the config file + • update i3bar config when necessary (reduces redraws on bar mode changes) + • mention rofi in default config file ┌────────────────────────────┐ │ Bugfixes │ @@ -33,3 +35,4 @@ strongly encouraged to upgrade. • i3-dmenu-desktop: Support symlinks in search path • build: correctly provide auxiliary functions when needed • build: fix issues with parallel build + • set _NET_DESKTOP_VIEWPORT after randr changes diff --git a/docs/bigpicture.asy b/docs/bigpicture.asy new file mode 100644 index 000000000..4b3656c62 --- /dev/null +++ b/docs/bigpicture.asy @@ -0,0 +1,19 @@ +import drawtree; +treeLevelStep = 2cm; +TreeNode n94457831379296 = makeNode("``root'' (splith) []"); +TreeNode n94457831380944 = makeNode(n94457831379296, "``\_\_i3'' (output) []"); +TreeNode n94457831384048 = makeNode(n94457831380944, "``content'' (splith) []"); +TreeNode n94457831387184 = makeNode(n94457831384048, "``\_\_i3\_scratch'' (splith) []"); +TreeNode n94457831390576 = makeNode(n94457831379296, "``eDP-1'' (output) []"); +TreeNode n94457831393744 = makeNode(n94457831390576, "``topdock'' (dockarea) []"); +TreeNode n94457831396992 = makeNode(n94457831390576, "``content'' (splith) []"); +TreeNode n94457831628304 = makeNode(n94457831396992, "``1'' (splith) []"); +TreeNode n94457831571040 = makeNode(n94457831628304, "``Hacking i3: How To - Mozilla Firefox'' (leaf) []"); +TreeNode n94457831246384 = makeNode(n94457831628304, "``vim'' (leaf) []"); +TreeNode n94457831461088 = makeNode(n94457831396992, "``Named workspace'' (splith) []"); +TreeNode n94457831471424 = makeNode(n94457831461088, "``[Empty]'' (tabbed) []"); +TreeNode n94457831570576 = makeNode(n94457831471424, "``contrib/dump-asy.pl --no-gv'' (leaf) [Marks go here]"); +TreeNode n94457831645488 = makeNode(n94457831471424, "``ipython'' (leaf) []"); +TreeNode n94457831400192 = makeNode(n94457831390576, "``bottomdock'' (dockarea) []"); +TreeNode n94457831424848 = makeNode(n94457831400192, "``i3bar for output eDP-1'' (leaf) []"); +draw(n94457831379296, (0, 0)); diff --git a/docs/bigpicture.png b/docs/bigpicture.png index fc3c8db75..031673b8f 100644 Binary files a/docs/bigpicture.png and b/docs/bigpicture.png differ diff --git a/docs/bigpicture.xcf b/docs/bigpicture.xcf deleted file mode 100644 index ead007194..000000000 Binary files a/docs/bigpicture.xcf and /dev/null differ diff --git a/docs/hacking-howto b/docs/hacking-howto index 2ca44a5ff..ff3c89bca 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -8,6 +8,19 @@ 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. +++++ +
+WARNING! +

+++++ +This document is not 100% up to date. Specifically, everything up to and +including <> has been updated recently. The rest might contain +outdated information. +++++ +

+
+++++ + == Building i3 You can build i3 like you build any other software package which uses autotools. @@ -18,60 +31,51 @@ Here’s a memory refresher: $ ../configure $ make -j8 -(The autoreconf -fi step is unnecessary if you are building from a release tarball, - but shouldn’t hurt either.) +The autoreconf -fi step is unnecessary if you are building from a release +tarball, but shouldn’t hurt either. === Build system features -* We use the AX_ENABLE_BUILDDIR macro to enforce builds happening in a separate - directory. This is a prerequisite for the AX_EXTEND_SRCDIR macro and building +* We use the +AX_ENABLE_BUILDDIR+ macro to enforce builds happening in a separate + directory. This is a prerequisite for the +AX_EXTEND_SRCDIR+ macro and building in a separate directory is common practice anyway. In case this causes any trouble when packaging i3 for your distribution, please open an issue. -* “make check” runs the i3 testsuite. See docs/testsuite for details. +* +make check+ runs the i3 testsuite. See docs/testsuite for details. -* “make distcheck” (runs testsuite on “make dist” result, tiny bit quicker +* +make distcheck+ (runs testsuite on +make dist+ result, tiny bit quicker feedback cycle than waiting for the travis build to catch the issue). -* “make uninstall” (occasionally requested by users who compile from source) +* +make uninstall+ (occasionally requested by users who compile from source) -* “make” will build manpages/docs by default if the tools are installed. +* +make+ will build manpages/docs by default if the tools are installed. Conversely, manpages/docs are not tried to be built for users who don’t want - to install all these dependencies to get started hacking on i3. + to install all these dependencies to get started hacking on i3. Manpages and + docs can be disabled with the +--disable-mans++ and ++--disable-docs++ + configure options respectively. * non-release builds will enable address sanitizer by default. Use the - --disable-sanitizers configure option to turn off all sanitizers, and see - --help for available sanitizers. - -* Support for pre-compiled headers (PCH) has been dropped for now in the - interest of simplicity. If you need support for PCH, please open an issue. + +--disable-sanitizers+ configure option to turn off all sanitizers, and see + +--help+ for available sanitizers. -* Coverage reports are now generated using “make check-code-coverage”, which - requires specifying --enable-code-coverage when calling configure. +* Coverage reports are now generated using +make check-code-coverage+, which + requires specifying +--enable-code-coverage+ when calling configure. -== Using git / sending patches - -For a short introduction into using git, see -https://web.archive.org/web/20121024222556/http://www.spheredev.org/wiki/Git_for_the_lazy -or, for more documentation, see https://git-scm.com/documentation +== Pull requests 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. +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 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. +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. After you are done, please submit your work for review as a pull request at -https://github.com/i3/i3. - -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. +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. === Which branch to use? @@ -82,9 +86,8 @@ repository). 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. -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”. +New features are only found in the “next” branch. Always use this branch when +writing new code (both bugfixes and features). == Window Managers @@ -106,9 +109,9 @@ In the case of i3, the tasks (and order of them) are the following: 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 `_WM_STATE_FULLSCREEN` and - `_NET_WM_STATE_DEMANDS_ATTENTION` -. Handle the client’s `WM_NAME` property +. 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 . Handle enter notifications (focus follows mouse) @@ -123,11 +126,11 @@ 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 distributes windows to use as much space as possible while not -overlapping each other. +Traditionally, there are two approaches to managing windows: The most common one +nowadays is stacking (or floating, using i3's terminology), which means the user +can freely move/resize the windows, potentially overlapping them. The other +approach is called tiling, which means that the window manager distributes +windows to use as much space as possible while not overlapping each other. The idea behind tiling is that you should not need to waste your time moving/resizing windows while you usually want to get some work done. After @@ -161,63 +164,67 @@ example. == Files -include/atoms.xmacro:: -A file containing all X11 atoms which i3 uses. This file will be included -various times (for defining, requesting and receiving the atoms), each time -with a different definition of xmacro(). +i3's source code is in the +src+ folder while header files reside in +include+. +Other tools such as i3bar and i3-nagbar have their own folders. i3 and its tools +share an internal library called ``libi3'' which also has its own folder. + +The following list gives an overview of the codebase, explaining the +functionality of the most important, core source code files. Other files in the +tree that are not mentioned here implement specific functionalities: for example, ++src/scratchpad.c+ is obviously about the scratchpad functionality. 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. include/*.h:: Contains forward definitions for all public functions, as well as doxygen-compatible comments (so if you want to get a bit more of the big picture, either browse all header files or use doxygen if you prefer that). -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/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/config_directives.c:: +src/commands.c:: +Contain the definitions for all high-level config and command directives. These +are excellent places to start with a top-to-bottom approach to understand +specific i3 behavior. For example, if you want to investigate a bug that happens +for the +move to mark+ command, you can use gdb to pause in ++cmd_move_con_to_mark+ and then work your way from there, stepping into +lower-level functions. src/con.c:: -Contains all functions which deal with containers directly (creating -containers, searching containers, getting specific properties from containers, -…). +Contains all functions which deal with containers directly (creating containers, +searching containers, getting specific properties from containers, …). Contains +abstractions and auxiliary functions necessary to work with the container +structure which is used in almost all parts of the codebase. -src/config.c:: -Contains all functions handling the configuration file (calling the parser -src/config_parser.c) with the correct path, switching key bindings mode). - -src/ewmh.c:: -Functions to get/set certain EWMH properties easily. +src/tree.c:: +Contains functions which deal with the tree abstraction. However, be aware that ++src/con.c+ also contains functions that heavily interact with the tree +structure. Some functions that are included in +str/tree.c+ are those that handle +opening and closing containers in the tree, finding the container that should be +focused next and flattening the tree. See also +src/move.c+ for other +move-specific functions that interact with the tree, which were moved into their +own file because they are so long. -src/floating.c:: -Contains functions for floating mode (mostly resizing/dragging). +src/workspace.c:: +Contains functions which deal with workspaces. Includes code that creates new +workspaces, shows existing ones and deals with workspace assignments. src/handlers.c:: Contains all handlers for all kinds of X events (new window title, new hints, -unmapping, key presses, button presses, …). +unmapping, key presses, button presses, …). This is a very important file to +understand how i3 interacts with changes to its environment. -src/ipc.c:: -Contains code for the IPC interface. - -src/load_layout.c:: -Contains code for loading layouts from JSON files. - -src/log.c:: -Contains the logging functions. +src/command_parser.c:: +src/config_parser.c:: +Contain a hand-written parser to parse commands and configuration (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/config.c+ is responsible for calling the +configuration parser. -src/main.c:: -Initializes the window manager. +src/click.c:: +src/resize.c:: +Contain functions which handle mouse button clicks (right mouse button +clicks initiate resizing and thus are relatively complex). src/manage.c:: Looks at existing or new windows and decides whether to manage them. If so, it @@ -226,93 +233,66 @@ reparents the window and inserts it into our data structures. src/match.c:: A "match" is a data structure which acts like a mask or expression to match certain windows or not. For example, when using commands, you can specify a -command like this: [title="*Firefox*"] kill. The title member of the match +command like this: +[title="*Firefox*"] kill+. The title member of the match data structure will then be filled and i3 will check each window using -match_matches_window() to find the windows affected by this command. - -src/move.c:: -Contains code to move a container in a specific direction. - -src/output.c:: -Functions to handle CT_OUTPUT cons. ++match_matches_window()+ to find the windows affected by this command. src/randr.c:: The RandR API is used to get (and re-query) the configured outputs (monitors, -…). +…). Legacy Xinerama support resides in +src/xinerama.c+. src/render.c:: Renders the tree data structure by assigning coordinates to every node. These values will later be pushed to X11 in +src/x.c+. -src/resize.c:: -Contains the functions to resize 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 -in-place but forget about the layout. - -src/tree.c:: -Contains functions which open or close containers in the tree, change focus or -cleanup ("flatten") the tree. See also +src/move.c+ for another similar -function, which was moved into its own file because it is so long. - -src/util.c:: -Contains useful functions which are not really dependent on anything. +You can choose to let it dump core and restart i3 in-place (either trying to +preserve layout or forget about it). src/window.c:: Handlers to update X11 window properties like +WM_CLASS+, +_NET_WM_NAME+, +CLIENT_LEADER+, etc. -src/workspace.c:: -Contains all functions related to workspaces (displaying, hiding, renaming…) - -src/x.c:: -Transfers our in-memory tree (see +src/render.c+) to X11. - -src/xcb.c:: -Contains wrappers to use xcb more easily. - -src/xcursor.c:: -XCursor functions (for cursor themes). - -src/xinerama.c:: -Legacy support for Xinerama. See +src/randr.c+ for the preferred API. +include/atoms.xmacro:: +A file containing all X11 atoms which i3 uses. This file will be included +various times (for defining, requesting and receiving the atoms), each time +with a different definition of xmacro(). +[[data_structures]] == Data structures +See +include/data.h+ for documented data structures. The most important ones are +explained here. -See include/data.h for documented data structures. The most important ones are -explained right here. - -///////////////////////////////////////////////////////////////////////////////// -// TODO: update image - -image:bigpicture.png[The Big Picture] +The following picture is generated by the +contrib/dump-asy.pl+ script. -///////////////////////////////////////////////////////////////////////////////// +image:bigpicture.png["The Big Picture",width=1000,link="bigpicture.png"] -So, the hierarchy is: +The hierarchy is: -. *X11 root window*, the root container -. *Output container* (LVDS1 in this example) -. *Content container* (there are also containers for dock windows) -. *Workspaces* (Workspace 1 in this example, with horizontal orientation) -. *Split container* (vertically split) -. *X11 window containers* +. *Root container* +. *Output containers*: +eDP-1+ in this example and the internal +__i3++ output +. *Content and 2 dockarea containers* +. *Workspaces*: Numbered workspace ``1'' and a ``Named workspace'' +. *Split containers*: One horizontal in the first workspace and a tabbed one in + the named one. +. *Leaf containers*: Windows like vim and an i3bar dock. The data type is +Con+, in all cases. -=== X11 root window +=== Root container + +The root container (global variable +croot+) is the up-most ascendant of every i3 +container. It can be used to iterate over the whole tree structure. E.g., it is +used to reply to the +GET_WORKSPACES+ request, iterating over it's children to +find all workspaces. This is different from the X11 root window. -The X11 root window is a single window per X11 display (a display is identified -by +:0+ or +:1+ etc.). The root window is what you draw your background image -on. It spans all the available outputs, e.g. +VGA1+ is a specific part of the -root window and +LVDS1+ is a specific part of the root window. +The X11 root window (global variable +root+) is a single window per X11 display +(a display is identified by +:0+ or +:1+ etc.). The root window is what you draw +your background image on. It spans all the available outputs, e.g. +VGA1+ is a +specific part of the root window and +LVDS1+ is a specific part of the root +window. === Output container @@ -334,8 +314,8 @@ currently on. === Content container Each output has multiple children. Two of them are dock containers which hold -dock clients. The other one is the content container, which holds the actual -content (workspaces) of this output. +the top and bottom dock clients. The other one is the content container, which +holds the actual content (workspaces) of this output. === Workspace @@ -354,21 +334,20 @@ vertical) and a layout. Split containers (and X11 window containers, which are a subtype of split containers) can have different border styles. -=== X11 window container +=== Leaf containers -An X11 window container holds exactly one X11 window. These are the leaf nodes -of the layout tree, they cannot have any children. +A leaf container holds exactly one X11 window. They can't have any children. == List/queue macros i3 makes heavy use of the list macros defined in BSD operating systems. To ensure that the operating system on which i3 is compiled has all the 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). +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), +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 +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. @@ -378,10 +357,10 @@ selected window to the window above/below. 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 - * ``con'' names a container - * ``current'' is a loop variable when using +TAILQ_FOREACH+ etc. + * +conn+ is the xcb_connection_t + * +event+ is the event of the particular type + * +con+ names a container + * +current+ is a loop variable when using +TAILQ_FOREACH+ etc. == Startup (src/mainx.c, main()) @@ -430,7 +409,7 @@ The bound command is parsed by the cmdparse lexer/parser, see +parse_cmd+ in == Manage windows (src/main.c, manage_window() and reparent_window()) -`manage_window()` does some checks to decide whether the window should be ++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 @@ -438,18 +417,18 @@ managed at all: not be managed by a window manager Afterwards, i3 gets the initial geometry and reparents the window (see -`reparent_window()`) if it wasn’t already managed. ++reparent_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"). -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 +After reparenting, the window type (+_NET_WM_WINDOW_TYPE+) is checked to see +whether this window is a dock (+_NET_WM_WINDOW_TYPE_DOCK+), like dzen2 for example. Docks are handled differently, they don’t have decorations and are not assigned to a specific container. Instead, they are positioned at the bottom or top of the screen (in the appropriate dock area containers). To get the -height which needs to be reserved for the window, the `_NET_WM_STRUT_PARTIAL` +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 @@ -460,10 +439,10 @@ target workspace is not visible, the window will not be mapped. == What happens when an application is started? 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 +mapped (see +src/handlers.c+, +handle_map_request()+). The window is then reparented (see section "Manage windows"). -After reparenting the window, `render_tree()` is called which renders the +After reparenting the window, +render_tree()+ is called which renders the internal layout table. The new window has been placed in the currently focused container and therefore the new window and the old windows (if any) need to be moved/resized so that the currently active layout (default/stacking/tabbed mode) @@ -482,7 +461,7 @@ can reconfigure themselves). 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 +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. @@ -539,7 +518,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. @@ -558,7 +537,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. @@ -566,7 +545,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 @@ -574,22 +553,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. @@ -835,8 +814,8 @@ workspace :: 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. + + 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 @@ -1020,11 +999,11 @@ Without much ado, here is the list of cases which need to be considered: == Gotchas -* Forgetting to call `xcb_flush(conn);` after sending a request. This usually +* 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 `floating_fix_coordinates(con, old_rect, new_rect)` after +* 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. diff --git a/etc/config b/etc/config index 2591c1875..67bcb1473 100644 --- a/etc/config +++ b/etc/config @@ -53,9 +53,10 @@ bindsym Mod1+Shift+q kill # start dmenu (a program launcher) bindsym Mod1+d exec dmenu_run -# There also is the (new) i3-dmenu-desktop which only displays applications -# shipping a .desktop file. It is a wrapper around dmenu, so you need that -# installed. +# A more modern dmenu replacement is rofi: +# bindsym Mod1+d exec rofi -modi drun,run -show drun +# There also is i3-dmenu-desktop which only displays applications shipping a +# .desktop file. It is a wrapper around dmenu, so you need that installed. # bindsym Mod1+d exec --no-startup-id i3-dmenu-desktop # change focus diff --git a/etc/config.keycodes b/etc/config.keycodes index 951c0a23e..35468bf06 100644 --- a/etc/config.keycodes +++ b/etc/config.keycodes @@ -47,10 +47,11 @@ bindcode $mod+Shift+24 kill # start dmenu (a program launcher) bindcode $mod+40 exec dmenu_run -# There also is the (new) i3-dmenu-desktop which only displays applications -# shipping a .desktop file. It is a wrapper around dmenu, so you need that -# installed. -# bindsym $mod+d exec --no-startup-id i3-dmenu-desktop +# A more modern dmenu replacement is rofi: +# bindcode $mod+40 exec rofi -modi drun,run -show drun +# There also is i3-dmenu-desktop which only displays applications shipping a +# .desktop file. It is a wrapper around dmenu, so you need that installed. +bindcode $mod+40 exec --no-startup-id i3-dmenu-desktop # change focus bindcode $mod+44 focus left diff --git a/include/commands.h b/include/commands.h index de066e45f..00be6672a 100644 --- a/include/commands.h +++ b/include/commands.h @@ -315,10 +315,16 @@ void cmd_title_format(I3_CMD, const char *format); void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name); /** - * Implementation of 'bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) []' + * Implementation of 'bar mode dock|hide|invisible|toggle []' * */ -void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id); +void cmd_bar_mode(I3_CMD, const char *bar_mode, const char *bar_id); + +/** + * Implementation of 'bar hidden_state hide|show|toggle []' + * + */ +void cmd_bar_hidden_state(I3_CMD, const char *bar_hidden_state, const char *bar_id); /** * Implementation of 'shmlog |toggle|on|off' diff --git a/include/configuration.h b/include/configuration.h index 53973462d..c09791f14 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -437,9 +437,3 @@ bool load_configuration(const char *override_configfile, config_load_t load_type * */ void ungrab_all_keys(xcb_connection_t *conn); - -/** - * Sends the current bar configuration as an event to all barconfig_update listeners. - * - */ -void update_barconfig(void); diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index f6e541e9c..3f28078e4 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -478,15 +478,17 @@ state BAR: -> BAR_MODE state BAR_HIDDEN_STATE: - bar_value = 'hide', 'show', 'toggle' - -> BAR_W_ID + bar_hidden_state = 'hide', 'show', 'toggle' + -> + bar_id = word + -> + end + -> call cmd_bar_hidden_state($bar_hidden_state, $bar_id) state BAR_MODE: bar_value = 'dock', 'hide', 'invisible', 'toggle' - -> BAR_W_ID - -state BAR_W_ID: + -> bar_id = word -> end - -> call cmd_bar($bar_type, $bar_value, $bar_id) + -> call cmd_bar_mode($bar_value, $bar_id) diff --git a/src/commands.c b/src/commands.c index d5f526621..4b2eed6b8 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1621,8 +1621,11 @@ void cmd_reload(I3_CMD) { x_set_i3_atoms(); /* Send an IPC event just in case the ws names have changed */ ipc_send_workspace_event("reload", NULL, NULL); - /* Send an update event for the barconfig just in case it has changed */ - update_barconfig(); + /* Send an update event for each barconfig just in case it has changed */ + Barconfig *current; + TAILQ_FOREACH (current, &barconfigs, configs) { + ipc_send_barconfig_update_event(current); + } // XXX: default reply for now, make this a better reply ysuccess(true); @@ -2075,7 +2078,7 @@ void cmd_rename_workspace(I3_CMD, const char *old_name, const char *new_name) { * Implementation of 'bar mode dock|hide|invisible|toggle []' * */ -static bool cmd_bar_mode(const char *bar_mode, const char *bar_id) { +void cmd_bar_mode(I3_CMD, const char *bar_mode, const char *bar_id) { int mode = M_DOCK; bool toggle = false; if (strcmp(bar_mode, "dock") == 0) @@ -2088,39 +2091,38 @@ static bool cmd_bar_mode(const char *bar_mode, const char *bar_id) { toggle = true; else { ELOG("Unknown bar mode \"%s\", this is a mismatch between code and parser spec.\n", bar_mode); - return false; + assert(false); } - bool changed_sth = false; Barconfig *current = NULL; TAILQ_FOREACH (current, &barconfigs, configs) { - if (bar_id && strcmp(current->id, bar_id) != 0) + if (strcmp(current->id, bar_id) != 0) { continue; + } - if (toggle) + if (toggle) { mode = (current->mode + 1) % 2; + } - DLOG("Changing bar mode of bar_id '%s' to '%s (%d)'\n", current->id, bar_mode, mode); - current->mode = mode; - changed_sth = true; - - if (bar_id) - break; - } + DLOG("Changing bar mode of bar_id '%s' from '%d' to '%s (%d)'\n", + current->id, current->mode, bar_mode, mode); + if ((int)current->mode != mode) { + current->mode = mode; + ipc_send_barconfig_update_event(current); + } - if (bar_id && !changed_sth) { - DLOG("Changing bar mode of bar_id %s failed, bar_id not found.\n", bar_id); - return false; + ysuccess(true); + return; } - return true; + yerror("Changing bar mode of bar_id %s failed, bar_id not found.\n", bar_id); } /* * Implementation of 'bar hidden_state hide|show|toggle []' * */ -static bool cmd_bar_hidden_state(const char *bar_hidden_state, const char *bar_id) { +void cmd_bar_hidden_state(I3_CMD, const char *bar_hidden_state, const char *bar_id) { int hidden_state = S_SHOW; bool toggle = false; if (strcmp(bar_hidden_state, "hide") == 0) @@ -2131,54 +2133,31 @@ static bool cmd_bar_hidden_state(const char *bar_hidden_state, const char *bar_i toggle = true; else { ELOG("Unknown bar state \"%s\", this is a mismatch between code and parser spec.\n", bar_hidden_state); - return false; + assert(false); } - bool changed_sth = false; Barconfig *current = NULL; TAILQ_FOREACH (current, &barconfigs, configs) { - if (bar_id && strcmp(current->id, bar_id) != 0) + if (strcmp(current->id, bar_id) != 0) { continue; + } - if (toggle) + if (toggle) { hidden_state = (current->hidden_state + 1) % 2; + } - DLOG("Changing bar hidden_state of bar_id '%s' to '%s (%d)'\n", current->id, bar_hidden_state, hidden_state); - current->hidden_state = hidden_state; - changed_sth = true; - - if (bar_id) - break; - } - - if (bar_id && !changed_sth) { - DLOG("Changing bar hidden_state of bar_id %s failed, bar_id not found.\n", bar_id); - return false; - } - - return true; -} - -/* - * Implementation of 'bar (hidden_state hide|show|toggle)|(mode dock|hide|invisible|toggle) []' - * - */ -void cmd_bar(I3_CMD, const char *bar_type, const char *bar_value, const char *bar_id) { - bool ret; - if (strcmp(bar_type, "mode") == 0) - ret = cmd_bar_mode(bar_value, bar_id); - else if (strcmp(bar_type, "hidden_state") == 0) - ret = cmd_bar_hidden_state(bar_value, bar_id); - else { - ELOG("Unknown bar option type \"%s\", this is a mismatch between code and parser spec.\n", bar_type); - ret = false; - } + DLOG("Changing bar hidden_state of bar_id '%s' from '%d' to '%s (%d)'\n", + current->id, current->hidden_state, bar_hidden_state, hidden_state); + if ((int)current->hidden_state != hidden_state) { + current->hidden_state = hidden_state; + ipc_send_barconfig_update_event(current); + } - ysuccess(ret); - if (!ret) + ysuccess(true); return; + } - update_barconfig(); + yerror("Changing bar hidden_state of bar_id %s failed, bar_id not found.\n", bar_id); } /* diff --git a/src/config.c b/src/config.c index 112f2baa9..26f02bb3a 100644 --- a/src/config.c +++ b/src/config.c @@ -28,17 +28,6 @@ void ungrab_all_keys(xcb_connection_t *conn) { xcb_ungrab_key(conn, XCB_GRAB_ANY, root, XCB_BUTTON_MASK_ANY); } -/* - * Sends the current bar configuration as an event to all barconfig_update listeners. - * - */ -void update_barconfig(void) { - Barconfig *current; - TAILQ_FOREACH (current, &barconfigs, configs) { - ipc_send_barconfig_update_event(current); - } -} - static void free_configuration(void) { assert(conn != NULL); diff --git a/src/randr.c b/src/randr.c index 56b0707fc..bdb1ce12e 100644 --- a/src/randr.c +++ b/src/randr.c @@ -1023,6 +1023,7 @@ void randr_query_outputs(void) { } /* render_layout flushes */ + ewmh_update_desktop_properties(); tree_render(); FREE(primary);