HERBSTLUFTWM(1)

๐Ÿ’– okay bestie, it's herbstluftwm time ๐Ÿ’–

This is the herbstluftwm(1) manual, rewritten so it actually makes sense. Grab a snack, we're doing window-manager lore. ๐Ÿ“

โœจ NAME โœจ

herbstluftwm โ€” a manual tiling window manager for X. Periodt.

๐ŸŒธ SYNOPSIS ๐ŸŒธ

herbstluftwm [OPTION ...]

๐Ÿ’… DESCRIPTION ๐Ÿ’…

So herbstluftwm starts the herbstluftwm window manager on DISPLAY. It also listens for calls from herbstclient(1) and executes them. The full list of available COMMANDS is literally below, don't worry.

OPTION can be:

  • -v, --version โ€” print version and exit.
  • -h, --help โ€” print a short help and exit.
  • -c, --autostart PATH โ€” use PATH as the autostart file instead of the one in $XDG_CONFIG_HOME.
  • --replace โ€” replace the existing window manager.
  • -l, --locked โ€” initially set the monitors_locked setting to 1. WARNING: this keeps herbstluftwm locked until the unlock command is invoked (usually by the autostart). If --locked is activated but the autostart does not invoke unlock (or if its invokation is unreachable because of a blocking command before), then herbstluftwm stays locked, resulting in frozen state. Only use with care!
  • --exit-on-xerror โ€” make herbstluftwm exit whenever xlib reports an error. This may only be activated for automated testing and never for actual sessions.
  • --no-transparency โ€” disable true transparency.
  • --no-tag-import โ€” do not preserve the tags (virtual desktops) from a previous running window manager.
  • --verbose โ€” print verbose information to stderr. This can be switched at run-time by the verbose setting.

This manual documents the scripting and configuration interface. For a more verbose introduction, see herbstluftwm-tutorial(7). ๐Ÿ’œ

๐ŸŒˆ TILING ALGORITHM ๐ŸŒˆ

The basic tiling concept is that the layout is represented by a binary tree. On startup you see one big frame across the entire screen. A frame fulfills exactly one of the following conditions:

  1. Frame contains windows:

It shows some clients and arranges them. The available layout algorithms are:

  • vertical โ€” clients are placed below each other.
  • horizontal โ€” clients are placed next to each other.
  • max โ€” all clients are maximized in this frame.
  • grid โ€” clients are arranged in an almost quadratic grid.
  1. Frame is split into subframes:

It is split into exactly two subframes in a configurable fraction, either in a vertical or horizontal way. So it produces two frames which fulfill the same conditions (new frames always are about to contain windows). If you split a frame that already contains windows, the windows are inherited by the first new child frame.

If a new window appears, it is put in the currently focused frame. Only the leaves of the frame tree can be focused.

A frame can be removed, and it is then merged with its neighbour frame. Due to the layout structure of a binary tree, each frame (i.e. node in binary tree) has exactly one neighbour.

The analogy to a binary tree is explained the best way with a small example. On startup you have a simple binary tree, with one frame that can contain clients:

C

When splitting it (e.g. with the command split vertical 0.5) you will get this:

      V
     / \
    C   C

You also can split the left frame horizontally and you will get:

        V
       / \
      H   C
     / \
    C   C

If you change the focus to the client on the right and remove this frame, it will be merged with the left subtree and you will get:

      H
     / \
    C   C

The layout command prints the current layout of all tags as a tree. Cute, right? ๐ŸŒธ

๐ŸŽ€ FRAME INDEX ๐ŸŽ€

The exact position of a frame in the layout tree may be described by its index, which is just a string of characters. The lookup algorithm starts at the root frame and interprets the index string character by character as follows:

  • 0 โ€” select the first subtree.
  • 1 โ€” select the second subtree.
  • . โ€” select the subtree having the focus.
  • / โ€” select the subtree not having the focus.
  • @ โ€” select the frame having the focus. In contrast to ., this passes multiple layers all down to the focused leaf of the frame tree.
  • p โ€” select the parent tree.
  • e โ€” finds a suitable empty frame: if the focused frame is not empty, this selects the closest frame that is empty (in any subtree).

For example:

  • An empty string refers to the root frame.
  • 00 refers to the first subtree of the first subtree of the root frame.
  • 1e refers to the first empty frame in the second subtree.
  • /@ refers to the focused frame within the unfocused "half" of the frame tree.
  • @p/ refers to the sibling of the focused frame.

๐Ÿฆ‹ TAGS ๐Ÿฆ‹

Tags are very similar to workspaces, virtual desktops or window groups. Each tag has one layout. There is a list of tags. You can add or remove tags dynamically. Very main-character energy, honestly. โœจ

๐Ÿ’œ MONITORS ๐Ÿ’œ

Monitors in herbstluftwm are totally independent of the actual physical screens. This means you can, for example, split your screen in two virtual monitors to view two tags at once on a big screen.

Each monitor displays exactly one tag on a specified rectangle on the screen.

Each monitor may have a name, which can be set via add_monitor and rename_monitor. It can be unset with the rename_monitor command. A monitor name is an arbitrary non-empty string which must not start with +, - or any digit.

A monitor can be referenced in different ways:

  • by its absolute index as listed in the list_monitors command.
  • by its relative index: a + or - followed by a delta, e.g.: +3.
  • by its relative position to the focused monitor. -l denotes the monitor left of the focused monitor, -r right of, -u above of, and -d below of, respectively.
  • by "" (an empty string) which represents the current monitor.
  • by its name.

๐Ÿ”ฅ COMMANDS ๐Ÿ”ฅ

herbstluftwm is controlled by internal commands, which can be executed via herbstclient(1) or via keybindings. Okay, here's the whole command menu:

  • quit โ€” Quits herbstluftwm.
  • reload โ€” Executes the autostart file.
  • version โ€” Prints the version of the running herbstluftwm instance.
  • echo [ARGS ...] โ€” Prints all given ARGS separated by a single space and a newline afterwards.
  • true โ€” Ignores all arguments and always returns success, i.e. 0.
  • false โ€” Ignores all arguments and always returns failure, i.e. 1.
  • help [OBJECT|ATTRIBUTE] โ€” Print help on a given object or attribute. For example:
    • help clients.focus
    • help monitors
    • help types.color
  • list_commands โ€” Lists all available commands.
  • list_monitors โ€” List currently configured monitors with their index, area (as rectangle), name (if named) and currently viewed tag.
  • list_rules โ€” Lists all active rules. Each line consists of all the parameters the rule was called with, plus its label, separated by tabs.
  • list_keybinds โ€” Lists all bound keys with their associated command. Each line consists of one key combination and the command with its parameters separated by tabs.
Warning: Tabs within command parameters are not escaped!
  • list_clients [--tag=TAG|--monitor=MONITOR] [--frame=FRAME_PATH|--floating|--tiling] [--title] โ€” Lists the window ids of all clients on the given TAG or MONITOR (or the current if unspecified). In addition to that, one can restrict to clients in a specific frame (--frame=) or to tiled or floated clients. The output is one line per client; if --title is given, then in addition to every clientโ€™s window id, its window title is printed in the same line.
  • lock โ€” Increases the monitors_locked setting. Use this if you want to do multiple window actions at once (i.e. without repainting between the single steps). See also: unlock.
  • unlock โ€” Decreases the monitors_locked setting. If monitors_locked is changed to 0, then all monitors are repainted again. See also: lock.
  • keybind KEY COMMAND [ARGS ...] โ€” Adds a key binding. If there is already a binding for this KEY, it will be overwritten. When KEY is pressed, the internal COMMAND (with its ARGS) is executed. A key binding is a (possibly empty) list of modifiers (Mod1, Mod2, Mod3, Mod4, Mod5, Alt, Super, Control/Ctrl, Shift) and one key (see keysymdef.h for a list of keys). Modifiers and the key are concatenated with - or + as separator. If KEY is prefixed with Release- then the keybinding is only active during the corresponding key release event: that is, in order to run the key binding for Release-Mod1-Shift-p one needs to first press Mod1-Shift-p and then release p. Examples:
    • keybind Mod4+Ctrl+q quit
    • keybind Mod4-Shift-d attr clients.focus.decorated toggle
    • keybind Mod1-Shift-space cycle_layout -1
    • keybind Release-Mod4-Shift-p spawn scrot takes a screenshot when the p is released while Mod4 and Shift are still pressed.
  • keyunbind KEY|-F|--all โ€” Removes the key binding for KEY. The syntax for KEY is defined in keybind. If -F or --all is given, then all key bindings will be removed.
  • mousebind BUTTON ACTION [COMMAND ...] โ€” Adds a mouse binding for the floating mode. When BUTTON is pressed, the specified ACTION will be performed. BUTTON has a similar syntax to the KEY argument of keybind: It consists of a list of modifiers (separated by - or +, valid modifiers are listed in the description of keybind) and exactly one button name:
    • B1 or Button1
    • B2 or Button2
    • ...
    • B9 or Button9

ACTION must be one of the following actions:

  • move: Moves the window by dragging the cursor.
  • resize: Resizes the window by dragging a corner.
  • zoom: Resizes the window into all four directions while keeping the center of the window constant.
  • call: Only calls the specified COMMAND while client.dragged links to the client on which the BUTTON has been performed.

While an ACTION is performed, client.dragged is the client which is dragged. E.g.:

  • mousebind Mod1-Button3 zoom
  • mousebind Mod1-B4 call substitute WID clients.dragged.winid spawn transset-df --inc -i WID 0.05
  • mousebind Mod1-B5 call substitute WID clients.dragged.winid spawn transset-df --dec -i WID -m 0.2 0.05
  • drag WINID ACTION โ€” Starts dragging the specified client window WINID with the specified ACTION (see mousebind). E.g. drag '' resize starts resizing the focused window.
  • mouseunbind โ€” Removes all mouse bindings.

spawn EXECUTABLE [ARGS ...]

Okay so this one spawns an EXECUTABLE with its ARGS. For the full deets, see man 3 execvp. Example:

  • spawn xterm -e man 3 execvp

wmexec [WINDOWMANAGER [ARGS ...]]

Executes the WINDOWMANAGER with its ARGS. This is lowkey iconic for switching the window manager in the running session without restarting the session. If no WINDOWMANAGER is given, or itโ€™s invalid, then herbstluftwm is restarted. For details see man 3 execvp. Example:

  • wmexec openbox

chain SEPARATOR [COMMANDS ...]

chain expects a SEPARATOR and a list of COMMANDS with arguments. The commands have to be separated by the specified SEPARATOR. The SEPARATOR can be any word and is only recognized as the separator between commands if it exactly matches SEPARATOR. chain outputs the appended outputs of all commands and returns the exit code of the last executed command. Examples are:

  • Create a tag called "foo" and directly use it:
chain , add foo , use foo
  • Rotate the layout clockwise:
chain .-. lock .-. rotate .-. rotate .-. rotate .-. unlock

Counterexamples are:

  • This will only create a tag called "foo,":
chain , add foo, use foo
  • Separator "." defined, but "," is used:
chain . add foo , use foo

and SEPARATOR [COMMANDS ...]

and behaves like the chain command but only executes the specified COMMANDS while the commands return the exit code 0.

or SEPARATOR [COMMANDS ...]

or behaves like the chain command but only executes the specified COMMANDS until one command returns the exit code 0.

! COMMAND

! executes the provided command, but inverts its return value. If the provided command returns a nonzero, ! returns a 0; if the command returns a zero, ! returns a 1.

try COMMAND

try executes the provided command, prints its output, but always returns success, i.e. 0. no cap, itโ€™s the โ€œplease donโ€™t fail the whole chainโ€ bestie.

silent COMMAND

silent executes the provided command, but discards its output and only returns its exit code.

focus_nth INDEX

Focuses the nth window in a frame. The first window has INDEX 0. If INDEX is negative or greater than the last window index, then the last window is focused.

cycle [DELTA]

Cycles the selection within the current frame by DELTA, or cycles through the clients in the floating layer if that is focused. If DELTA is omitted, DELTA = 1 will be used. DELTA can be negative; DELTA = -1 means: cycle in the opposite direction by 1.

cycle_all [--skip-invisible] [DIRECTION]

Cycles through all non-minimized windows and frames on the current tag. DIRECTION = 1 means forward (default value), DIRECTION = -1 means backward, DIRECTION = 0 has no effect. If there are multiple windows within one frame, then it acts similar to the cycle command. If --skip-invisible is given, then this only cycles through all visible windows and skips invisible windows in the max layout (the flag only affects invisible windows in the max layout; minimized windows are always skipped). After each focus change, the focused window is raised.

cycle_frame [DIRECTION]

Cycles through all frames on the current tag. DIRECTION = 1 means forward, DIRECTION = -1 means backward, DIRECTION = 0 has no effect. DIRECTION defaults to 1.

cycle_layout [DELTA [LAYOUTS ...]]

Cycles the layout algorithm in the current frame by DELTA. DELTA defaults to 1. You can find a list of layout algorithms above. If a list of LAYOUTS is given, cycle_layout will cycle through those instead of the default layout algorithm list. This is done by finding the first occurrence of the current layout in LAYOUTS and picking the next layout according to DELTA. If the current layout doesnโ€™t occur in LAYOUTS, the first entry is picked. Example:

  • cycle_layout -1
  • cycle_layout 1 vertical grid

set_layout LAYOUT

Sets the layout algorithm in the current frame to LAYOUT. For the list of layouts, check the list of layout algorithms above.

close WINID

Closes the specified window gracefully or the focused window if none is given explicitly. See the section on WINDOW IDS for how to reference a certain window.

close_or_remove

Closes the focused window or removes the current frame if no window is focused. In floating mode, this acts as the close command.

close_and_remove

Closes the focused window and removes the current frame if no other window is present in that frame. In floating mode, this acts as the close command.

split ALIGN [FRACTION [FRAMEINDEX]]

Splits the focused frame (or the frame specified by FRAMEINDEX, see the section frame index) into two subframes with a specified FRACTION between 0 and 1 which defaults to 0.5. ALIGN is one of:

  • top
  • bottom (= vertical)
  • left
  • right (= horizontal)
  • explode
  • auto (split along longest side)

It specifies which of the two halves will be empty after the split. The other half will be occupied by the currently focused frame. After splitting, the originally focused frame will stay focused. One special ALIGN mode is explode, which splits the frame in such a way that the window focus, window sizes, and positions are kept as much as possible (so the default FRACTION is not always 0.5, unlike for the other ALIGN modes). Example:

  • split explode
  • split bottom 0.5
  • split horiz 0.3
  • split vertical 0.5
  • split h
  • split top 0.2 '' (splits the root frame)

focus [-i|-e|--level=LEVEL] DIRECTION

Moves the focus from the current frame to the next frame or client in DIRECTION, which is in:

  • l[eft]
  • r[ight]
  • u[p]
  • d[own]

If there is no client within this frame or LEVEL is frame, then the next frame in the specified DIRECTION will be focused. If LEVEL is visible or default_direction_external_only is unset, then the next client in DIRECTION can also be within the same frame, but has to be visible. For tabs LEVEL, the next client may be hidden in a tabbed_max layout. With all, any client within a max layout maybe selected before focusing the next frame. The flag -i is an alias for --level=visible and -e for --level=frame.

The direction between frames is defined as follows: the focus is in a leaf of the binary tree. Each inner node in the tree remembers the last focus direction (child 0 or child 1). The algorithm uses the shortest possible way from the leaf (the currently focused frame) to the root until it is possible to change focus in the specified DIRECTION. From there the focus goes back to the leaf.

Example: the focus is at frame A. After executing focus right, focus will be at frame C.

     Tree:  H,0     Screen: โ”Œโ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ” (before)
            โ•ฑ โ•ฒ             โ”‚  B  โ”‚โ”‚  C  โ”‚
           โ•ฑ   โ•ฒ            โ””โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”˜
         V,1   V,0          โ”Œโ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ”
         โ•ฑ โ•ฒ   โ•ฑ โ•ฒ          โ”‚  A* โ”‚โ”‚  D  โ”‚
        B  A* C   D         โ””โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”˜

     Tree:  H,1     Screen: โ”Œโ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ” (after focus right)
            โ•ฑ โ•ฒ             โ”‚  B  โ”‚โ”‚  C* โ”‚
           โ•ฑ   โ•ฒ            โ””โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”˜
         V,1   V,0          โ”Œโ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ”
         โ•ฑ โ•ฒ   โ•ฑ โ•ฒ          โ”‚  A  โ”‚โ”‚  D  โ”‚
        B   A C*  D         โ””โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”˜

If the currently focused client is floated, then the next floating window in the specified direction is focused and raised.

If focus_crosses_monitor_boundaries is set and no client or frame is found in the specified DIRECTION, then the next monitor in that DIRECTION is focused.

focus_edge [-i|-e] DIRECTION

Focuses the window on the edge of the tag in the specified DIRECTION. The DIRECTIONS and -e behave as specified at the focus command.

If -i (internal) is given or default_direction_external_only is unset, then the window on the edge of the tag will be focused. Else, only the frame on the edge of the tag will be focused, and the window that was last focused in that frame will be focused.

raise WINID

Raises the specified managed or unmanaged window. Managed windows are only moved within the tagโ€™s stack (as reported by the stack command), and unmanaged windows are raised globally, i.e. are raised above all managed windows. See the section on WINDOW IDS on how to reference a certain window. Its result is only visible for floating windows and unmanaged windows.

lower WINID

Lowers the specified managed or unmanaged window, analogously to the raise command: managed windows are lowered within the stack of floating windows (with no effect for tiled windows) and unmanaged windows are moved below all managed windows (for example, it can be used to lower desktop windows).

jumpto WINID

Puts the focus to the specified window. See the section on WINDOW IDS on how to reference a certain window.

bring WINID

Moves the specified window to the current frame and focuses it. Floating windows are brought to the current tag, but keep their floating state. See the section on WINDOW IDS on how to reference a certain window.

resize DIRECTION [FRACTIONDELTA]

Changes the size of the focused frame in the specified DIRECTION by FRACTIONDELTA (which defaults to 0.02 if none is supplied). DIRECTION behaves as specified at the focus command. If a floating window is focused, it grows towards next edge, i.e. either the edge of the next window or the monitor edge in the specified DIRECTION (FRACTIONDELTA is ignored in that case). Example:

  • resize right +0.05
  • resize down -0.1

shift_edge [-i|-e] DIRECTION

Shifts the focused window to the the edge of a tag in the specified DIRECTION. The DIRECTIONS behave as specified at the focus command and -i and -e behave as specified at the focus_edge command.

  • shift [-i|-e|--level=LEVEL] DIRECTION โ€” moves the focused window to the next frame in whatever DIRECTION you picked ๐Ÿ’…. The DIRECTIONS and the -i / -e / --level=LEVEL params work exactly like they do at the focus command (go look at that one, bestie). If the focused client is floated instead of tiled, then the client gets shifted to the next window or to the screen edge instead ๐Ÿฆ‹. And if the window can't be moved and the setting focus_crosses_monitor_boundaries is activated, then the window gets moved to the monitor in the specified DIRECTION. slay.
  • shift_to_monitor MONITOR โ€” moves the focused window to the tag on the specified MONITOR. Wanna know how to address a monitor? Peek at the MONITORS section ๐Ÿ‘‘
  • remove โ€” removes the focused frame and merges its windows into its closest neighbour frame ๐ŸŽ€
  • rotate โ€” rotates the layout on the focused tag counterclockwise by 90 degrees. Heads up though: this only messes with the alignment of frames, NOT the content of them ๐Ÿ”ฅ
  • mirror [vertical|horizontal|both] โ€” mirrors the layout on the focused tag vertically, horizontally, or both; the default is horizontal. Same deal: this only manipulates the alignment of frames, not the content of them โœจ
  • set NAME VALUE โ€” sets the specified setting NAME to VALUE. For boolean settings the allowed values are on or true for on, off or false for off, and toggle to toggle its value ๐Ÿ”. Every setting is listed in the section below, iykyk.
  • get NAME โ€” prints the value of setting NAME. All settings are listed in the section below ๐Ÿ’–
  • toggle NAME โ€” toggles the setting NAME if it's a boolean setting ๐Ÿซถ
  • cycle_value PATH VALUES ... โ€” cycles the value of the attribute PATH through VALUES. Like: it searches for the first occurrence of the current value in VALUES and changes the value to the next one in the list, or to the first one if the end is reached or if the current value wasn't found at all ๐ŸŒˆ. For compatibility reasons, PATH can also be the name of a setting. Examples, bestie:
    • cycle_value settings.frame_gap 0 5 10 15
    • cycle_value theme.active.inner_color red green blue
    • the command cycle_layout +1 is equivalent to cycle_value tags.focus.tiling.focused_frame.algorithm
  • cycle_monitor [DELTA] โ€” cycles the focused monitor by DELTA. DELTA defaults to 1 ๐Ÿ’ซ
  • focus_monitor MONITOR โ€” puts focus on the specified monitor. See the MONITORS section for how to address a monitor ๐Ÿ‘‘
  • add TAG โ€” creates a new empty tag named TAG ๐ŸŽ€
  • use TAG โ€” switches the focused monitor to the specified TAG โœจ
  • use_index INDEX [--skip-visible] โ€” switches the focused monitor to the TAG with the specified INDEX. If INDEX starts with + or -, then INDEX is treated relative to the current TAG. And if --skip-visible is passed and INDEX is relative, then tags that are already visible on a monitor get skipped ๐Ÿฆ‹. E.g. this cycles backwards through the tags:
    • use_index -1 --skip-visible
  • use_previous โ€” switches the focused monitor to the previously viewed tag ๐Ÿ”™
  • merge_tag TAG [TARGET] โ€” removes the tag named TAG and moves all its windows to tag TARGET. If TARGET is omitted, the focused tag gets used ๐Ÿ’…
  • rename OLDTAG NEWTAG โ€” renames the tag named OLDTAG to NEWTAG โœ๏ธ
  • move TAG โ€” moves the focused window to the tag named TAG ๐Ÿšš
  • move_index INDEX [--skip-visible] โ€” moves the focused window to the tag specified by INDEX. Analogical to the argument for use_index: if INDEX starts with + or -, then it's treated as relative. And if --skip-visible is passed along with a relative index, then already-visible tags get skipped ๐Ÿ‘€
  • lock_tag [MONITOR] โ€” locks the tag switching on the specified monitor. If no argument is given, the currently focused monitor is used ๐Ÿ”’. When tag switching is disabled for a monitor, the commands use and use_index have no effect when executed there โ€” fr fr, nothing happens. When swap_monitors_to_get_tag is enabled, switching to a tag that's located on a locked monitor switches to that monitor instead of stealing the tag from there ๐Ÿ™ˆ. The lock state of a monitor is shown by [LOCKED] in the list_monitors output ๐Ÿ’€
  • unlock_tag [MONITOR] โ€” re-enables tag switching on the specified monitor. If no argument is given, the currently focused monitor is used ๐Ÿ”“. This is the reverse operation to lock_tag and has no further side effects besides removing the lock โœจ
  • disjoin_rects RECTS ... โ€” takes a list of rectangles and splits them into smaller pieces until all rectangles are disjoint; the resulting rectangles get printed line by line ๐Ÿ“. Heads up: this command does not modify the current list of monitors! So it's lowkey useful in combination with the set_monitors command ๐Ÿซถ
    • E.g. disjoin_rects 600x400+0+0 600x400+300+250 prints this:
300x150+300+250
600x250+0+0
300x150+0+250
300x150+600+250
600x250+300+400
  • In the example above, two monitors get split into 5 monitors, which graphically means:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      โ”‚                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚  โ”Œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”              โ”Œโ”€โ”โ”Œโ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”
โ”‚  โ”‚   โ”‚   โ”‚   disjoin    โ”‚ โ”‚โ”‚   โ”‚โ”‚  โ”‚
โ””โ”€โ”€โ”ผโ”€โ”€โ”€โ”˜   โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>  โ””โ”€โ”˜โ””โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”˜
   โ”‚       โ”‚                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  • set_monitors RECTS ... โ€” sets the list of monitors exactly to the list of given rectangles, like this ๐ŸŒธ:
    • The i'th existing monitor gets moved to the i'th given RECT
    • New monitors get created if there are more RECTS than monitors
    • Existing monitors get deleted if there are more monitors than RECTS
  • detect_monitors -l|--list|--list-all|--no-disjoin โ€” sets the list of monitors to the physically available monitors ๐Ÿ–ฅ๏ธ. If both Xinerama and xrandr are missing, it falls back to one monitor across the entire screen. If the detected monitors overlap, they get split into more monitors that are disjoint but cover the same area, using disjoin_rects โœจ

If -l or --list is passed, the list of rectangles of detected physical monitors gets printed. So hc detect_monitors is equivalent to the bash command hc set_monitors $(hc disjoin_rects $(hc detect_monitors -l)) ๐Ÿ’ซ

If --list-all is passed, then it prints which multimonitor detection (xinerama, xrandr) has which set of physical monitors ๐Ÿ‘‘

  • add_monitor RECT [TAG [NAME]] โ€” adds a monitor on the specified rectangle RECT and displays TAG on it ๐ŸŽ€. TAG currently must not be displayed on any other monitor โ€” that's a real rule, bestie. RECT is a string of the form WxHยฑXยฑY. If no or an empty TAG is given, then any free/empty tag gets chosen, depending on the monitors.tag_selection_strategy attribute. And if a NAME is given, you can reference this monitor by its name instead of using an index ๐Ÿ”ฅ. Example:
    • add_monitor 1024x768-20+0 mynewtag main
  • remove_monitor MONITOR โ€” removes the specified monitor ๐Ÿ—‘๏ธ
  • move_monitor MONITOR RECT [PADUP [PADRIGHT [PADDOWN [PADLEFT]]]] โ€” moves the specified monitor to rectangle RECT. RECT is defined as in add_monitor. If no pad or an empty pad is given, it's not changed ๐Ÿฆ‹
  • raise_monitor [MONITOR] โ€” raises the specified monitor, or the current one if MONITOR is omitted โฌ†๏ธ
  • rename_monitor MONITOR NAME โ€” (re)names an already existing monitor. If NAME is empty, it removes the monitor's name โœ๏ธ
  • stack โ€” prints the stack of monitors with the visible tags and their layers as a tree ๐ŸŒณ. The order of the printed stack is top to bottom. The style is configured by the tree_style setting ๐ŸŽจ
  • monitor_rect [[-p] MONITOR] โ€” prints the rectangle of the specified monitor in the format: X Y W H ๐Ÿ“. If no MONITOR or cur is given, then the current monitor is used. If -p is supplied, then the remaining rect without the pad around this monitor gets printed ๐Ÿ’…
  • pad MONITOR [PADUP [PADRIGHT [PADDOWN [PADLEFT]]]] โ€” sets the pad of the specified monitor to the specified padding. If no padding or an empty padding is given, it's not changed ๐ŸŽ€
  • list_padding [MONITOR] โ€” lists the padding of the specified monitor, or of the currently focused monitor if no monitor is given ๐Ÿ‘€
  • layout [TAG [INDEX]] โ€” prints the layout of the frame with INDEX on TAG, in a nice tree style ๐ŸŒณ. Its style is defined by the tree_style setting. If no TAG is given, the current tag is used. If no INDEX is given, the root frame is used. To specify INDEX without specifying TAG (i.e. use the current tag), pass an empty string as TAG ๐Ÿซถ

An example output is:

โ•พโ”€โ” horizontal 50% selection=1
  โ”œโ”€โ•ผ vertical: 0xe00009
  โ””โ”€โ” vertical 50% selection=0
    โ”œโ”€โ•ผ vertical: 0xa00009 [FOCUS]
    โ””โ”€โ•ผ vertical: 0x1000009
  • dump [TAG [INDEX]] โ€” prints the same information as the layout command but in a machine readable format ๐Ÿค–. Its output can be read back with the load command ๐Ÿ”

An example output (formatted afterwards) is:

(split horizontal:0.500000:1
    (clients vertical:0 0xe00009)
    (split vertical:0.500000:1
        (clients vertical:0 0xa00009)
        (clients vertical:0 0x1000009)))
  • load [TAG] LAYOUT โ€” loads a given LAYOUT description into the specified TAG, or the current tag if no TAG is given ๐Ÿ“ฅ
Caution โš ๏ธ โ€” LAYOUT is exactly one parameter. If you're calling it manually from your shell or from a script, QUOTE IT PROPERLY! No cap, this will bite you ๐Ÿ˜ญ
  • complete POSITION [COMMAND ARGS ...] โ€” prints the result of tab completion for the partial COMMAND with optional ARGS โœจ. You usually don't need this, because there's already tab completion for bash, zsh and fish ๐ŸŸ. Example:
    • complete 0 m

prints all commands beginning with m ๐Ÿ’…

  • complete 1 toggle fra

prints all settings beginning with fra that can be toggled ๐ŸŽ€

  • complete_shell POSITION [COMMAND ARGS ...] โ€” behaves like complete with the following extras, which are useful for completion on posix shells ๐Ÿš:
    • Escape sequences get removed in COMMAND and ARGS ๐Ÿงš
    • A space gets appended to each full completion result โฃ
    • Special characters get escaped in the output ๐Ÿ”
  • emit_hook NAME ARGS ... โ€” emits a custom hook NAME to all idling herbstclients ๐Ÿ“ข
  • tag_status [MONITOR] โ€” prints a tab-separated list of every tag on the monitor with index MONITOR. No MONITOR index? Then it uses the focused monitor, obvs. Each tag name gets a single char slapped on the front to tell you its whole vibe:
    • . โ€” the tag is empty
    • : โ€” the tag is not empty
    • + โ€” the tag is viewed on the specified MONITOR, but this monitor is not focused
    • # โ€” the tag is viewed on the specified MONITOR and it is focused
    • - โ€” the tag is viewed on a different MONITOR, but this monitor is not focused
    • % โ€” the tag is viewed on a different MONITOR and it is focused
    • ! โ€” the tag contains an urgent window
โš ๏ธ Warning: if you put a tab in one of your tag names, tag_status is probably gonna be straight-up useless for you. Like, bestie, why. ๐Ÿ˜ญ
  • floating [[TAG] on|off|toggle|status] โ€” flips the specified TAG into floating or tiling mode, or just prints its current status if you're nosy. No TAG given? It uses the current tag. No argument at all? Floating mode gets toggled. And if you pass status, it prints on or off depending on the floating state of TAG. โœจ
  • rule [[--]FLAG|[--]LABEL|[--]CONDITION|[--]CONSEQUENCE ...] โ€” defines a rule that gets applied to every new client that shows up. The whole behaviour thing is described in the RULES section, go peek there.
  • unrule LABEL|--all|-F โ€” removes all rules named LABEL. If you pass --all or -F, then literally every rule gets removed. bye y'all ๐Ÿ‘‹
  • apply_rules WINID|--all โ€” applies the rules to the window WINID. Pass --all and the rules get applied to all clients.
  • apply_tmp_rule WINID|--all [RULEDESCRIPTION...] โ€” applies the rule RULEDESCRIPTION to one particular client WINID, or to all clients if you pass --all, without adding the rule to the rule list. The RULEDESCRIPTION is a rule made of conditions and consequences, exactly like you'd pass to the rule command as described in the RULES section. This is your little test kitchen, so you can try rules before committing to them. Running apply_tmp_rule only applies the particular rule given in the arguments and ignores the existing rules. ๐Ÿงช
  • fullscreen [on|off|toggle] โ€” sets or toggles the fullscreen state of the focused client. No argument? Fullscreen mode gets toggled.
  • pseudotile [on|off|toggle] โ€” sets or toggles the pseudotile state of the focused client. So like, if a client is pseudotiled, then in tiling mode the client is only moved but not resized โ€” the client size stays the floating size. The only reason to resize the client is to make sure it fits into its tile. No argument given? Pseudotile mode gets toggled. ๐Ÿฆ‹
  • object_tree [PATH] โ€” prints the tree of objects. If you give it the object path PATH, only the subtree starting at PATH gets printed. See the OBJECTS section for more, iykyk.
  • attr [PATH [NEWVALUE] โ€” prints the children and attributes of the given object addressed by PATH. If PATH is an attribute, then it prints the attribute value. And if NEWVALUE is given, it assigns NEWVALUE to the attribute given by PATH. See the OBJECTS section for the details. ๐Ÿ’…
  • get_attr ATTRIBUTE โ€” prints the value of the specified ATTRIBUTE, as described in the OBJECTS section.
  • set_attr ATTRIBUTE NEWVALUE โ€” assigns NEWVALUE to the specified ATTRIBUTE, as described in the OBJECTS section.
  • attr_type ATTRIBUTE โ€” prints the type of the specified ATTRIBUTE.
  • new_attr bool|color|int|string|uint PATH [VALUE] โ€” creates a new attribute with the name and in the object specified by PATH. Its type is whatever the first argument says. Heads up: the attribute name has to begin with my_. If VALUE is supplied, then it gets written to the attribute (and if that fails, the attribute still remains). ๐ŸŒธ
  • watch PATH โ€” watches the value of the given attribute PATH. Whenever the value changes from OLDVALUE to NEWVALUE, a hook gets emitted:
attribute_changed PATH OLDVALUE NEWVALUE
  • remove_attr PATH โ€” removes the user-defined attribute PATH.
  • substitute IDENTIFIER ATTRIBUTE COMMAND [ARGS ...] โ€” replaces all exact occurrences of IDENTIFIER in COMMAND and its ARGS with the value of the ATTRIBUTE. Note that the COMMAND also gets replaced by the attribute value if it equals IDENTIFIER. The replaced command with its arguments then gets executed. Example:
    • substitute MYTITLE clients.focus.title echo MYTITLE โ€” prints the title of the currently focused window. ๐ŸŽ€
  • sprintf IDENTIFIER FORMAT [FORMATARG ...] COMMAND [CMDARGS ...] โ€” replaces all exact occurrences of IDENTIFIER in COMMAND and its CMDARGS with the string specified by FORMAT. The FORMAT string may contain several placeholders, similar to the printf(1) command:
    • %s inserts an attribute value whose path is given by the string value of the next FORMATARG
    • %c ("constant") inserts the next FORMATARG without modification
    • %{ATTR} inserts the current value of the attribute ATTR. The path ATTR can itself contain format placeholders. This is lowkey iconic because you can compose attribute paths at run time, e.g. in a foreach loop.
    • %% stands for a plain %

The replaced command with its arguments then gets executed. Examples:

  • sprintf STR title=%s clients.focus.title echo STR โ€” prints the title of the currently focused window prepended by title=.
  • sprintf X "%c %s tags" "there are" tags.count echo X โ€” prints there are N tags with N replaced by the number of tags.
  • sprintf X tag=%s tags.focus.name rule once X โ€” moves the next client that appears to the tag that is currently focused.
  • sprintf X %s/%s tags.focus.index tags.count echo X โ€” tells which tag is focused and how many tags there are.
  • sprintf l somelongstring echo l l l โ€” prints somelongstring three times, separated by spaces.
  • sprintf VALUE "%{%c.client_count}" tags.0 echo VALUE โ€” prints the number of clients on the tag with index 0.
  • foreach --filter-name="[0-9]*" T tags. sprintf S "%{%c.client_count}" T echo T S โ€” prints the number of clients for each tag.
  • substitute X tags.count sprintf Y "number=%c" X echo Y โ€” has the same output as sprintf Y "number=%s" tags.count echo Y (note how the %c changes to %s). ๐Ÿคฏ
  • foreach IDENTIFIER OBJECT [--recursive] [--unique] [--filter-name=REGEX] COMMAND [ARGS ...] โ€” for each child of the given OBJECT, the COMMAND gets called with its ARGS, where the IDENTIFIER is replaced by the path of the child. The options are:
    • --filter-name=REGEX โ€” consider children whose name match the specified REGEX
    • --unique โ€” do not print duplicates (some objects can be reached via multiple paths, such as clients.focus)
    • --recursive โ€” print OBJECT and all its children of arbitrary depth in breadth-first search order. This implicitly activates --unique.

The exit code is the exit code of the command executed last. Examples:

  • foreach T tags.by-name. echo T โ€” prints:
tags.by-name.1
tags.by-name.2
tags.by-name.3
[...]
  • Note that foreach only iterates over children, but not over attributes, so foreach S settings echo S prints nothing, since the settings object has only attributes but no child objects.
  • foreach C clients. echo C prints the object paths of all clients, but the focused client twice, because it's mentioned in clients. twice: by window id and as clients.focus.
  • foreach F tags.focus.tiling.root. --recursive echo F prints the object paths of all frames on the focused tag.
  • mktemp [bool|int|string|uint] IDENTIFIER COMMAND [ARGS ...] โ€” creates a temporary attribute with the given type and replaces all occurrences of IDENTIFIER in COMMAND and ARGS by the path of the temporary attribute. The replaced command with its arguments then gets executed. The exit status of COMMAND is returned. ๐Ÿ”ฅ
  • compare ATTRIBUTE OPERATOR VALUE โ€” compares the value of ATTRIBUTE with VALUE using the comparison method OPERATOR. If the comparison succeeds, it returns 0, else 1. The operators are:
    • =: ATTRIBUTE's value equals VALUE
    • !=: ATTRIBUTE's value does not equal VALUE
    • le: ATTRIBUTE's value <= VALUE
    • lt: ATTRIBUTE's value < VALUE
    • ge: ATTRIBUTE's value >= VALUE
    • gt: ATTRIBUTE's value > VALUE

The OPERATORs le,lt,ge,gt can only be used if ATTRIBUTE is of the type integer or unsigned integer. Note that the first parameter must always be an attribute and the second a constant value. If you wanna compare two attributes, use the substitute command:

substitute FC tags.focus.frame_count \
    compare tags.focus.client_count gt FC

It returns success if there are more clients on the focused tag than frames. ๐Ÿ’€

  • getenv NAME โ€” gets the value of the environment variable NAME.
  • setenv NAME VALUE โ€” sets the value of the environment variable NAME to VALUE. See the export command for a convenience wrapper.
  • unsetenv NAME โ€” unsets the environment variable NAME.
  • export NAME=VALUE โ€” sets the value of the environment variable NAME to VALUE. The syntax is the same as for export in unix shells (notice there's a = in there). Intuitively: if you forgot to run export FOO=BAR before starting herbstluftwm, you can run herbstclient export FOO=BAR from within your herbstluftwm session for the same effect. The export command is the same as the setenv command with different syntax. ๐Ÿซถ
  • debug_css [FLAGS] โ€” ok so this command exists solely for testing herbstluftwm; it has no use in normal hlwm sessions. Moreover, the interface of this command may change in incompatible ways. Consider yourself warned ๐Ÿ™ˆ. The command performs various operations, specified by the optional FLAGS:
    • --stylesheet=CSS โ€” specify some stylesheet that is possibly used in one of the other commands
    • --print-css โ€” print the stylesheet in some normalized form
    • --tree=TREE โ€” a dom-style tree specification, where the syntax of a tree starts with ( and ends with ). In between, the tree contains a space-separated list of class names and subtrees.
    • --print-tree โ€” print the tree specification of TREE again
    • --pretty-client-tree=CLIENT โ€” for the given CLIENT, print the tree of its widgets together with the classes each widget has. Each class is preceeded with a dot . in the same way as in a css selector. ๐ŸŽจ
  • --query-tree-indices=SELECTOR โ€” prints the tree indices (analogously to frame indices) of those nodes that match the given css-style SELECTOR. ๐Ÿ’…
  • --compute-style=INDEX โ€” computes the box style of the node in above TREE that has the tree index INDEX. โœจ

๐ŸŽ€ RULES ๐ŸŽ€

Okay bestie, rules are how you change default properties for certain clients when they appear โ€” or when the apply_rules command is called. Each rule matches against a certain subset of all clients and defines a set of properties for them (called CONSEQUENCEs). You define a rule with this:

rule [[--]FLAG|[--]LABEL|[--]CONDITION|[--]CONSEQUENCE ...]

Each rule is a list of FLAGs, CONDITIONs, CONSEQUENCEs and, optionally, a LABEL. (Each of them can be optionally prefixed with two dashes (--) to provide a more iptables(8)-like feeling, iykyk.)

Each rule can get a custom label by specifying the LABEL property:

  • [--]label=VALUE

If multiple labels are specified, the last one in the list will be applied. If no label is given, then the rule gets an integer name that represents the index of the rule since the last unrule -F command (which is triggered in the default autostart).

Tip ๐Ÿ’– Rule labels default to an incremental index. These default labels are unique, unless you assign a different rule a custom integer LABEL. Default labels can be captured with the printlabel flag.

When a new client appears, herbstluftwm tries to apply each rule to this new client like this: if each CONDITION of the rule matches against the client, then every CONSEQUENCE is executed. (If there are no conditions given, then this rule is executed for each client.) ๐Ÿ‘‘

Each CONDITION is a property name, an operator and a value. The valid operators are:

  • ~ โ€” matches if clientโ€™s property is matched by the regex value.
  • = โ€” matches if clientโ€™s property string is equal to value.

Valid properties are:

  • instance โ€” the first entry in clientโ€™s WM_CLASS.
  • class โ€” the second entry in clientโ€™s WM_CLASS.
  • title โ€” clientโ€™s window title.
  • pid โ€” the clientโ€™s process id. Warning: the pid is not available for every client. This only matches if the client sets _NET_WM_PID to the pid itself.
  • pgid โ€” this clientโ€™s process group id. Since the pgid of a window is derived from its pid, the same restrictions apply as above.
  • maxage โ€” matches if the age of the rule measured in seconds does not exceed value. This condition only can be used with the = operator. If maxage already is exceeded (and never will match again), then this rule is removed. (With this you can build rules that only live for a certain time.) โณ
  • windowtype โ€” matches the _NET_WM_WINDOW_TYPE property of a window. If _NET_WM_WINDOW_TYPE has multiple entries, then only the first entry is used here.
  • windowrole โ€” matches the WM_WINDOW_ROLE property of a window if it is set by the window.
  • fixedsize (no parameter) โ€” matches if the window does not allow being resized (i.e. if the minimum size matches the maximum size). This condition does not take a parameter. Example:
hc rule fixedsize floating=on

Each CONSEQUENCE is a NAME=VALUE pair. Valid NAMEs are:

  • tag โ€” moves the client to tag VALUE.
  • monitor โ€” moves the client to the tag on monitor VALUE. If the tag consequence was also specified, and switchtag is set for the client, move the client to that tag, then display that tag on monitor VALUE. If the tag consequence was specified, but switchtag was not, ignore this consequence.
  • focus โ€” decides whether the client gets the input focus in its tag. The default is off. VALUE is a boolean (on or off).
  • switchtag โ€” if focus is activated and the client is put to a not focused tag, then switchtag tells whether the clientโ€™s tag will be shown or not. If the tag is shown on any monitor but is not focused, the clientโ€™s tag only is brought to the current monitor if swap_monitors_to_get_tag is activated. VALUE is a boolean (on or off).
  • manage โ€” decides whether the client will be managed or not. The default is on. VALUE is a boolean (on or off).
  • index โ€” moves the window to a specified index in the tree. VALUE is a frame index.
  • floating โ€” sets the floating state of the client. VALUE is a boolean.
  • pseudotile โ€” sets the pseudotile state of the client. VALUE is a boolean.
  • sticky โ€” sets the sticky attribute of the client. VALUE is a boolean.
  • ewmhrequests โ€” sets whether the window state (the fullscreen state and the demands attention flag) can be changed by the application via ewmh itself. This does not affect the initial fullscreen state requested by the window. VALUE is a boolean; it defaults to on.
  • ewmhnotify โ€” sets whether hlwm should let the client know about EMWH changes (currently only the fullscreen state). If this is set, applications do not change to their fullscreen-mode while still being fullscreen. VALUE is a boolean, it defaults to on.
  • fullscreen โ€” sets the fullscreen flag of the client. VALUE is a boolean.
  • hook โ€” emits the custom hook rule VALUE WINID when this rule is triggered by a new window with the id WINID. This consequence can be used multiple times, which will cause a hook to be emitted for each occurrence of a hook consequence.
  • keymask โ€” sets the keymask for a client (see the keymask attribute documentation).
  • keys_inactive โ€” sets a regex that determines which key bindings are inactive for a client (see the keys_inactive attribute documentation).
  • floatplacement โ€” changes the floating position of a window. The VALUE can be one of the following:
    • none does not change the placement at all.
    • center centers the window on the monitor.
    • smart tries to place it with as little overlap to other floating windows as possible. If there are multiple options with the least overlap, then the position with the least overlap to tiling windows is chosen.
    • topleft, topright, bottomleft, bottomright moves the window to the respective corner of the monitor but leaves a gap of settings.snap_gap pixels.
  • floating_geometry โ€” sets the clientโ€™s floating_geometry attribute. The VALUE is a rectangle, interpreted relatively to the monitor. If floatplacement is also specified for the client (possibly by another rule), then only the size of the floating_geometry is used. In order to force the position from the geometry, it is necessary to add floatplacement=none.

A ruleโ€™s behaviour can be configured by some special FLAGs:

  • not โ€” negates the next CONDITION.
  • ! โ€” same as not.
  • once โ€” only apply this rule once (and delete it afterwards).
  • printlabel โ€” prints the label of the newly created rule to stdout.
  • prepend โ€” prepend the rule to the list of rules instead of appending it. So its consequences may be overwritten by already existing rules.

Examples, bestie โ€” these are iconic:

  • rule --class=Netscape --tag=6 --focus=off
rule --class=Netscape --tag=6 --focus=off

Moves all Netscape instances to tag 6, but doesnโ€™t give focus to them. ๐Ÿ’…

  • rule not class~.*[Tt]erm tag=2
rule not class~.*[Tt]erm tag=2

Moves all clients to tag 2, if their class does not end with term or Term.

  • rule class=Thunderbird index=/0
rule class=Thunderbird index=/0

Inserts all Thunderbird instances in the tree that has no focus and there in the first child.

  • rule --windowtype=_NET_WM_WINDOW_TYPE_DIALOG --focus=on
rule --windowtype=_NET_WM_WINDOW_TYPE_DIALOG --focus=on

Sets focus to new dialogs which set their _NET_WM_WINDOW_TYPE correctly. ๐ŸชŸโœจ

๐Ÿฆ‹ WINDOW IDS ๐Ÿฆ‹

Several commands accept a window as reference, e.g. close. The syntax is as follows:

  • an empty string โ€” or missing argument โ€” references the currently focused window.
  • urgent references some window that is urgent.
  • 0xHEXID โ€” where HEXID is some hexadecimal number โ€” references the window with hexadecimal X11 window id HEXID.
  • longest-minimized references the minimized window on the focused tag that has been minimized for the longest time.
  • last-minimized references the minimized window on the focused tag that has been minimized most recently.
  • DECID โ€” where DECID is some decimal number โ€” references the window with the decimal X11 window id DECID.

๐ŸŒˆ OBJECTS ๐ŸŒˆ

The object tree is a collection of objects with attributes similar to /sys known from the Linux kernel. Many entities (like tags, monitors, clients, ...) have objects to access their attributes directly. The tree is printed by the object_tree command and looks more or less as follows:

$ herbstclient object_tree
โ•พโ”€โ”
  โ”œโ”€โ” tags
  โ”‚ โ”œโ”€โ” by-name
  โ”‚ โ”‚ โ”œโ”€โ•ผ 1
  โ”‚ โ”‚ ...
  โ”‚ โ”‚ โ””โ”€โ•ผ 9
  โ”‚ โ””โ”€โ•ผ focus
  โ”œโ”€โ” clients
  โ”‚ โ”œโ”€โ•ผ 0x1400022
  โ”‚ โ””โ”€โ•ผ focus
  โ””โ”€โ” monitors
    โ”œโ”€โ•ผ by-name
    โ””โ”€โ•ผ focus

To print a subtree starting at a certain object, pass the PATH of the object to object_tree. The object PATH is the path using the separator . (dot), e.g. tags.by-name:

$ herbstclient object_tree tags.by-name.
โ•พโ”€โ” tags.by-name.
  โ”œโ”€โ•ผ 1
  โ”œโ”€โ•ผ 2
  ...
  โ””โ”€โ•ผ 9

To query all attributes and children of an object, pass its PATH to attr:

$ herbstclient attr tags.
2 children:
  by-name.
  focus.

1 attributes:
 .---- type
 | .-- writable
 V V
 u - count                = 9
$ herbstclient attr tags.focus.
0 children.
6 attributes:
 .---- type
 | .-- writable
 V V
 s w name                 = "1"
 b w floating             = false
 i - frame_count          = 2
 i - client_count         = 1
 i - curframe_windex      = 0
 i - curframe_wcount      = 1

This already gives an intuition of the output: attr first lists the names of the child objects and then all attributes, telling for each attribute:

  • its type
    • b for boolean
    • c for color
    • i for integer
    • r for regex
    • s for string
    • u for unsigned integer
  • if it is writable by the user: w if yes, - else.
  • the name of the attribute
  • its current value (only quoted for strings)

okay so to actually read one of these attribute things without the quotes being all extra about it, you address the attribute using the exact same syntax as you'd use for object paths, and then you pass it to attr or get_attr:

$ herbstclient attr clients.focus.title
herbstluftwm.txt = (~/dev/c/herbstluftwm/doc) - VIM
$ herbstclient get_attr  clients.focus.title
herbstluftwm.txt = (~/dev/c/herbstluftwm/doc) - VIM

And when you wanna change a writable attribute value? You just pass the new value to attr or to set_attr, bestie:

$ herbstclient attr tags.focus.floating
false
$ herbstclient attr tags.focus.floating true
$ herbstclient attr tags.focus.floating
true
$ herbstclient set_attr tags.focus.floating false
$ herbstclient attr tags.focus.floating
false

If you want the โœจloreโœจ on an attribute or an object, the help command is right there:

$ herbstclient help clients.focus

Literally just poke around and get a feel for what's in there ๐Ÿซถ. The entry point is a root object that has the following child objects:


๐ŸŒธ autostart

  • string global_path = globalAutostart โ€” the path of the system-wide autostart, which gets used as a fallback.
  • int last_status = 0 โ€” the exit status of the last autostart run. ngl if the autostart is still running, then this status is the exit status of the previous autostart invocation.
  • string path = autostartFromCmdLine โ€” a custom path to the user's autostart path. If it's empty, then the autostart in $XDG_CONFIG_HOME or $HOME is used.
  • uint pid = 0 โ€” the process id of the last autostart invocation. Even if the autostart isn't running anymore, its pid is still sitting here.
  • bool running = false โ€” whether the autostart process (with pid) is still running.

๐Ÿฆ‹ clients

The managed windows, periodt. For every (managed) window id there's an entry here.

  • dragged โ€” the object of a client which is currently being dragged by the mouse, if any. See the documentation of the mousebind command for examples. For attributes and children, see clients.focus.
  • focus โ€” the focused client (only exists if a client is focused). a managed window
    • string class โ€” the class of it (second entry in WM_CLASS)
    • Rectangle content_geometry โ€” the geometry of the application content, i.e. not taking the decoration into account. Also, this is the last window geometry that was reported to the client application.
    • bool decorated = true โ€” whether window border and title are drawn
    • Rectangle decoration_geometry โ€” the geometry of the client, taking the window decoration into account. The position is the global window position, that is, relative to the top left corner of the entire screen
    • bool ewmhnotify = true โ€” if the client is told about its state via ewmh
    • bool ewmhrequests = true โ€” if ewmh requests are permitted for this client
    • bool floating = false โ€” whether this client is set as a (single-window) floating client. If set, the client is floated above the tiled clients.
    • bool floating_effectively = false โ€” whether this client is in the floating state currently. This is the case if the client's tag is set to floating mode or if the client itself is set as floating. Its value is also indicated via the X11 properties HLWM_FLOATING_WINDOW and HLWM_TILING_WINDOW.
    • Rectangle floating_geometry = 0 โ€” the geometry of the client content if the client is in floating mode. The position is relative to the monitor and does not take the window decoration into account.
    • bool fullscreen = false โ€” whether this client covers all other windows and panels on its monitor.
    • string instance โ€” the instance of it (first entry in WM_CLASS)
    • regex keymask = "" โ€” a regular expression that is matched against the string representation of all key bindings (as they are printed by list_keybinds). While this client is focused, only bindings that match the expression will be active. Any other bindings will be disabled. The default keymask is an empty string (""), which does not disable any keybinding.
    • regex keys_inactive = "" โ€” a regular expression that describes which keybindings are inactive while the client is focused. If a key combination is pressed and its string representation (as given by list_keybinds) matches the regex, then the key press is propagated to the client.
    • bool minimized = false โ€” whether this client is minimized (also called iconified).
    • int pgid = -1
    • int pid = -1 โ€” the process id of it (-1 if unset).
    • bool pseudotile = false โ€” if activated, the client always has its floating window size, even if it is in tiling mode.
    • bool sizehints_floating = true โ€” if sizehints for this client should be respected in floating mode
    • bool sizehints_tiling = false โ€” if sizehints for this client should be respected in tiling mode
    • bool sticky = false โ€” whether this client is pinned to the monitor. This means that the client stays on its monitor, even when the monitor switches to another tag.
    • string tag โ€” the name of the tag it's currently on.
    • string title = "" โ€” its window title
    • bool urgent = false โ€” the urgency state (also known as: demands attention). The focused client can not be urgent.
    • bool visible = visible_already โ€” whether this client is rendered currently
    • string winid = "" โ€” its window id (as a hexadecimal number with 0x prefix)
    • parent_frame โ€” the frame containing this client if the client is tiled. For attributes and children, see tags.focus.tiling.root

๐Ÿงš monitors

Every monitor is a rectangular part of the screen on which a tag is shown, bestie. These monitors may or may not match the actual outputs. This has an entry INDEX for each monitor with index INDEX.

  • uint count
  • TagSelectionStrategy tag_selection_strategy = any_unshown โ€” how to select a tag when a new monitor is created.
    • any_unshown: select the first tag that is not shown on any monitor
    • only_empty: select the first empty tag that isn't shown, abort if none is available
    • prefer_empty: prefer an empty tag, but select any unshown tag if no empty tag is available
  • by-name โ€” this has an entry name for every object with the given name. If an object has an empty name then it is not listed here.
  • focus โ€” the focused monitor. The monitor is a rectangular part on the screen that holds precisely one tag at a time. The pad attributes reserve space on the monitor's edge for panels, so this space (given in number of pixels) is never occupied by tiled clients.
    • Rectangle content_geometry โ€” the inner geometry of the monitor, i.e. the geometry with the pads deducted from all sides. This is the area floating and tiled client windows are placed.
    • Rectangle geometry = rect_ โ€” the outer geometry of the monitor
    • uint index = 0 โ€” the monitor's index (starts at index 0)
    • bool lock_tag = false โ€” if activated, then it it is not possible to switch this monitor to a different tag.
    • string name = "" โ€” the monitor's name (can be empty)
    • int pad_down = 0 โ€” space for panels at the monitor's lower edge
    • int pad_left = 0 โ€” space for panels at the monitor's left edge
    • int pad_right = 0 โ€” space for panels at the monitor's right edge
    • int pad_up = 0 โ€” space for panels at the monitor's upper edge
    • string tag โ€” the name of the tag viewed here

๐Ÿ’… panels

For every panel window, there's an entry with the panel's window id here.

  • uint count
  • bool geometry_fallback = false โ€” when auto-detecting panels: if a panel does not specify the amount of space it needs at the monitor edge, fall back to reserve the panel's geometry at the screen edge.
  • 0xWindowID โ€” a panel is an unmanaged window that reserves space at the edge of the monitor it is on. The space depends on the _NET_WM_STRUT defined by the panel. If it is however not defined explicitly, then the amount of reserved space is inferred from the window geometry.
    • string class โ€” the window class (second entry of WM_CLASS)
    • Rectangle geometry โ€” the size and position of the window
    • string instance โ€” the window instance (first entry of WM_CLASS)
    • WindowID winid = winid โ€” the ID of the panel window

๐Ÿ‘‘ settings

Settings configure the general behaviour of herbstluftwm and can be controlled via the set, get and toggle commands. The settings. object has an attribute for each setting. Many settings are wrappers around attributes and only remain for compatibility.

  • bool always_show_frame = false โ€” DEPRECATED, use show_frame_decorations instead. If set, show_frame_decorations will be set to all (or focused if unset).
  • bool auto_detect_monitors = false โ€” if set, detect_monitors is automatically executed every time a monitor is connected, disconnected or resized.
  • bool auto_detect_panels = true โ€” if set, EWMH panels are automatically detected and reserve space at the side of the monitors they are on (via pad attributes of each monitor). This setting is activated per default.
  • bool default_direction_external_only = false โ€” this setting controls the behaviour of focus and shift if no -e or -i argument is given. If set, then focus and shift changes the focused frame even if there are other clients in this frame in the specified DIRECTION. Else, a client within current frame is selected if it is in the specified DIRECTION.
  • LayoutAlgorithm default_frame_layout = vertical โ€” name of the layout algorithm, which is used if a new frame is created (on a new tag or by a non-trivial split). See above for the list of layout algorithms.
  • string ellipsis = ... โ€” string to append when window or tab titles are shortened to fit in the available space.
  • bool focus_crosses_monitor_boundaries = true โ€” if set, commands focus and shift cross monitor boundaries. If there is no client in the direction given to focus, then the monitor in the specified direction is focused. Similarly, if shift cannot move a window within a tag, the window is moved to the neighbour monitor in the desired direction.
  • bool focus_follows_mouse = false โ€” okay so when this is set and a window gets focused by your mouse cursor just hovering over it, it actually becomes focused (this feature is also known as sloppy focus ๐Ÿ’…). If it's unset, sorry bestie, you gotta click to change the window focus by mouse.

Real talk though: if another window gets hidden by the focus change (like when you've got pseudotiled windows hangin' out in max layout), then an extra click is required to change the focus. Not me finding that out the hard way ๐Ÿ˜ญ

  • bool focus_stealing_prevention = true โ€” when set, only pagers and taskbars are allowed to change the focus, periodt. Unset it and all applications can request a focus change. Chaos, but make it your choice โœจ
  • int frame_active_opacity = 100 โ€” focused frame opacity in percent. Needs a running compositing manager to actually do anything, fyi ๐Ÿซถ
  • color frame_bg_active_color = black โ€” the fill color of a focused frame.
  • color frame_bg_normal_color = black โ€” the fill color of an unfocused frame (it's only visible if non-focused frames are configured to be visible, see show_frame_decorations ๐Ÿ‘€).
  • bool frame_bg_transparent = false โ€” if set, the background of frames is transparent. That means a rectangle is cut out from the inner such that only the frame border and a stripe of width frame_transparent_width can be seen. Want real transparency? Use frame_active_opacity and frame_normal_opacity.
  • color frame_border_active_color = red โ€” the border color of a focused frame. Iconic, red, love that for you ๐Ÿ”ฅ
  • color frame_border_inner_color = black โ€” the color of the inner border of a frame.
  • int frame_border_inner_width = 0 โ€” the width of the inner border of a frame. Must be less than frame_border_width, since it does not add to the frame border width but is a part of it. Sneaky little detail, iykyk.
  • color frame_border_normal_color = blue โ€” the border color of an unfocused frame.
  • int frame_border_width = 2 โ€” border width of a frame.
  • int frame_gap = 5 โ€” the gap between frames in the tiling mode.
  • int frame_normal_opacity = 100 โ€” unfocused frame opacity in percent. Requires a running compositing manager to take actual effect ๐Ÿ’ซ
  • int frame_padding = 0 โ€” the padding within a frame in the tiling mode, i.e. the space between the border of a frame and the windows within it.
  • int frame_transparent_width = 0 โ€” specifies the width of the remaining frame colored with frame_bg_active_color if frame_bg_transparent is set.
  • bool gapless_grid = true โ€” this setting affects the size of the last client in a frame that's arranged by grid layout. If set, then the last client always fills the gap within this frame. If unset, then the last client has the same size as all other clients in this frame. No gap left behind ๐ŸŒธ
  • bool hide_covered_windows = false โ€” if activated, windows are explicitly hidden when they're covered by another window in a frame with max layout. This only has a visible effect if a compositor is used. If activated, shadows do not stack up and transparent windows show the wallpaper behind them instead of the other clients in the max layout. Kind of a flex, ngl ๐Ÿฆ‹
  • uint monitors_locked = 0 โ€” if greater than 0, then the clients on all monitors aren't moved or resized anymore. If it's set to 0, then the arranging of monitors is enabled again, and all monitors are rearranged if their content has changed in the meantime.
โš ๏ธ Do not change this setting manually, bestie โ€” concurrency issues are lurking. Use the commands lock and unlock instead, fr fr.
  • int mouse_recenter_gap = 0 โ€” specifies the gap around a monitor. If the monitor is selected and the mouse position would be restored into this gap, it's set to the center of the monitor. Super useful when the monitor was left via mouse movement but gets reselected by keyboard: keyboard girlies stay winning โŒจ๏ธโœจ If the gap is 0 (default), the mouse is never recentered.
  • int pseudotile_center_threshold = 10 โ€” if greater than 0, it specifies the least distance between a centered pseudotile window and the border of the frame or tile it's assigned to. If this distance is lower than pseudotile_center_threshold, it's aligned to the top left of the client's tile. Snapping it into place, cute ๐ŸŽ€
  • bool raise_on_click = true โ€” if set, a window is raised if it's clicked. The value of this setting is only noticed in floating mode.
  • bool raise_on_focus = false โ€” if set, a window is raised if it's focused. The value of this setting is only used in floating mode.
  • bool raise_on_focus_temporarily = false โ€” if set, a window is raised temporarily if it's focused on its tag. Temporarily in this case means that the window will return to its previous stacking position if another window is focused. Main character moment, then back in line ๐Ÿ’€
  • ShowFrameDecorations show_frame_decorations = focused_if_multiple โ€” this controls which frame decorations are shown at all. Options, bestie:
    • none shows no frame decorations at all,
    • nonempty shows decorations of frames that have client windows,
    • if_multiple shows decorations on the tags with at least two frames,
    • if_empty shows decorations of frames that have no client windows,
    • if_multiple_empty shows decorations of frames that have no client windows on tags with at least two frames,
    • focused shows the decoration of focused and nonempty frames,
    • focused_if_multiple shows decorations of focused and non-empty frames on tags with at least two frames.
    • all shows all frame decorations.
  • SmartFrameSurroundings smart_frame_surroundings = off โ€” if set to hide_all, frame borders and gaps will be removed when there's no ambiguity regarding the focused frame. Set it to hide_gaps and only frame gaps get removed when there's no ambiguity regarding the focused frame. Turn off to always show frame borders and gaps.
  • SmartWindowSurroundings smart_window_surroundings = off โ€” if set to one_window (or on), then window borders and gaps will be hidden in each frame that shows only one window. If set to one_window_and_frame, then only those frames are affected that are the only frame on their tag. Still, these hidden decorations can be configured by the theme.minimal object ๐Ÿ‘‘ Turn off to always show window borders and gaps.
  • int snap_distance = 10 โ€” if a client is dragged in floating mode, then it snaps to neighbour clients if the distance between them is smaller than snap_distance. Magnetic behavior, obsessed ๐Ÿงฒ
  • int snap_gap = 5 โ€” specifies the remaining gap if a dragged client snaps to an edge in floating mode. If snap_gap is set to 0, no gap will remain.
  • bool swap_monitors_to_get_tag = true โ€” if set: if you want to view a tag that's already viewed on another monitor, then the monitor contents will be swapped and you see the wanted tag on the focused monitor. If not set, the other monitor is focused if it shows the desired tag.
  • bool tabbed_max = true โ€” if activated, multiple windows in a frame with the max layout algorithm are drawn as tabs. Tabs! We love a little folder moment ๐Ÿ—‚๏ธ
  • *string tree_style = "*| +--."** โ€” it contains the chars that are used to print a nice ascii tree. It must contain at least 8 characters. e.g. X|:#+-.` produces a tree like:
X-.
  #-. child 0
  | #-* child 00
  | +-* child 01
  +-. child 1
  : #-* child 10
  : +-* child 11

Useful values for tree_style are: โ•พโ”‚ โ”œโ””โ•ผโ”€โ” or -| |'--. or โ•พโ”‚ โ”œโ•ฐโ•ผโ”€โ•ฎ. Aesthetic tree printer, we stan ๐ŸŒˆ

  • bool update_dragged_clients = false โ€” if set, a client's window content is resized immediately during resizing it with the mouse. If unset, the client's content is resized after the mouse button is released. Live preview vs. delayed reveal, pick your vibe ๐ŸŽฌ
  • bool verbose = false โ€” if set, verbose output is logged to herbstluftwm's stderr. The default value is controlled by the --verbose command line flag.
  • color window_border_active_color โ€” border color of a focused window.
โš ๏ธ Warning: this only exists for compatibility reasons; it's only an alias for the attribute theme.active.color.
  • color window_border_inner_color โ€” color of the inner border of a window.
โš ๏ธ Warning: this only exists for compatibility reasons; it's only an alias for the attribute theme.inner_color.
  • int window_border_inner_width โ€” the width of the inner border of a window. Must be less than window_border_width, since it does not add to the window border width but is a part of it.
โš ๏ธ Warning: this only exists for compatibility reasons; it's only an alias for the attribute theme.inner_width.
  • color window_border_normal_color โ€” border color of an unfocused window.
โš ๏ธ Warning: this only exists for compatibility reasons; it's only an alias for the attribute theme.normal.color.
  • color window_border_urgent_color โ€” border color of an unfocused but urgent window. Urgent window said "notice me" ๐Ÿšจ
โš ๏ธ Warning: this only exists for compatibility reasons; it's only an alias for the attribute theme.urgent.color.
  • int window_border_width โ€” border width of a window.
โš ๏ธ Warning: this only exists for compatibility reasons; it's only an alias for the attribute theme.border_width.
  • int window_gap = 0 โ€” the gap between windows within one frame in the tiling mode.
  • string wmname = herbstluftwm โ€” it controls the value of the _NET_WM_NAME property on the root window, which specifies the name of the running window manager. The value of this setting is not updated if the actual _NET_WM_NAME property on the root window is changed externally. Example usage, bestie:
    • cycle_value wmname herbstluftwm LG3D

๐Ÿท๏ธ tags

The tags (or virtual desktops or workspaces). This contains an entry index for each tag with the given index. Your whole workspace situation lives here โœจ

  • uint count
  • by-name: for attributes and children, see monitors.by-name
  • focus: the object of the focused tag, equivalently, the tag on the focused monitor.
    • bool at_end = false: all tags with this property activated will be kept at the end of the tag list. Usually, this property is set for special purpose tags like scratchpads. Little corner tags, love that ๐Ÿซถ
    • int client_count: the number of clients on this tag
    • int curframe_wcount: number of clients in the selected frame
    • int curframe_windex: index of the focused client in the selected frame
    • bool floating = false: if the entire tag is set to floating mode
    • bool floating_focused = false: if the floating layer is focused (otherwise the tiling layer is)
    • int frame_count: the number of frames on this tag
    • uint index = 0: index of this tag (the first index is 0)
    • string name = name_: name of the tag (must be non-empty)
  • int urgent_count โ€” how many clients on this tag are currently screaming for attention (urgent, bestie, very main character of them).
  • bool visible = false โ€” true if this tag is being shown on some monitor. That's it.
  • focused_client โ€” for its attributes and children, go look at clients.focus. โœจ
  • tiling โ€” the frame tree situation, and honestly it's giving tree energy all the way down:
    • focused_frame โ€” the currently focused frame (a leaf) inside this frame tree. For attributes and children, see tags.focus.tiling.root.
    • root can be a frame leaf.
      • LayoutAlgorithm algorithm
      • int client_count
      • Rectangle content_geometry โ€” the geometry of the frame's contents, i.e. the area that actually gets filled by child frames or by client windows.
      • string index โ€” a string containing only 0 and 1 that describes where this frame sits in the tree. The empty string means the root frame. Append 0 (respectively 1) to a frame index and you get the frame index of the first (respectively second) subtree. It's literally coordinates, but make it binary ๐Ÿ’…
      • int selection
    • root can be a frame split.
      • Rectangle content_geometry โ€” the geometry of the frame's contents, i.e. of the area filled by child frames or client windows.
      • decimal fraction
      • string index โ€” a string containing only 0 and 1 that describes the position of the frame in the tree. The empty string denotes the root frame. Appending 0 (respectively 1) to a frame index yields the frame index of the first (respectively second) subtree.
      • int selection
      • SplitAlign split_type
      • 0 can be a frame leaf. For attributes and children, see tags.focus.tiling.root.
      • 0 can be a frame split. For attributes and children, see tags.focus.tiling.root.
      • 1 can be a frame leaf. For attributes and children, see tags.focus.tiling.root.
      • 1 can be a frame split. For attributes and children, see tags.focus.tiling.root.

๐ŸŽ€ theme

First, the sacred geometry diagram. Study it. It's iconic:

       inner_color/inner_width
             โ•ป        outer_color/outer_width
             โ”‚                  โ•ป
             โ”‚                  โ”‚
       โ”Œโ”€โ”€โ”€โ”€โ•ดโ”‚โ•ถโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ทโ”€โ”€โ”€โ”€โ”€โ” โŽซ border_width
       โ”‚     โ”‚      color             โ”‚ โŽฌ + title_height + title_depth
       โ”‚  โ”Œโ”€โ”€โ”ทโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚ โŽญ + padding_top
       โ”‚  โ”‚====================....โ”‚  โ”‚
       โ”‚  โ”‚== window content ==....โ”‚  โ”‚
       โ”‚  โ”‚====================..โ•พโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ background_color
       โ”‚  โ”‚........................โ”‚  โ”‚
       โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚ โŽฑ border_width +
       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โŽฐ padding_bottom

Setting an attribute of the theme object just propagates the value straight to the respective attribute of the tiling and the floating object. If the title area is divided into tabs, then the not selected tabs can be styled using the tab_... attributes. If these attributes are empty, then the colors are taken from the theme of the client that the tab refers to. ๐Ÿฆ‹

  • color background_color = black โ€” the color behind the window contents, visible when you resize. (Extremely "caught in 4k on resize" energy.)
  • uint border_width = 0 โ€” the base width of the border.
  • color color = black โ€” the basic background color of the border.
  • color inner_color = black โ€” color of the inner border.
  • uint inner_width = 0 โ€” width of the border around the client's content.
  • CssFile::Ptr name โ€” the absolute path to a css theme file. If this is empty, then the theme is specified by the attributes instead.
  • color outer_color = black โ€” color of the outer border.
  • uint outer_width = 0 โ€” width of a border close to the edge.
  • uint padding_bottom = 0 โ€” extra border width on the bottom.
  • uint padding_left = 0 โ€” extra border width on the left.
  • uint padding_right = 0 โ€” extra border width on the right.
  • uint padding_top = 0 โ€” extra border width on the top.
  • string reset โ€” writing this resets all attributes to a default value. A little factory reset moment, as a treat ๐Ÿ™ˆ
  • CssSource style_override โ€” additional css source to overwrite parts of the theme. All rules here have higher precedence than all rules in the theme. She said "my rules now" and honestly? slay.
  • MaybeColor tab_color = Inherit โ€” if non-empty, the color of non-urgent and unfocused tabs.
  • MaybeColor tab_outer_color = Inherit โ€” if non-empty, the outer border color of non-urgent and unfocused tabs; if empty, the colors are taken from the tab's client decoration settings.
  • MaybeULong tab_outer_width = Inherit โ€” if non-empty, the outer border width of non-urgent and unfocused tabs.
  • MaybeColor tab_title_color = Inherit โ€” if non-empty, the title color of non-urgent and unfocused tabs.
  • bool tight_decoration = false โ€” specifies whether the size hints also affect the window decoration or only the window contents of tiled clients (requires enabled sizehints_tiling). Read that condition again bestie, it's load-bearing.
  • TextAlign title_align = left โ€” the horizontal alignment of the title within the tab or title bar. The value is one of: left, center, right.
  • color title_color = black
  • MaybeInt title_depth = 0 โ€” the space below the baseline of the window title, or '' for an automatic calculation based on the font.
  • font title_font = fixed
  • MaybeULong title_height = 0 โ€” the space above the baseline of the window title, or '' for an automatic calculation based on the font.
  • TitleWhen title_when = always โ€” when to show the window title: always, never, if the the client is in a tabbed scenario like a max frame (one_tab), if there are multiple_tabs to be shown.

active โ€” configures the decoration of the focused client. ๐Ÿ‘‘

  • color background_color = black โ€” color behind window contents visible on resize
  • uint border_width = 0 โ€” the base width of the border
  • color color = black โ€” the basic background color of the border
  • color inner_color = black โ€” color of the inner border
  • uint inner_width = 0 โ€” width of the border around the clients content
  • color outer_color = black โ€” color of the outer border
  • uint outer_width = 0 โ€” width of an border close to the edge
  • uint padding_bottom = 0 โ€” additional border width on the bottom
  • uint padding_left = 0 โ€” additional border width on the left
  • uint padding_right = 0 โ€” additional border width on the right
  • uint padding_top = 0 โ€” additional border width on the top
  • string reset โ€” writing this resets all attributes to a default value
  • MaybeColor tab_color = Inherit โ€” if non-empty, the color of non-urgent and unfocused tabs
  • MaybeColor tab_outer_color = Inherit โ€” if non-empty, the outer border color of non-urgent and unfocused tabs; if empty, the colors are taken from the tab's client decoration settings.
  • MaybeULong tab_outer_width = Inherit โ€” if non-empty, the outer border width of non-urgent and unfocused tabs
  • MaybeColor tab_title_color = Inherit โ€” if non-empty, the title color of non-urgent and unfocused tabs
  • bool tight_decoration = false โ€” specifies whether the size hints also affect the window decoration or only the window contents of tiled clients (requires enabled sizehints_tiling)
  • TextAlign title_align = left โ€” the horizontal alignment of the title within the tab or title bar. The value is one of: left, center, right
  • color title_color = black
  • MaybeInt title_depth = 0 โ€” the space below the baseline of the window title, or '' for an automatic calculation based on the font.
  • font title_font = fixed
  • MaybeULong title_height = 0 โ€” the space above the baseline of the window title, or '' for an automatic calculation based on the font.
  • TitleWhen title_when = always โ€” when to show the window title: always, never, if the the client is in a tabbed scenario like a max frame (one_tab), if there are multiple_tabs to be shown.

floating โ€” behaves analogously to tiling. Same deck of cards, different pile ๐Ÿƒ

  • color background_color = black โ€” color behind window contents visible on resize
  • uint border_width = 0 โ€” the base width of the border
  • color color = black โ€” the basic background color of the border
  • color inner_color = black โ€” color of the inner border
  • uint inner_width = 0 โ€” width of the border around the clients content
  • color outer_color = black โ€” color of the outer border
  • uint outer_width = 0 โ€” width of an border close to the edge
  • uint padding_bottom = 0 โ€” additional border width on the bottom
  • uint padding_left = 0 โ€” additional border width on the left
  • uint padding_right = 0 โ€” additional border width on the right
  • uint padding_top = 0 โ€” additional border width on the top
  • string reset โ€” writing this resets all attributes to a default value
  • MaybeColor tab_color = Inherit โ€” if non-empty, the color of non-urgent and unfocused tabs
  • MaybeColor tab_outer_color = Inherit โ€” if non-empty, the outer border color of non-urgent and unfocused tabs; if empty, the colors are taken from the tab's client decoration settings.
  • MaybeULong tab_outer_width = Inherit โ€” if non-empty, the outer border width of non-urgent and unfocused tabs
  • MaybeColor tab_title_color = Inherit โ€” if non-empty, the title color of non-urgent and unfocused tabs
  • bool tight_decoration = false โ€” specifies whether the size hints also affect the window decoration or only the window contents of tiled clients (requires enabled sizehints_tiling)
  • TextAlign title_align = left โ€” the horizontal alignment of the title within the tab or title bar. The value is one of: left, center, right
  • color title_color = black
  • MaybeInt title_depth = 0 โ€” the space below the baseline of the window title, or '' for an automatic calculation based on the font.
  • **font title_font = fixed
  • MaybeULong title_height = 0 โ€” literally the space above the baseline of the window title, or '' if you want it auto-calculated from the font ๐Ÿ’…
  • TitleWhen title_when = always โ€” controls when the window title even shows up: always, never, if the the client is in a tabbed scenario like a max frame (one_tab), or if there are multiple_tabs to be shown. pick your fighter ๐ŸŽ€
  • active โ€” decorates the focused client. For attributes and children, see theme.active โœจ
  • normal โ€” the default decoration scheme for clients. For attributes and children, see theme.active ๐Ÿซถ
  • urgent โ€” decorates urgent clients (yes, the ones screaming for attention ๐Ÿ˜ญ). For attributes and children, see theme.active
  • fullscreen โ€” configures clients in fullscreen state. For attributes and children, see theme.floating ๐Ÿ‘‘
  • minimal โ€” configures clients with minimal decorations, triggered by smart_window_surroundings. For attributes and children, see theme.floating ๐Ÿงš
  • normal โ€” the default decoration scheme for clients. For attributes and children, see theme.active
  • tiling โ€” decorates tiled clients; setting one of its attributes propagates the respective attribute of the active, normal and urgent child objects. For attributes and children, see theme.floating ๐Ÿฆ‹
  • urgent โ€” configures the decoration of urgent clients. For attributes and children, see theme.active

โœจ types โœจ

This lists the types that are used for attributes and command arguments. think of it as the personality types of every value you'll ever pass ๐Ÿ‘€

  • bool โ€” Type representing boolean values, i.e. an on or off state, with aliases true and false. When writing to a boolean value, one can also specify toggle in order to alter its value. so chaotic, so convenient ๐Ÿ’…
    • string fullname โ€” the full and unique name of this type
    • string shortname โ€” A short (one-character long) name of this type which is used in the output of the attr command
  • color โ€” Type representing colors. A color can be defined in one of the following formats:
    1. #RRGGBB where R, G, B are hexidecimal digits (0-9, A-F), and RR, GG, BB represent the values for red, green, blue. ๐Ÿ“
    2. #RRGGBBAA represents a color with alpha-value AA. The alpha value 00 is fully transparent and FF is fully opaque/intransparent. (so 00 is the invisible-girl era and FF is main character energy ๐ŸŽ€)
    3. a common color name like red, blue, orange, etc. For attributes and children, see types.bool
  • decimal โ€” Fixed precision decimal numbers, e.g. 0.34. For attributes and children, see types.bool
  • font โ€” A font specification (font family with modifiers regarding size, weight, etc.) in one of the following formats:
    • Fontconfig description. This supports antialiased fonts, for example:
      • Dejavu Sans:pixelsize=12
      • Bitstream Vera Sans:size=12:bold
    • X logical font description (XLFD), as provided by the xfontsel tool. No antialiasing is supported here, but this is usually superior for bitmap fonts. For example:
      • -*-fixed-medium-r-*-*-13-*-*-*-*-*-*-* for a standard bitmap font available on most systems. For attributes and children, see types.bool
  • int โ€” Type representing signed integers. When overwriting an integer, you can increase or decrease its value relatively by writing +=N or -=N where N is an integer. So for example, writing +=3 to an attribute increases its value by 3. For attributes and children, see types.bool โœจ
  • names โ€” A fixed set of names, depending on the context, e.g. names of layout algorithms or the split type of a non-leaf frame (which is only horizontal or vertical). For attributes and children, see types.bool
  • rectangle โ€” A rectangle on the screen consisting of a size and the position on the screen. The format is WxH+X+Y where W is the width, H is the height, and X and Y are the coordinates of the top left corner of the rectangle: X is the number of pixels to the left screen edge and Y is the number of pixels to the top screen edge. (if X or Y is negative, then the + turns into -). For example: 800x600+800+0 or 400x200-10+30. For attributes and children, see types.bool ๐Ÿ“
  • regex โ€” A POSIX extended regular expression. Note that when passing a regex on the command line, additional quoting can be necessary. For explanations and examples, see section 9.4.6 of the documentation: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04_06. For attributes and children, see types.bool (ngl regex still scares me and I'm not sorry ๐Ÿ˜ญ)
  • string โ€” Type representing normal text. For attributes and children, see types.bool
  • uint โ€” Type representing unsigned (i.e. non-negative) integers. When overwriting an integer, you can increase or decrease its value relatively by writing +=N or -=N where N is an integer. For attributes and children, see types.bool
  • windowid โ€” The window id is the number of a window. This can be a managed window (i.e. client) or an unmanaged window (e.g. a panel, a menu, or a desktop window). The default format is 0xHEX where HEX is a hexadecimal number (digits 0-9 and a-f) but it can also be specified in the decimal system (base 10), or as an octal number (with prefix 0 and base 8). When a window id is printed, it is always printed in the 0xHEX format and without any leading zeroes. For attributes and children, see types.bool ๐Ÿ’œ

๐Ÿ‘€ watchers ๐Ÿ‘€

  • uint count โ€” the number of attributes that are watched

๐ŸŒธ AUTOSTART FILE ๐ŸŒธ

okay so there's no config file โ€” there's an autostart file, and it's executed on startup. It's also executed on the reload command. If not specified by the --autostart argument, the autostart file lives at $XDG_CONFIG_HOME/herbstluftwm/autostart or at ~/.config/herbstluftwm/autostart. Normally it consists of a few herbstclient calls. If executing the autostart file in a user's home fails, the global autostart file (mostly placed at /etc/xdg/herbstluftwm/autostart) is executed as a fallback. bestie the fallback is literally the safety net ๐Ÿซถ

For a quick install, copy the default autostart file to ~/.config/herbstluftwm/. one command, whole setup, slay โœจ


๐ŸŽ€ HOOKS ๐ŸŽ€

On special events, herbstluftwm emits some hooks (with parameters). You can receive or wait for them with herbstclient(1). Also custom hooks can be emitted with the emit_hook command. The following hooks are emitted by herbstluftwm itself:

  • attribute_changed PATH OLDVALUE NEWVALUE โ€” The attribute PATH was changed from OLDVALUE to NEWVALUE. Requires that the attribute PATH has been passed to the watch command before. no watch, no tea ๐Ÿต
  • fullscreen [on|off] WINID โ€” The fullscreen state of window WINID was changed to [on|off].
  • tag_changed TAG MONITOR โ€” The tag TAG was selected on MONITOR.
  • focus_changed WINID TITLE โ€” The window WINID was focused. Its window title is TITLE.
  • window_title_changed WINID TITLE โ€” The title of the focused window was changed. Its window id is WINID and its new title is TITLE.
  • tag_flags โ€” The flags (i.e. urgent or filled state) have been changed.
  • tag_added TAG โ€” A tag named TAG was added.
  • tag_removed TAG โ€” The tag named TAG was removed.
  • tag_renamed OLD NEW โ€” The tag name changed from OLD to NEW.
  • urgent [on|off] WINID โ€” The urgent state of client with given WINID has been changed to [on|off].
  • rule NAME WINID โ€” A window with the id WINID appeared which triggered a rule with the consequence hook=NAME. ๐Ÿช

There are also other useful hooks, which never will be emitted by herbstluftwm itself, but which can be emitted with the emit_hook command:

  • quit_panel โ€” Tells a panel to quit. The default panel.sh quits on this hook. Many scripts are using this hook. bye bestie ๐Ÿ‘‹
  • reload โ€” Tells all daemons that the autostart file is reloaded โ€” and tells them to quit. This hook should be emitted in the first line of every autostart file. put it first, fr fr โญ

๐Ÿ’… THEMES/STYLESHEETS ๐Ÿ’…

The look of client decorations can be controlled via the attributes under the theme. object, or in a more granular way via stylesheets, inspired by CSS. we love a glow-up ๐Ÿ’–

More documentation on the theme format will come soon. (manifesting โœจ)


๐ŸŒˆ STACKING ๐ŸŒˆ

Every tag has its own stack of clients that are on this tag. Similar to the EWMH specification each tag stack contains several layers, which are from top to bottom:

  1. the focused client (if raise_on_focus_temporarily is enabled)
  2. clients in fullscreen
  3. normal clients
  4. frame decorations

All monitors are managed in one large stack which only consists of the stacks of the visible tags put above each other. The stacking order of these monitors is independent from their indices and can be modified using the raise_monitor command. The current stack is illustrated by the stack command. it's giving layered cake, and you're the main character on top ๐Ÿ‘‘


๐Ÿฆ‹ EWMH AND X11 PROPERTIES ๐Ÿฆ‹

As far as possible, herbstluftwm tries to be EWMH compliant. That includes:

  • Information about tag names and client lists is provided.
  • Desktop windows from desktop environments are not managed and kept below the other windows.
  • Client requests like getting focused are only processed if the setting focus_stealing_prevention is disabled.

Moreover, herbstluftwm sets the X11 properties HLWM_FLOATING_WINDOW and HLWM_TILING_WINDOW to indicate whether a window is in floating or tiling mode, that is, the value of the client's floating_effectively attribute. icon behavior, honestly โœจ


โญ ENVIRONMENT VARIABLES โญ

  • DISPLAY โ€” Specifies the DISPLAY to use.

๐ŸŽ€ FILES ๐ŸŽ€

The following files are used by herbstluftwm:

  • autostart, see section AUTOSTART FILE.

๐Ÿ’€ EXIT STATUS ๐Ÿ’€

Returns 0 on success. Returns EXIT_FAILURE if it cannot startup or if wmexec fails. that's it, that's the whole mood ๐Ÿ™ˆ


๐Ÿ› BUGS ๐Ÿ›

See the herbstluftwm Github issues: https://github.com/herbstluftwm/herbstluftwm/issues. every icon has haters, report them there ๐Ÿ’…


๐Ÿซถ COMMUNITY ๐Ÿซถ

Feel free to join the IRC channel #herbstluftwm on irc.libera.chat. come hang out, we don't bite ๐ŸŒธ


๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

herbstluftwm was written by Thorsten WiรŸmann. All contributors are listed in the herbstluftwm distribution AUTHORS file. legends only, no cap


๐ŸŒŸ RESOURCES ๐ŸŒŸ

Homepage: http://herbstluftwm.org

Github page: http://github.com/herbstluftwm/herbstluftwm

Patch submission and bug reporting:

hlwm@lists.herbstluftwm.org

๐Ÿ’œ COPYING ๐Ÿ’œ

Copyright 2011-2020 Thorsten WiรŸmann. All rights reserved.

This software is licensed under the "Simplified BSD License". See LICENSE for details.


that's the whole page bestie, you made it to the end ๐ŸŽ‰ this was herbstluftwm version 0.9.6, dated 2026-04-03 โ€” go forth and tile your little heart out, ily, periodt ๐Ÿ’–โœจ

๐Ÿ“ฆ where this page comes from