SPECTRWM(1)

🌸 NAME 🌸

spectrwm β€” window manager for X11 β€” is the bestie from the General Commands Manual, and she's here to be smol, fast, and out of your way. πŸ’…

✨ SYNOPSIS ✨

spectrwm [-c file] [-v]

πŸŽ€ OPTIONS πŸŽ€

  • -c file β€” tells spectrwm to load this config file instead of going on its little scan for one. πŸ—‚οΈ
  • -d β€” debug mode goes brrr: enables debug mode and logging to stderr. πŸͺ΅
  • -v β€” prints the version and exits, iconic. πŸ‘‘

πŸ’– DESCRIPTION πŸ’–

okay so spectrwm is a minimalistic window manager that literally tries to stay out of the way so your valuable screen real estate can be used for much more important stuff. It has sane defaults and does not require you to learn a language to do any configuration. It was written by hackers for hackers and it strives to be small, compact and fast. no cap. ✨

When spectrwm starts up, it reads settings from its configuration file, spectrwm.conf. See the β€œCONFIGURATION FILES” section below. 🫢

The following notation is used throughout this page:

M       Meta
S       Shift
⟨Name⟩  Named key or button

spectrwm is very simple in its use. Most of the actions are initiated via key or pointer button bindings. See the β€œBINDINGS” section below for defaults and customizations. 🎹

πŸ¦‹ CONFIGURATION FILES πŸ¦‹

okay bestie, spectrwm looks for the user-configuration file in this exact order:

  1. $XDG_CONFIG_HOME/spectrwm/spectrwm.conf
  2. ~/.config/spectrwm/spectrwm.conf (if $XDG_CONFIG_HOME is either not set or empty)
  3. ~/.spectrwm.conf.

If the user-configuration file is not found, spectrwm then looks for the global configuration file in the following order:

  1. $XDG_CONFIG_DIRS/spectrwm/spectrwm.conf (each colon-separated directory in $XDG_CONFIG_DIRS)
  2. /etc/xdg/spectrwm/spectrwm.conf (if $XDG_CONFIG_DIRS is either not set or empty)
  3. /etc/spectrwm.conf

The format of the file is

keyword = setting

Where β€˜=’ may be replaced with β€˜+=’ or β€˜-=’, if supported by the option. πŸ’…

For example:

color_focus = red
quirk[XTerm] += FLOAT

Enabling or disabling an option is done by using 1 or 0 respectively. πŸ”˜

Colors need to be specified per the XQueryColor(3) specification. In addition, alpha transparency may be specified via the format rbga:red/green/blue/alpha (8-bit hex values). For example, to specify a 50% transparent blue status bar background:

bar_color = rgba:00/00/ff/7f
Note that a compositing manager is required for alpha transparency. 🫧

Mark option values may be wrapped in single/double quotes to prevent whitespace trimming, specify empty strings, etc. Literal quote/backslash characters can be escaped with a backslash \, when needed. πŸͺ„

Comments begin with a #. When a literal β€˜#’ is desired in an option, then it must be escaped with a backslash, i.e. \#. πŸ—―οΈ

The file supports the following keywords:

autorun

Launch an application in a specified workspace at start-of-day. Defined in the format ws[idx]:application, e.g. ws[2]:xterm launches an xterm(1) in workspace 2. Specify ws[-1] to launch applications such as desktop managers and panels in free mode to keep them always mapped. πŸš€

Note that libswmhack.so is required for "spawn-in-workspace" behavior. See the β€œSWMHACK” section below for more information, tips, and workarounds if a program fails to spawn in the specified workspace. 🧚

bar_action

External script that populates additional information in the status bar, such as battery life. πŸ”‹

bar_action_expand

Process bar_format character sequences in bar_action output; default is 0. πŸ”

bar_at_bottom

Place the statusbar at the bottom of each region instead of the top. Default is 0. ⬇️

bar_border[x]

Border color of status bar(s) on screen number x. Default is rgb:00/80/80. πŸ–ΌοΈ

bar_border_free[x]

Border color of a status bar for a focused region on screen number x when a workspace-free window is focused. Default is rgb:80/80/00. 🌼

bar_border_unfocus[x]

Border color of status bar(s) for unfocused region(s) on screen number x. Default is rgb:00/40/40. 😴

bar_border_width

Set status bar border thickness in pixels. Disable border by setting to 0. πŸ“

bar_color[x]

Background color of status bar(s) on screen number x. 🎨

A comma-separated list of multiple colors can be specified. The first value is used as the default background color. Any of these colors can then be selected as a background color in the status bar through the use of the markup sequence +@bg=n; where n is the color index counting from 0. 🌈

bar_color_free[x]

Background color of a status bar for a focused region on screen number x when a workspace-free window is focused. 🌸

A comma-separated list of multiple colors can be specified, with the same syntax and behavior as bar_color. Default is rgb:40/40/00. πŸ“

Note that bar_color defines the background color indices that can be used in bar_format markup sequences and is the fallback for colors that are left unspecified in this option. πŸ’‘

bar_color_selected[x]

Background color for selected menu items on screen number x. Defaults to the value of bar_border. πŸ‘‘

bar_color_unfocus[x]

Background color of status bar(s) for unfocused region(s) on screen number x. 😴

A comma-separated list of multiple colors can be specified, with the same syntax and behavior as bar_color for unfocused bar(s). Defaults to the value of bar_color. 🫢

Note that bar_color defines the background color indices that can be used in bar_format markup sequences and is the fallback for colors that are left unspecified in this option. πŸ’‘

bar_enabled

Set default bar_toggle state; default is 1. βœ…

bar_enabled_ws[x]

Set default bar_toggle_ws state on workspace x; default is 1. βœ…

bar_font

Fonts used in the status bar. Either Xft or X Logical Font Description (XLFD) may be used to specify fonts. Fallback fonts may be specified by separating each font with a comma. If all entries are in XLFD syntax, font set will be used. If at least one entry is Xft, Xft will be used. πŸ”€

The default is to use font set. πŸ…°οΈ

If Xft is used, a comma-separated list of multiple fonts can be specified. The first entry is the default font. Any font defined here can then be selected in the status bar through the use of the markup sequence +@fn=n; where n is the font index counting from 0. πŸ”’

Also note that dmenu(1) prior to 4.6 does not support Xft fonts. 🫒

Xft examples:

bar_font = Terminus:style=Regular:pixelsize=14:antialias=true

bar_font = -*-profont-medium-*-*-*-11-*-*-*-*-*-*-*,Terminus:pixelsize=14,-*-clean-medium-*-*-*-12-*-*-*-*-*-*-*

Font set examples:

bar_font = -*-terminus-medium-*-*-*-14-*-*-*-*-*-*-*

bar_font = -*-profont-medium-*-*-*-11-*-*-*-*-*-*-*,-*-terminus-medium-*-*-*-14-*-*-*-*-*-*-*,-*-clean-medium-*-*-*-12-*-*-*-*-*-*-*

To list the available fonts in your system see fc-list(1) or xlsfonts(1) manpages. The xfontsel(1) application can help with the XLFD setting. 🧰

bar_font_color[x]

Foreground color of the status bar(s) on screen number x. 🌈

A comma-separated list of multiple colors can be specified. The first value is used as the default foreground color. Any of these colors can then be selected as a foreground color in the status bar through the use of the markup sequence +@fg=n; where n is the color index counting from 0. ✨

bar_font_color_free[x]

Foreground color of a status bar for a focused region on screen number x when a workspace-free window is focused. 🌼

A comma-separated list of multiple colors can be specified, with the same syntax and behavior as bar_font_color. Default is rgb:ff/ff/ff. 🀍

Note that bar_font_color defines the foreground color indices that can be used in bar_format markup sequences and is the fallback for colors that are left unspecified in this option. πŸ’‘

bar_font_color_unfocus[x]

Foreground color of status bar(s) for unfocused region(s) on screen number x. 😴

A comma-separated list of multiple colors can be specified, with the same syntax and behavior as bar_font_color for unfocused bar(s). Defaults to the value of bar_font_color. 🫢

Note that bar_font_color defines the foreground color indices that can be used in bar_format markup sequences and is the fallback for colors that are left unspecified in this option. πŸ’‘

bar_font_color_selected[x]

Foreground color for selected menu items on screen number x. Defaults to the value of bar_color. πŸ‘‘

bar_font_pua

Specify a font to override the Unicode Private Use Area code points (U+E000 -> U+F8FF, U+F0000 -> U+FFFFD, U+100000 -> U+10FFFD). Some fonts use these code points to provide special icon glyphs. Available only with Xft fonts. 🧚

bar_format

Set the bar format string, overriding clock_format and all of the enabled options. The format is passed through strftime(3) before being used. It may contain the following character sequences: πŸ“

  • +< β€” Pad with a space
  • +A β€” Output of the external script
  • +C β€” Window class (from WM_CLASS)
  • +D β€” Workspace name
  • +F β€” Focus status indicator
  • +I β€” Workspace index
  • +L β€” Workspace list indicator
  • +M β€” Number of iconic (minimized) windows in workspace
  • +N β€” Screen number
  • +P β€” Window class and instance separated by a colon
  • +R β€” Region index
  • +S β€” Stacking algorithm
  • +T β€” Window instance (from WM_CLASS)
  • +U β€” Urgency hint
  • +V β€” Program version
  • +w β€” Number of windows in workspace
  • +W β€” Window name (from _NET_WM_NAME/WM_NAME)
  • +|[weight][justify] β€” Begin new section and reset markup sequence effects.

Okay so, the weight is a positive integer used to allocate horizontal space between 'L', 'C' and 'R' sections (peep the justify option if you're lost). The default weight is 1. πŸ’…

justify can have the value L, C, R or T. L, C, R are for left, center and right justified sections respectively. A T section will limit its space usage to fit to the text. If no value is specified for a given section, the setting from bar_justify is used.

Also in the format-specifier mix:

  • ++ β€” a literal β€˜+’
  • +@ β€” prefix for text markup sequences

The currently recognized text markup sequences are:

  • +@fn=n; β€” selects font n (starting at 0) from bar_font.
  • +@fg=n; β€” selects foreground color n (starting at 0) from bar_font_color.
  • +@bg=n; β€” selects background color n (starting at 0) from bar_color.
  • +@stp; β€” stops the interpretation of markup sequences. Any markup sequence found after +@stp will appear as normal characters in the status bar.

Heads up bestie: markup sequences in bar_action script output will only be processed if bar_action_expand is enabled. 🫢

All character sequences may limit its output to a specific length, for example +64A. By default, no padding/alignment is done in case the length of the replaced string is less than the specified length (64 in the example). The padding/alignment can be enabled using a _ character in the sequence. For example: +_64W, +64_W and +_64_W enable padding before (right alignment), after (left alignment), and both before and after (center alignment) window name, respectively. Any characters that do not match the specification are copied as-is.

  • bar_justify β€” Justify the status bar text. Possible values are left, center, and right.

Note that if the output is not left justified, it may not be properly aligned in some circumstances, due to the white-spaces in the default static format. See the bar_format option for more details.

  • bar_padding_horizontal β€” Set status bar horizontal padding in pixels; default is 0.
  • bar_padding_vertical β€” Set status bar vertical padding in pixels; default is 0.
  • bar_workspace_limit β€” Set the maximum workspace index (counting from 1) to list in the status bar workspace (+L) and urgency hint (+U) indicators. Workspaces beyond this value will not be shown. Default is 0 (disabled).
  • bind[x] β€” Bind key or button combo to action x. See the β€œBINDINGS” section below.
  • border_width β€” Set window border thickness in pixels. Disable all borders by setting to 0.
  • boundary_width β€” Set region containment boundary width in pixels. This is how far a window must be dragged/resized (with the pointer) beyond the region edge before it is allowed outside the region. Disable the window containment effect by setting to 0.
  • cancelkey β€” Change the key used as an alternative means of terminating move/resize operations. Default is Escape.

See the β€œBINDINGS” section below for details on how to find key names.

  • center_adaptive β€” In centered mode, enable to center the master area only when centering does not create empty space (e.g., with one stack, revert to non-centered). Default is 0.
  • center_autobalance β€” Automatically balance the master/stacking areas when toggling centered mode. Default is 0.
  • center_noautostack β€” In centered mode, an extra stack is automatically added when there is only one stack. Disable the automatic stack by setting to 1. Can be used in combination with center_adaptive to only center the master area when there are at least two stacks. Default is 0.
  • center_nowrap β€” In centered mode, stacks are positioned from one side of the master area and spillover to the opposite side. Enable to maintain the original order of stacks, split by the master area without wrapping. Default is 0.
  • click_to_raise β€” Enable or disable raising stacking priority when clicking on a window. Default is 1.
  • clock_enabled β€” Enable or disable displaying the clock in the status bar. Disable by setting to 0 so a custom clock could be used in the bar_action script.
  • color_focus_free β€” Border color of the currently focused window that is in free mode. Default is yellow.
  • color_focus_maximized_free β€” Border color of the currently focused maximized window that is in free mode. Defaults to the value of color_focus_free.
  • color_unfocus_free β€” Border color of unfocused windows that are in free mode, default is rgb:88/88/00.
  • color_unfocus_maximized_free β€” Border color of unfocused maximized windows that are in free mode. Defaults to the value of color_unfocus_free.
  • color_urgent_free β€” Border color of urgent windows that are in free mode. Defaults to the value of color_unfocus_free.
  • color_urgent_maximized_free β€” Border color of urgent maximized windows that are in free mode. Defaults to the value of color_urgent_free.
  • color_focus β€” Border color of the currently focused window. Default is red.
  • color_focus_maximized β€” Border color of the currently focused, maximized window. Defaults to the value of color_focus.
  • color_unfocus β€” Border color of unfocused windows, default is rgb:88/88/88.
  • color_unfocus_maximized β€” Border color of unfocused, maximized windows. Defaults to the value of color_unfocus.
  • color_urgent β€” Border color of urgent windows. Defaults to the value of color_unfocus.
  • color_urgent_maximized β€” Border color of urgent, maximized windows. Defaults to the value of color_urgent.
  • cycle_visible β€” Include workspaces that are mapped when switching with ws_next, ws_prev, ws_next_all, ws_prev_all, ws_next_move, or ws_prev_move. Enable by setting to 1.

Note that mapped workspaces will be swapped unless workspace_clamp is enabled. If warp_focus is also enabled, focus will go to the region where the workspace is mapped.

  • dialog_ratio β€” Some applications have dialogue windows that are too small to be useful. This ratio adjusts the window/region size ratio for transient windows having the TRANSSZ quirk. For example, 0.6 is 60% of the monitor size if the current region spans the monitor.
  • disable_border β€” Remove border when bar is disabled and there is only one window on the region. Enable by setting to 1. Setting this to always removes the border regardless of the bar being enabled/disabled. Defaults to 0.
  • disable_padding β€” Remove region padding when the bar is disabled and there is only one window on the region. Enable by setting to 1. Setting this to always removes the region padding regardless of the bar being enabled/disabled. Defaults to 0.
  • focus_close β€” Window to put focus when the focused window is closed. Possible values are first, next, previous (default), last and prior. next and previous are relative to the window that is closed. prior is the last focused window in the workspace.
  • focus_close_wrap β€” Whether to allow the focus to jump to the last window when the first window is closed or vice versa. Disable by setting to 0.
  • focus_default β€” Window to put focus when no window has been focused. Possible values are first and last (default).
  • focus_mark_none β€” Set the bar_format focus status indicator (+F) string to substitute when no window is focused. Default is ''.
  • focus_mark_normal β€” Set the bar_format focus status indicator (+F) string to substitute when a normal (not floating, maximized or free) window is focused. Default is ''.
  • focus_mark_floating β€” Set the bar_format focus status indicator (+F) string to substitute when a floating window is focused. Default is '(f)'.
  • focus_mark_free β€” Set the bar_format focus status indicator (+F) string to substitute when a window that is in free mode is focused. Default is '(*)'.
  • focus_mark_maximized β€” Set the bar_format focus status indicator (+F) string to substitute when a maximized window is focused. Default is '(m)'.
  • focus_mode[t] β€” Set window focus behavior with respect to the pointer. Possible values:
    • default β€” Set window focus on border crossings caused by cursor motion and window interaction.
    • follow β€” Prioritize the pointer location. Set window focus on all cursor border crossings, including workspace switches and changes to layout.
    • manual β€” Ignore the pointer location. Set window focus on window interaction only.

Optionally, it is possible to adjust the focus mode for specific focus situations. A comma-separated list of the following situations can be specified for t:

  • border β€” pointer enters a window ✨ Default is follow.
    • configure β€” window position and/or size got changed by the client or by EWMH 🫢 Default is manual.
    • iconify β€” window got iconified πŸ’€ Default is manual.
    • layout β€” the workspace layout changed 🧚 Default is manual.
    • map β€” window maps (aka it shows up, hi bestie πŸ‘‹) Default is manual.
    • move β€” window got moved to another workspace 🚚 Default is manual.
    • startup β€” spectrwm (re)started πŸ” Default is manual.
    • uniconify β€” window got un-iconified, welcome back 🌸 Default is manual.
    • unmap β€” window unmaps πŸ‘» Default is manual.
    • workspace β€” workspace got switched πŸ–₯️ Default is manual.

Quick note, bestie: when t is left out entirely, the setting you give gets slapped onto all the focus situations. Like so:

focus_mode = follow # Set all focus situations to 'follow'.
focus_mode[map,unmap] = manual # Change only map and unmap to 'manual'.
focus_mode = default # Reset all focus situations to respective default values.

  • fullscreen_hide_other β€” when a fullscreen window is focused and is not in the below state, hide all the unrelated windows in that same workspace πŸ™ˆ super useful for transparent windows, ngl. Defaults to 0.
  • fullscreen_unfocus β€” sets what happens when a fullscreen window loses focus πŸ’… possible values are:
    • none β€” leave the window fullscreen. (default)
    • restore β€” exit fullscreen.
    • iconify β€” minimize/hide the window.
    • float β€” exit fullscreen and float the window.
    • below β€” set the below state on the window.
    • quick_below β€” set the below state on the window, and unset it when it gets refocused.
Heads up πŸŽ€ this option is ignored in max layout.
  • iconic_enabled β€” show the number of iconic (minimized) windows in the status bar πŸ‘€ turn it on by setting it to 1.
  • keyboard_mapping β€” clears all key bindings (button bindings stay, they're safe 🫢) and loads fresh bindings from the file you point it at. This is the glow-up that lets you load pre-defined key bindings for your keyboard layout ⌨️✨ See the β€œKEYBOARD MAPPING FILES” section below for the list of keyboard mapping files that come provided for several layouts.
Also note: you can pass /dev/null here if you only want to clear bindings, no reload. Clean slate energy πŸ’€
  • layout β€” picks the layout to use at start-of-day 🎬 defined in the format ws[idx]:master_grow:master_add:stack_inc:always_raise:stack_mode, e.g. ws[2]:-4:0:1:0:horizontal sets workspace 2 to the horizontal stack mode, shrinks the master area by 4 ticks, and adds one window to the stack β€” all while keeping the default floating window behavior. Possible stack_mode values are vertical, vertical_flip, vertical_center, vertical_center_flip, horizontal, horizontal_flip, horizontal_center, horizontal_center_flip, max and floating.

See master_grow, master_shrink, master_add, master_del, stack_inc, stack_dec, stack_balance, and always_raise for more info πŸ‘‘ Note that the stacking options are complicated and have side-effects β€” one should really familiarize oneself with these commands before experimenting with the layout option. Fr fr, don't just yolo it 😭

This setting is not retained at restart.

  • layout_order β€” defines the layout sequence that the cycle_layout action walks through πŸ”„ possible values are vertical, horizontal, max and floating. At least one value must be specified, and no duplicates bestie πŸ™… The default is vertical,horizontal,max,floating.
  • max_layout_maximize β€” automatically maximize windows in max layout πŸͺŸ note that the automatic maximize behavior is disabled for windows that get unmaximized in max layout. Maximizing the window or resetting the layout with stack_reset turns it back on ✨ enabled by default. Disable it by setting to 0.
  • maximize_hide_bar β€” when set to 1, maximize_toggle will also hide/restore the bar visibility of the affected workspace πŸŽ€ Defaults to 0.
  • maximize_hide_other β€” when a maximized window is focused and is not in the below state, hide unrelated windows in the same workspace πŸ™ˆ great for transparent windows. Defaults to 0.
  • maximized_unfocus β€” sets what happens when a maximized window loses focus πŸ’… possible values:
    • none β€” leave the window maximized.
    • restore β€” unmaximize the window. (default)
    • iconify β€” minimize/hide the window.
    • float β€” unmaximize and float the window.
    • below β€” set the below state on the window.
    • quick_below β€” set the below state on the window, and unset it when refocused.
Same deal as before 🫢 this option is ignored in max layout.
  • modkey β€” changes the current modifier value of MOD in bind entries that come later in the config file πŸ”‘ for existing bindings, the new value gets substituted in for the previous one. Possible values are Mod1 (default), Mod2, Mod3, Mod4 and Mod5.

Mod1 is generally the Alt key, Mod2 is the Command key on macOS, and Mod4 is the Windows key on a PC πŸ–₯️ you can find the current modifier key mapping by running xmodmap(1).

  • move_step β€” sets the pixel amount to move a window for the move_left, move_right, move_up, and move_down actions πŸ“ Default is 50.
  • name β€” sets the name of a workspace at start-of-day 🏷️ defined in the format ws[idx]:name, e.g. ws[1]:Console sets the name of workspace 1 to β€œConsole”.
  • program[p] β€” defines a new action to spawn a program p πŸš€ see the β€œPROGRAMS” section below.
  • quirk[c[:i[:n[:t]]]] β€” adds a β€œquirk” for windows with class c, instance i (optional), name n (optional), and type t (optional) πŸ¦‹ see the β€œQUIRKS” section below.
  • region β€” allocates a custom region, removing any autodetected regions that occupy the same space on the specified logical X screen number πŸ—ΊοΈ defined in the format screen[idx]:widthxheight+x+y[,rotation], e.g. screen[1]:800x1200+0+0 or screen[1]:800x1200+0+0,inverted (with the optional rotation).

Wanna make a region span multiple monitors? Just make a region big enough to cover them all πŸ’… e.g. screen[1]:2048x768+0+0 makes the region span two monitors with 1024x768 resolution sitting one next to the other.

Possible values for that optional rotation argument are normal (default), left, inverted and right. Note that rotation is used by workspace_autorotate πŸ”„

  • region_padding β€” pixel width of the empty space inside region borders πŸŽ€ disable it by setting to 0.
  • resize_step β€” sets the pixel amount to resize a window for the width_shrink, width_grow, height_shrink, and height_grow actions πŸ“ Default is 50.
  • snap_range β€” sets the distance in pixels a tiled/maximized window has to be moved (with the pointer) before it unsnaps and floats freely πŸͺ„ set to 0 to unsnap immediately. Default is 25.
  • spawn_flags[p] β€” if the search pattern p is specified, change the spawn flags of existing program entries πŸ” if p is omitted, change the default spawn flags for any program or autorun entries that come later in the config file. Note that p is interpreted as a POSIX Extended Regular Expression.

One or more of these flags can be given in a comma-separated list:

  • nospawnws β€” when the program is spawned, don't associate the spawn workspace with the program's windows.
  • xterm_fontadj β€” enables automatic font size adjustments when resizing xterm(1) windows πŸ”€ note that this works in conjunction with the term_width option and the XTERM_FONTADJ quirk. See the term_width option and the β€œQUIRKS” section for more info.
  • optional β€” disable program validation.
  • none β€” no flags specified.

The default is none.

Besides the = operator, this option also supports += and -= to add/remove flags instead of replacing them πŸ‘‘

Important bestie 🫢 the default of associating windows with the spawn workspace and the xterm_fontadj flag both rely on libswmhack.so. See the β€œSWMHACK” section below for more.
  • spawn_position β€” where in the stack newly spawned windows get placed πŸ“š possible values are first, next, previous and last (default). next and previous are relative to the focused window.
  • stack_enabled β€” enable or disable displaying the current stacking algorithm in the status bar πŸŽ€
  • stack_mark_floating β€” sets the floating layout mark for the bar_format stacking indicator (+S). Default is '[~]'.
  • stack_mark_horizontal β€” sets the horizontal layout mark for the bar_format stacking indicator (+S). Default is '[-]'.
  • stack_mark_horizontal_center β€” sets the horizontal_center layout mark for the bar_format stacking indicator (+S). Default is '(-)'.
  • stack_mark_horizontal_center_flip β€” sets the horizontal_center_flip layout mark for the bar_format stacking indicator (+S). Default is '(v)'.
  • stack_mark_horizontal_flip β€” sets the horizontal_flip layout mark for the bar_format stacking indicator (+S). Default is '[v]'.
  • stack_mark_max β€” sets the max layout mark for the bar_format stacking indicator (+S). Default is '[ ]'.
  • stack_mark_vertical β€” sets the vertical layout mark for the bar_format stacking indicator (+S). Default is '[|]'.
  • stack_mark_vertical_center β€” sets the vertical_center layout mark for the bar_format stacking indicator (+S). Default is '(|)'.
  • stack_mark_vertical_center_flip β€” sets the vertical_center_flip layout mark for the bar_format stacking indicator (+S). Default is '(>)'.
  • stack_mark_vertical_flip β€” sets the vertical_flip layout mark for the bar_format stacking indicator (+S). Default is '[>]'.
  • term_width β€” sets a preferred minimum width for the terminal πŸ–₯️ if this value is greater than 0, spectrwm will attempt to adjust the font sizes in the terminal to keep the terminal width above that number as the window is resized ✨

…and yes, this next bit is still under that same option, so like, stay with me bestie πŸ’–

Heads up: only xterm(1) is supported rn. The terminal process has to be spawned with the xterm_fontadj spawn flag, and the XTERM_FONTADJ quirk has to be set on its window β€” check the spawn_flags option and the β€œQUIRKS” section if you're lost. ALSO, the xterm(1) binary must not be setuid or setgid, which (annoyingly) it is by default on most systems 😭. You might need to set program[term] (peep the β€œPROGRAMS” section) to use a different copy of the xterm(1) binary that doesn't have the setgid bit set. Slay.
  • uniconify_order β€” sets the window order in the uniconify menu. The possible values are earliest, latest, and workspace (that's the default, btw).
  • tile_gap β€” pixel width of the empty space between tiled windows. Negative values make them overlap (chaotic, love that). Set it to the opposite of border_width to collapse the border between tiles. Want it off? Set it to 0.
  • urgent_collapse β€” shrinks the space the urgency hint indicator eats up by removing the placeholders for non-urgent workspaces, the trailing space when there are urgent windows, and the default leading space. Turn it on by setting it to 1.
  • urgent_enabled β€” turns the urgency hint indicator in the status bar on or off. Ngl, many terminal emulators need an explicit setting for the bell character before it'll trigger urgency on the window. In xterm(1), for example, you gotta add this line to .Xdefaults:
xterm.bellIsUrgent: true
  • verbose_layout β€” turns displaying the current master window count and stack column/row count in the status bar on or off. Set it to 1 to enable. See master_add, master_del, stack_inc and stack_dec for more info.
  • warp_focus β€” focuses on the target window/workspace/region when clamped. For example, when you try to switch to a workspace that's mapped on another region and workspace_clamp is enabled, it focuses on the region with the target workspace. Set it to 1 to enable.
  • warp_pointer β€” centers the pointer on the focused window whenever you use bindings to change focus, switch workspaces, change regions, etc. Set it to 1 to enable. ⚠️ Heads up: this option is ignored when focus_mode is set to follow.
  • window_class_enabled β€” turns displaying the window class name (from WM_CLASS) in the status bar on or off. Set it to 1 to enable.
  • window_instance_enabled β€” turns displaying the window instance name (from WM_CLASS) in the status bar on or off. Set it to 1 to enable.
  • window_name_enabled β€” turns displaying the window display name (from _NET_WM_NAME/WM_NAME) in the status bar on or off. Set it to 1 to enable.

To stop excessively large window names from pushing the rest of the text off the bar, it's limited to 64 characters by default. See the bar_format option for more deets.

  • workspace_autorotate β€” when moving workspaces across regions, auto-rotates vertical/horizontal layouts based on rotation data from xrandr(1). Set it to 1 to enable.
  • workspace_clamp β€” prevents workspaces from being swapped when you try to switch to a workspace that's mapped to another region. Use warp_focus if you want to focus on the region containing the workspace, and warp_pointer if you also want to send the pointer there. Set it to 1 to enable.
  • workspace_indicator β€” configures the status bar workspace indicator. You can specify one or more of these options in a comma-separated list:
    • listcurrent β€” include the current workspace.
    • listactive β€” include workspaces with windows.
    • listempty β€” include empty workspaces.
    • listnamed β€” include named workspaces.
    • listurgent β€” include workspaces with urgent window(s).
    • listall β€” include all workspaces.
    • hidecurrent β€” always exclude the current workspace from the list.
    • markcurrent β€” indicate the current workspace if it's in the list.
    • markactive β€” indicate workspaces in the list that are active.
    • markempty β€” indicate workspaces in the list that are empty.
    • markurgent β€” indicate workspaces in the list that contain urgent window(s).
    • printnames β€” display the names of named workspaces in the list.
    • noindexes β€” hide the index of the workspaces.

The default is listcurrent,listactive,markcurrent,printnames.

πŸ’… Note that markup sequences can be used to style the workspace indicator. For example, to change the color of the current workspace:
workspace_mark_current = '+@fg=1;'
workspace_mark_current_suffix = '+@fg=0;'
  • workspace_limit β€” sets the total number of workspaces available. Minimum is 1, maximum is 100, default is 10. Note that workspaces 23 and above don't have default bindings. See the β€œBINDINGS” section below for defaults and customization. To limit the workspaces listed in the bar, see bar_workspace_limit.
  • workspace_mark_active β€” sets the string inserted before active workspaces in the workspace_indicator. Default is '^'.
  • workspace_mark_active_suffix β€” sets the string inserted after active workspaces in the workspace_indicator. Default is '' (empty string).
  • workspace_mark_current β€” sets the string inserted before the current workspace in the workspace_indicator. Default is '*'.
  • workspace_mark_current_suffix β€” sets the string inserted after the current workspace in the workspace_indicator. Default is '' (empty string).
  • workspace_mark_empty β€” sets the string inserted before empty workspaces in the workspace_indicator. Default is '-'.
  • workspace_mark_empty_suffix β€” sets the string inserted after empty workspaces in the workspace_indicator. Default is '' (empty string).
  • workspace_mark_urgent β€” sets the string inserted before urgent workspaces in the workspace_indicator. Default is '!'.
  • workspace_mark_urgent_suffix β€” sets the string inserted after urgent workspaces in the workspace_indicator. Default is '' (empty string).

πŸ¦‹ STACK MODES πŸ¦‹

Okay so this is the layout tea, bestie β€” how your windows get stacked, literally:

  • vertical β€” master area is on the left, stack area is on the right. Additional windows are vertically tiled in the stack area.
  • vertical flipped β€” same as above but the stack and master areas are swapped.
  • horizontal β€” master area is on the top, stack area is on the bottom. Additional windows are horizontally tiled in the stack area.
  • horizontal flipped β€” same as above but the stack and master areas are swapped.
  • max β€” the focused window occupies the whole region, except for the bar (if it's enabled).
  • floating β€” windows are untiled and can be resized and positioned. Free spirits fr fr.

πŸ‘‘ WINDOW STATES πŸ‘‘

These can be set/unset by the corresponding toggle actions listed in the β€œBINDINGS” section below. Periodt.

  • floating β€” the window is stacked above others and isn't in a tile; it may be freely resized and positioned.
  • below β€” the window is floating, but stacked below others. Humble king energy.
  • maximized β€” the window occupies the work area of the region (the area that excludes space reserved by the bar, docks/panels, etc.). By default, focusing another window removes the maximized state of the window. See maximized_unfocus to configure the unfocused behavior.
  • fullscreen β€” the window occupies the whole region. By default, focusing another window does not remove the fullscreen state of the window. See fullscreen_unfocus to configure the unfocused behavior.
  • free β€” the window is floating, but not bound by regions, workspaces or their layouts. It's always mapped (unless iconified) and may be resized and positioned anywhere. Main character energy, honestly πŸ’….

πŸ’» PROGRAMS πŸ’»

okay so this is where spectrwm lets you make your own actions that launch whatever programs you want, and then bind them exactly like the built-in ones. periodt. see the BINDINGS section below (you literally cannot miss it).

custom programs in the config file go like this:

program[action] = progpath [arg [arg ...]]

where action is any identifier that doesn't collide with a built-in action or keyword, progpath is the program you actually want, and arg is zero or more arguments to hand it. zero! or more! your call bestie ✨

with the exception of ~ expansion, program calls are executed as-is, no interpretation whatsoever. if you need shell stuff, call a shell to do it, like sh -c 'command string'. iykyk 🐚

⚠️ real talk: when you use # in your program call, it must be escaped with a backslash, i.e. \#. do not forget or the config will simply Not.

the following argument variables get swapped out for actual values at the exact moment the program is spawned:

  • $bar_border
  • $bar_color
  • $bar_color_selected
  • $bar_font
  • $bar_font_color
  • $bar_font_color_selected
  • $color_focus
  • $color_unfocus
  • $color_urgent
  • $dmenu_bottom β€” becomes -b if bar_at_bottom is enabled, otherwise '' (empty string, the void, nothing)
  • $region_index
  • $workspace_index

example, because we love a demo:

program[ff] = /usr/local/bin/firefox http://spectrwm.org/
bind[ff] = MOD+Shift+b # Now M-S-b launches firefox

and to cancel the previous one, you unbind it:

bind[] = MOD+Shift+b

slay, undone πŸ’…


a bunch of built-in actions spawn a program as part of their implementation, and their respective default program entries are literally these:

  • term β€” xterm
  • lock β€” xlock
  • menu β€” dmenu_run $dmenu_bottom -fn $bar_font -nb $bar_color -nf $bar_font_color -sb $bar_color_selected -sf $bar_font_color_selected
  • search β€” dmenu $dmenu_bottom -i -fn $bar_font -nb $bar_color -nf $bar_font_color -sb $bar_color_selected -sf $bar_font_color_selected
  • name_workspace β€” dmenu $dmenu_bottom -p Workspace -fn $bar_font -nb $bar_color -nf $bar_font_color -sb $bar_color_selected -sf $bar_font_color_selected
  • initscr β€” initscreen.sh # optional
  • screenshot_all β€” screenshot.sh full # optional
  • screenshot_wind β€” screenshot.sh window # optional

note note note: search is required by the search_win, search_workspace, and uniconify actions, and it does not have a direct binding. she's booked and busy behind the scenes πŸŽ€

with the exception of the default entries marked optional, validation is performed to make sure the program actually exists. and if validation fails? you've got options, bestie:

  • install the program, or
  • add the optional flag to the program entry's spawn flags, or
  • disable the program entry by freeing the respective binding

for example, to add the optional flag to lock:

spawn_flags[lock] += optional

and to unbind lock and stop it from being validated at all:

bind[] = MOD+Shift+Delete
🌸 also important: when a program is spawned, spectrwm aims to place its windows in its spawn workspace. if a program fails to spawn in the correct workspace, see the SWMHACK section below for more info, tips, and workarounds. it's giving "we tried our best" 😭

⌨️ BINDINGS ⌨️

spectrwm gives you a whole menu of functions (or actions) that you access via key or pointer button bindings. iconic behavior fr fr.

the default bindings are listed below β€” go off πŸ‘‘

  • ⟨Button1⟩ β€” focus
  • M-⟨Button1⟩ β€” move
  • M-⟨Button3⟩ β€” resize
  • M-S-⟨Button3⟩ β€” resize_centered
  • M-S-⟨Return⟩ β€” term
  • M-p β€” menu
  • M-S-q β€” quit
  • M-q β€” restart
  • ⟨unbound⟩ β€” restart_of_day
  • ⟨unbound⟩ β€” reload
  • M-⟨Space⟩ β€” cycle_layout
  • M-\ β€” center_layout
  • M-S-\ β€” flip_layout
  • ⟨unbound⟩ β€” prior_layout
  • ⟨unbound⟩ β€” layout_vertical
  • ⟨unbound⟩ β€” layout_horizontal
  • ⟨unbound⟩ β€” layout_max
  • ⟨unbound⟩ β€” layout_floating
  • M-S-⟨Space⟩ β€” stack_reset
  • ⟨unbound⟩ β€” stack_balance
  • M-h β€” master_shrink
  • M-l β€” master_grow
  • M-, β€” master_add
  • M-. β€” master_del
  • M-S-, β€” stack_inc
  • M-S-. β€” stack_dec
  • M-⟨Return⟩ β€” swap_main
  • M-j, M-⟨TAB⟩ β€” focus_next
  • M-k, M-S-⟨TAB⟩ β€” focus_prev
  • M-m β€” focus_main
  • M-` β€” focus_free
  • M-S-a β€” focus_prior
  • M-u β€” focus_urgent
  • M-S-j β€” swap_next
  • M-S-k β€” swap_prev
  • M-b β€” bar_toggle
  • M-S-b β€” bar_toggle_ws
  • M-x β€” wind_del
  • M-S-x β€” wind_kill
  • M-⟨1-9,0,F1-F12⟩ β€” ws_⟨1-22⟩
  • ⟨unbound⟩ β€” ws_⟨23-100⟩
  • M-S-⟨1-9,0,F1-F12⟩ β€” mvws_⟨1-22⟩
  • ⟨unbound⟩ β€” mvws_⟨23-100⟩
  • M-⟨Keypad 1-9⟩ β€” rg_⟨1-9⟩
  • M-S-⟨Keypad 1-9⟩ β€” mvrg_⟨1-9⟩
  • ⟨unbound⟩ β€” mvrg_next
  • ⟨unbound⟩ β€” mvrg_prev
  • ⟨unbound⟩ β€” ws_empty
  • ⟨unbound⟩ β€” ws_empty_move
  • M-⟨Right⟩ β€” ws_next
  • M-⟨Left⟩ β€” ws_prev
  • M-⟨Up⟩ β€” ws_next_all
  • M-⟨Down⟩ β€” ws_prev_all
  • M-a β€” ws_prior
  • M-S-⟨Down⟩ β€” ws_prev_move
  • M-S-⟨Up⟩ β€” ws_next_move
  • M-S-⟨Right⟩ β€” rg_next
  • M-S-⟨Left⟩ β€” rg_prev
  • ⟨unbound⟩ β€” rg_move_next
  • ⟨unbound⟩ β€” rg_move_prev
  • M-s β€” screenshot_all
  • M-S-s β€” screenshot_wind
  • M-S-v β€” version
  • M-t β€” float_toggle
  • M-S-t β€” below_toggle
  • M-S-` β€” free_toggle
  • M-S-⟨Delete⟩ β€” lock
  • M-S-i β€” initscr
  • M-w β€” iconify
  • M-S-w β€” uniconify
  • ⟨unbound⟩ β€” uniconify_quick
  • M-e β€” maximize_toggle
  • M-S-e β€” fullscreen_toggle
  • M-r β€” raise
  • M-S-r β€” always_raise
  • M-v β€” button2
  • M-- β€” width_shrink
  • M-= β€” width_grow
  • M-S-- β€” height_shrink
  • M-S-= β€” height_grow
  • M-[ β€” move_left
  • M-] β€” move_right
  • M-S-[ β€” move_up
  • M-S-] β€” move_down
  • M-S-/ β€” name_workspace
  • M-/ β€” search_workspace
  • M-f β€” search_win
  • M-d β€” debug_toggle (debug mode only)
  • M-S-d β€” dumpwins (debug mode only)

the action names and descriptions are listed below:

  • focus β€” focuses the window/region under the pointer ✨
  • move β€” drags the window around with the pointer for as long as you're holding the binding down
  • resize β€” resizes the window with the pointer while the binding is held
  • resize_centered β€” same whole vibe as resize, but the window stays centered πŸŽ€
  • term β€” spawns a new terminal (peep β€œPROGRAMS” above)
  • menu β€” pops the menu (again, peep β€œPROGRAMS” above)
  • quit β€” bye-bye spectrwm πŸ‘‹
  • restart β€” restarts spectrwm
  • restart_of_day β€” same as restart except the config file gets loaded in full, minus autorun
  • reload β€” reloads the config without restarting, and reinitializes the bar(s) plus bar_action (if you use it)
  • cycle_layout β€” hops to the next layout
  • center_layout β€” toggles centering of the master area
  • flip_layout β€” swaps the master and stacking areas
  • prior_layout β€” back to the last layout you used
  • layout_vertical β€” switches to vertical layout
  • layout_horizontal β€” switches to horizontal layout
  • layout_max β€” switches to max layout
  • layout_floating β€” switches to floating layout
  • stack_reset β€” resets the layout
  • stack_balance β€” balances the master/stacking area βš–οΈ
  • master_shrink β€” shrinks the master area
  • master_grow β€” grows the master area
  • master_add β€” adds windows to the master area
  • master_del β€” removes windows from the master area
  • stack_inc β€” adds columns/rows to the stacking area
  • stack_dec β€” removes columns/rows from the stacking area
  • swap_main β€” sends the current window to the master area
  • focus_next β€” focuses the next window in the workspace
  • focus_prev β€” focuses the previous window in the workspace
  • focus_main β€” focuses the main window in the workspace
  • focus_prior β€” focuses the window you focused last in the workspace
  • focus_free β€” focuses a window in free mode, if there even is one
  • focus_urgent β€” focuses the next window with the urgency hint flag set πŸ‘€ the workspace switches if it has to
  • swap_next β€” swaps with the next window in the workspace
  • swap_prev β€” swaps with the previous window in the workspace
  • bar_toggle β€” toggles overall visibility of the status bars
  • bar_toggle_ws β€” toggles the status bar on the current workspace
  • wind_del β€” deletes the current window
  • wind_kill β€” kills the program that created the current window πŸ’€
  • ws_n β€” switches to workspace n, where n is at least 1
  • mvws_n β€” moves the current window to workspace n, where n is at least 1
  • rg_n β€” focuses region n, where n is at least 1
  • mvrg_n β€” moves the current window to region n, where n is at least 1
  • mvrg_next β€” moves the current window to the workspace in the next region
  • mvrg_prev β€” moves the current window to the workspace in the previous region
  • ws_empty β€” switches to the first empty workspace
  • ws_empty_move β€” switches to the first empty workspace and moves the current window there
  • ws_next β€” switches to the next workspace that actually has a window in it
  • ws_prev β€” switches to the previous workspace that has a window in it
  • ws_next_all β€” switches to the next workspace, period
  • ws_prev_all β€” switches to the previous workspace, period
  • ws_next_move β€” switches to the next workspace, taking the current window with you
  • ws_prev_move β€” switches to the previous workspace, taking the current window with you
  • ws_prior β€” back to the last workspace you visited
  • rg_next β€” switches to the next region
  • rg_prev β€” switches to the previous region
  • rg_move_next β€” goes to the next region and moves the current workspace there
  • rg_move_prev β€” goes to the previous region and moves the current workspace there
  • screenshot_all β€” screenshots the entire screen (if enabled) (see β€œPROGRAMS” above) πŸ“Έ
  • screenshot_wind β€” screenshots the selected window (if enabled) (see β€œPROGRAMS” above)
  • version β€” toggles the version display in the status bar
  • float_toggle β€” toggles the focused window between tiled and floating
  • below_toggle β€” toggles the below state on the current window
  • free_toggle β€” toggles the focused window between workspace mode and free mode
  • lock β€” locks the screen (see β€œPROGRAMS” above) πŸ”’
  • initscr β€” reinitializes the physical screens (see β€œPROGRAMS” above)
  • iconify β€” minimizes (unmaps) the currently focused window
  • uniconify β€” restores (maps) the window returned by your dmenu(1) selection
  • uniconify_quick β€” restores (maps) the window you iconified most recently
  • maximize_toggle β€” toggles maximization of the focused window
  • fullscreen_toggle β€” toggles fullscreen state of the focused window
  • raise β€” raises the current window
  • always_raise β€” when this is set, tiled windows are allowed to obscure floating windows
  • button2 β€” fakes a middle mouse button click (Button2)
  • width_shrink β€” shrinks the width of a floating window
  • width_grow β€” grows the width of a floating window
  • height_shrink β€” shrinks the height of a floating window
  • height_grow β€” grows the height of a floating window
  • move_left β€” moves a floating window one step to the left
  • move_right β€” moves a floating window one step to the right
  • move_up β€” moves a floating window one step upwards
  • move_down β€” moves a floating window one step downwards
  • name_workspace β€” names the current workspace
  • search_workspace β€” searches for a workspace
  • search_win β€” searches the windows in the current workspace
  • debug_toggle β€” toggles the debug overlay (debug mode only) πŸ›
  • dumpwins β€” dumps the current window/focus/stacking state to the debug log (debug mode only)

πŸ› οΈ your own custom bindings, bestie

Custom bindings in the config file go like this:

bind[action] = combo

action is literally one of the actions listed above (or leave it empty to unbind something), and combo is zero or more modifier keys and/or special arguments (Mod1, Shift, Control, MOD, etc.) followed by a normal key (b, Space, etc.) or a button (Button1 .. Button255), all held together with +. And yes β€” multiple key/button combos can be bound to the same action, no cap πŸ’…

the special arguments, iconically

  • MOD β€” gets substituted for the currently defined modkey
  • ANYMOD β€” selects all modifier combinations that aren't handled by another binding
  • REPLAY β€” reprocesses binding press/release events so other programs can handle them too. Unavailable for move, resize and resize_centered 🫢

MOD example

bind[reset] = Mod4+q # bind Windows-key + q to reset
bind[] = Mod1+q # unbind Alt + q
bind[move] = MOD+Button3 # Bind move to M-Button3
bind[] = MOD+Button1 # Unbind default move binding.

ANYMOD example

bind[focus] = ANYMOD+Button3
bind[move] = MOD+Button3

In the example above, M+Button3 kicks off move, and Button3 pressed with literally any other combination of modifiers sets focus to the window/region under the pointer ✨

REPLAY example

bind[focus] = REPLAY+Button3

In this one, when Button3 is pressed without any modifier(s), focus gets set to the window under the pointer and the button press gets passed through to the window 🫢


So here's the tea on non-latin characters: if you wanna bind something like Γ₯ or Ο€, you have to type the xkb character name instead of the character itself. Run xev(1), focus the window, press that specific key, and read the symbol name in the terminal output. Here's the example for Γ₯:

KeyPress event, serial 41, synthetic NO, window 0x2600001,
    root 0x15a, subw 0x0, time 106213808, (11,5), root:(359,823),
    state 0x0, keycode 24 (keysym 0xe5, aring), same_screen YES,
    XLookupString gives 2 bytes: (c3 a5) "Γ₯"
    XmbLookupString gives 2 bytes: (c3 a5) "Γ₯"
    XFilterEvent returns: False

See how the xkb name is aring? So in other words, in spectrwm.conf you'd add:

bind[program] = MOD+aring

And if you wanna clear out all the default keyboard bindings and roll with only your own, go look at the keyboard_mapping option πŸ‘‘


⌨️ KEYBOARD MAPPING FILES ⌨️

Okay so listen β€” there are keyboard mapping files for a bunch of keyboard layouts, and they're listed right here. You use them with the keyboard_mapping setting to load pre-defined key bindings for whichever layout you've got 🌍

  • spectrwm_cz.conf β€” Czech Republic keyboard layout
  • spectrwm_es.conf β€” Spanish keyboard layout
  • spectrwm_fr.conf β€” French keyboard layout
  • spectrwm_fr_ch.conf β€” Swiss French keyboard layout
  • spectrwm_se.conf β€” Swedish keyboard layout
  • spectrwm_us.conf β€” United States keyboard layout

✨ QUIRKS ✨

Okay so spectrwm has a whole quirks system, and it’s genuinely iconic for handling windows that need special treatment in a tiling window manager β€” think certain dialogs and fullscreen apps. It’s giving β€œmain character windows get their own rules,” and honestly? Slay. πŸ’…

Here are the default quirks, no cap:

.*:.*:.*:splash,dialog                  FLOAT
.*:.*:.*:toolbar,utility                FLOAT + ANYWHERE
.*:.*:.*:notification                   FLOAT + ANYWHERE +
                                        MINIMALBORDER +
                                        NOFOCUSONMAP
Firefox-bin:firefox-bin                 TRANSSZ
Firefox:Dialog                          FLOAT
Gimp:gimp                               FLOAT + ANYWHERE
MPlayer:xv                              FLOAT + FULLSCREEN +
                                        FOCUSPREV
OpenOffice.org 2.4:VCLSalFrame          FLOAT
OpenOffice.org 3.1:VCLSalFrame          FLOAT
pcb:pcb                                 FLOAT
xine:Xine Window                        FLOAT + ANYWHERE
xine:xine Panel                         FLOAT + ANYWHERE
xine:xine Video Fullscreen Window       FULLSCREEN + FLOAT
Xitk:Xitk Combo                         FLOAT + ANYWHERE
Xitk:Xine Window                        FLOAT + ANYWHERE
XTerm:xterm                             XTERM_FONTADJ

πŸŽ€ The Quirks Themselves πŸŽ€

Now the quirks themselves, one by one, bestie:

  • ANYWHERE β€” lets the window position itself, uncentered. It’s giving β€œI know where I belong.” ✨
  • BELOW β€” puts the window into below state as soon as it gets managed.
  • FLOAT β€” this window should not be tiled; let it float freely, like the free spirit it is. πŸ¦‹
  • FOCUSONMAP_SINGLE β€” when the window first appears on the screen, change focus to it if there are no other windows on the workspace with the same WM_CLASS class/instance value. Has no effect when focus_mode is set to follow.
  • FOCUSPREV β€” on exit, force focus on the previously focused application, not the previous application in the stack.
  • FULLSCREEN β€” removes the border so the window can use the full region size. Big β€œedge-to-edge” energy.
  • ICONIFY β€” hides/minimizes the window upon being managed.
  • IGNOREPID β€” ignores the PID when determining the initial workspace for a new window. Especially useful for terminal windows that share a process.
  • IGNORESPAWNWS β€” ignores the spawn workspace when determining the initial workspace for a new window.
  • IGNOREURGENT β€” ignores the urgency hint. Not today, urgency.
  • MAXIMIZE β€” puts the window into maximized state upon being managed.
  • MINIMALBORDER β€” removes the border when the window is unfocused and floating.
  • NOFOCUSCYCLE β€” removes the window from the normal focus cycle (focus_prev or focus_next). It can still be focused using search_win.
  • NOFOCUSONMAP β€” do not change focus to the window when it first appears on the screen. Has no effect when focus_mode is set to follow.
  • NOFOCUSPOINTER β€” do not focus the window via pointer interaction. It can still be focused using key bindings.
  • OBEYAPPFOCUSREQ β€” when an application requests focus on the window via a _NET_ACTIVE_WINDOW client message (source indication of 1), comply with the request. Note that a source indication of 0 (unspecified) or 2 (pager) are always obeyed.
  • TRANSSZ β€” adjusts size on transient windows that are too small using dialog_ratio (see β€œCONFIGURATION FILES”).
  • WS[n] β€” forces a new window to appear on workspace n. Specify -1 to put the window into free mode so that it is mapped independent of workspaces and regions.
  • XTERM_FONTADJ β€” adjusts xterm(1) fonts when resizing. Note that this requires the xterm_fontadj spawn flag to be set on the autorun/program entry when the program is spawned. See the spawn_flags option for info on how to enable it.
  • NOTILE β€” disallows the window from being tiled. Note that the window will always float regardless of whether _NET_WM_STATE_ABOVE is set.

Custom Quirks, Bestie πŸ’–

Custom quirks in the configuration file are specified as follows:

quirk[class[:instance[:name[:type]]]] {=|+=|-=} quirk [+ quirk
...]

class, instance (optional), name (optional), and type (optional) are used to determine which window(s) the quirk(s) apply to. class and instance are regex search patterns for the respective fields of the WM_CLASS window property. name is a regex search pattern for the window name (WM_NAME/_NET_WM_NAME.) type is a comma-separated list of zero or more of the following window types (_NET_WM_WINDOW_TYPE): desktop, dock, toolbar, menu, utility, splash, dialog, dropdown_menu, popup_menu, tooltip, notification, combo, dnd, and normal. Leave this field blank to match any window type. quirk is one of the quirks from the list above.

When a window is managed, quirk entries are applied in the order specified in the configuration file. The assignment operator determines how the quirks are applied. When assigning quirks with =, quirks are replaced on matching windows. To add or remove quirks, assign them with += or -= instead.

Note that patterns are interpreted as POSIX Extended Regular Expressions. Any ':', '[' or ']' must be escaped with '\'. See regex(7) for more information on POSIX Extended Regular Expressions.

For example:

quirk[MPlayer] = FLOAT + FULLSCREEN + FOCUSPREV # Float all windows having a class of 'MPlayer'
quirk[.*] = FLOAT # Float all windows by default.
quirk[.*:.*:.*] = FLOAT # Same as above.
quirk[firefox:Navigator] = FLOAT # Float all Firefox browser windows.
quirk[::Console] = FLOAT # Float windows with WM_CLASS not set and a window name of 'Console'.
quirk[\[0-9\].*:.*:\[\[\:alnum\:\]\]*] = FLOAT # Float windows with WM_CLASS class beginning with a number, any WM_CLASS instance and a _NET_WM_NAME/WM_NAME either blank or containing alphanumeric characters without spaces.
quirk[pcb:pcb] = NONE # Remove the default quirk entry.
quirk[.*:ws10] += WS[10] # Force windows with a WM_CLASS name of 'ws10' to workspace 10 without removing existing quirks.
quirk[.*:.*:.*:splash,dialog] = FLOAT + ANYWHERE # Override default quirk entry.

You can obtain class, instance and name by running xprop(1) and then clicking on the desired window. In the following example the main window of Firefox was clicked:

$ xprop | grep -E "^(WM_CLASS|_NET_WM_NAME|WM_NAME)"
WM_CLASS(STRING) = "Navigator", "Firefox"
WM_NAME(STRING) = "spectrwm - ConformalOpenSource"
_NET_WM_NAME(UTF8_STRING) = "spectrwm - ConformalOpenSource"

Note that xprop(1) displays WM_CLASS as:

WM_CLASS(STRING) = "<instance>", "<class>"

In the example above the quirk entry would be:

quirk[Firefox:Navigator] = FLOAT

spectrwm also automatically assigns quirks to windows based on the value of the window’s _NET_WM_WINDOW_TYPE property as follows:

_NET_WM_WINDOW_TYPE_TOOLBAR          FLOAT + ANYWHERE
_NET_WM_WINDOW_TYPE_UTILITY          FLOAT + ANYWHERE
_NET_WM_WINDOW_TYPE_SPLASH           FLOAT
_NET_WM_WINDOW_TYPE_DIALOG           FLOAT

In all other cases, no automatic quirks are assigned to the window. Quirks specified in the configuration file override the automatic quirks. Periodt. πŸ’…βœ¨

🌈 EWMH 🌈

okay so spectrwm partially implements the Extended Window Manager Hints (EWMH) specification, and that's literally how external scripts and programs can control windows and spectrwm itself. How? spectrwm responds to certain ClientMessage events. From the terminal you can send these events conveniently with tools like wmctrl(1) and xdotool(1). For the actual format of these ClientMessage events, check the EWMH specification πŸ’…

The id of the currently focused window is stored in the _NET_ACTIVE_WINDOW property of the root window. This can be used, for example, to retrieve the title of the currently active window with xprop(1) and grep(1):

$ WINDOWID=`xprop -root _NET_ACTIVE_WINDOW | grep -o "0x.*"`
$ xprop -id $WINDOWID _NET_WM_NAME | grep -o "\".*\""

A window can be focused by sending a _NET_ACTIVE_WINDOW client message to the root window. For example, using wmctrl(1) to send the message (assuming 0x4a0000b is the id of the window to be focused):

$ wmctrl -i -a 0x4a0000b

Windows can be closed by sending a _NET_CLOSE_WINDOW client message to the root window. For example, using wmctrl(1) to send the message (assuming 0x4a0000b is the id of the window to be closed):

$ wmctrl -i -c 0x4a0000b

Windows can be floated and un-floated by adding or removing the _NET_WM_STATE_ABOVE atom from the _NET_WM_STATE property of the window. This can be achieved by sending a _NET_WM_STATE client message to the root window. For example, the following toggles the floating state of a window using wmctrl(1) to send the message (assuming 0x4a0000b is the id of the window to be floated or un-floated):

$ wmctrl -i -r 0x4a0000b -b toggle,above

Windows can also be iconified and un-iconified by substituting _NET_WM_STATE_HIDDEN for _NET_WM_STATE_ABOVE in the previous example:

$ wmctrl -i -r 0x4a0000b -b toggle,hidden

Floating windows can also be resized and moved by sending a _NET_MOVERESIZE_WINDOW client message to the root window. For example, using wmctrl(1) to send the message (assuming 0x4a0000b is the id of the window to be resize/moved):

$ wmctrl -i -r 0x4a0000b -e 0,100,50,640,480

This moves the window to (100,50) and resizes it to 640x480.

🫢 bestie, important caveat: if a window has been manually positioned via binding, _NET_MOVERESIZE_WINDOW requests are ignored unless the window has the ANYWHERE quirk, the workspace is in floating layout, or the window is workspace-free. Requests are also ignored on maximized and fullscreen windows. no cap.

🧚 SWMHACK 🧚

When spawning a program via an autorun or program entry without the nospawnws flag, spectrwm aims to place the program's windows (if any) in its spawn workspace. To accomplish this "spawn-in-workspace" behavior, spectrwm must determine the intended spawn workspace when managing a new window. Since it cannot be done with X11 alone, libswmhack.so is included to make this feature possible ✨

When a program is spawned, spectrwm automatically sets LD_PRELOAD and _SWM_WS in the program's spawn environment to enable libswmhack.so when it is executed. Note that LD_PRELOAD is the path to libswmhack.so and _SWM_WS is the spawn workspace for any windows created by the program.

When running programs from terminals, scripts, etc, the inherited environment may need to be configured. It is possible to override the spawn workspace by setting _SWM_WS to a different value. Alternatively, _SWM_WS can be unset(1) or set to a blank value to disable "spawn-in-workspace" behavior. Note that workspaces are counted from 0. β€˜-1’ can be specified to put windows into workspace-free mode.

For example, to play a video with mpv(1) on workspace 10 without changing the spawn workspace in the environment:

$ _SWM_WS=9 mpv video.mkv

Play the video in free mode so that it remains mapped when switching workspaces.

$ _SWM_WS=-1 mpv video.mkv

Disable "spawn-in-workspace" in the environment so that new windows map on whichever workspace happens to be focused.

$ unset _SWM_WS

Change the environment to spawn programs in free mode.

$ export _SWM_WS=-1

When spawning a program that creates windows via a daemon, ensure the daemon is started with the correct LD_PRELOAD in its environment.

For example, when starting urxvtd(1) via xinit(1), LD_PRELOAD must be specified.

LD_PRELOAD=/usr/lib/libswmhack.so.0.0 urxvtd -q -o -f
πŸ’€ note that some operating systems may ignore LD_PRELOAD if certain conditions are not met. It is advised to check the man page of ld.so.

In situations where libswmhack.so cannot be used, it is possible to use a quirk to spawn a program in a specific workspace.

e.g. launch an xterm(1) in workspace 2 on startup:

quirk[XTerm:ws2] += WS[2]
autorun = ws[2]:xterm -name ws2

Launch a chromium(1) window in workspace 3 on startup:

quirk[Chromium:chromium:ws3] += WS[3]
autorun = ws[3]:chromium --window-name="ws3" --new-window

If the "spawn-in-workspace" behavior is not desired, it is possible to disable it before programs are spawned by setting the nospawnws spawn flag on spawn entries via the spawn_flags option:

# Make 'nospawnws' the default for any autorun/program entries that are
# added/replaced below this line in the configuration file:
spawn_flags = nospawnws
program[pcmanfm] = pcmanfm -n  # 'nospawnws' is set
autorun = ws[1]:firefox        # ws[1] is ignored since 'nospawnws' is set
program[lock] = xlock          # the replaced default entry has 'nospawnws' set

# Add 'nospawnws' to an existing entry:
spawn_flags[term] += nospawnws

Alternatively, the IGNORESPAWNWS and IGNOREPID quirks can be applied to windows:

# Disable spawn-in-workspace on PCManFM windows:
quirk[Pcmanfm] = IGNORESPAWNWS

# Disable spawn-in-workspace on all windows, including those spawned via autorun:
quirk[.*] += IGNORESPAWNWS + IGNOREPID
😭 also: XCB programs that roll their own X11 requests (e.g. Chromium) are currently unsupported by libswmhack.so.

🚨 SIGNALS 🚨

Sending spectrwm a HUP signal will restart it. USR1 will reload the configuration without restarting and reinitialize the bar(s) along with bar_action (if used). slay, low-effort reload energy πŸ’…


πŸ“ FILES πŸ“

  • ~/.spectrwm.conf β€” spectrwm user specific settings.
  • /etc/spectrwm.conf β€” spectrwm global settings.

🌸 HISTORY 🌸

spectrwm was inspired by xmonad & dwm. iconic lineage tbh 🫢


πŸ‘‘ AUTHORS πŸ‘‘

spectrwm was written by:

  • Marco Peereboom ⟨marco@peereboom.us⟩
  • Ryan Thomas McBride ⟨mcbride@countersiege.com⟩
  • Darrin Chandler ⟨dwchandler@stilyagin.com⟩
  • Pierre-Yves Ritschard ⟨pyr@spootnik.org⟩
  • Tuukka Kataja ⟨stuge@xor.fi⟩
  • Jason L. Wright ⟨jason@thought.net⟩
  • Reginald Kennedy ⟨rk@rejii.com⟩
  • Lawrence Teo ⟨lteo@lteo.net⟩
  • Tiago Cunha ⟨tcunha@gmx.com⟩
  • David Hill ⟨dhill@mindcry.org⟩

okay bestie, that's the whole page β€” source/version: Debian, dated August 26, 2025, and yeah, SPECTRWM(1) stays main character energy πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from
  • alpine 3.24: spectrwm-doc 3.7.0-r1 Β· ISC
  • nixos 26.05: spectrwm 3.7.0
  • nixpkgs unstable: spectrwm 3.7.0
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms