Skip to content

Configuration

Kenan Pelit edited this page Sep 9, 2026 · 6 revisions

Configuration

margo reads ~/.config/margo/config.conf — plain key = value, hot-reloadable with mctl reload (or Super+Ctrl+R). Everything has a sane built-in default, so you only set what you want to change.

mctl reload          # re-read the config in place — no logout
mctl check-config    # validate offline; exits 1 on any error (unknown keys,
                     # regex errors, duplicate/shadowed binds, include loops)
mctl actions --verbose   # the always-current dispatch-action catalogue

Full annotated reference: every knob with inline commentary lives at https://kenanpelit.github.io/margo/config-reference/, rendered from margo/src/config.example.conf (also installed at /usr/share/doc/margo-git/config.example.conf). This page is the structured guide to the high-traffic options.

Includes & multi-file configs

include = keybinds.conf                 # single file
include = rules.conf
source  = ~/.config/margo/conf.d/*.conf # glob, lex order

mctl reload re-reads the entire tree.

Layouts

margo ships 11 layouts — 9 partition-style tiling algorithms plus floating and mosaic for non-partition desktops — and a separate zoom-out overview mode. Each tag remembers its own. Set one with setlayout <name>, or cycle with switch_layout.

setlayout name Layout Description
tile Tile dwm classic — master + stack
scroller Scroller PaperWM-style horizontal column scroller (the default)
grid Grid equal-area grid
monocle Monocle one window fills the area; siblings hidden
deck Deck master + stacked tabs
center_tile Center tile master centred, stacks left + right
right_tile Right tile master pane on the right
tgmix TG-mix tile / grid hybrid
dwindle Dwindle recursive split (Hyprland default)
floating Floating classic stacking desktop — windows auto-float with a cascade
mosaic Mosaic GNOME's content-aware self-arranging concept — windows keep their own size, drag one onto another to swap, overflow moves to an empty tag (or stacks in the corner, see below)
overview Overview zoom-out of all tags — usually via toggle_overview
default_layout = scroller          # any tag without a tagrule uses this
circle_layout  = scroller, tile, center_tile, grid, deck, monocle, mosaic

bind = super, t, setlayout, tile   # set the current tag's layout
bind = super, e, switch_layout     # cycle circle_layout
tagrule = id:9, layout_name:monocle

Mosaic-specific knobs: drag_tile_to_tile (drag one window onto another to swap places), mosaic_auto_overflow_tag (a window that no longer fits even at its own minimum size moves itself to the first empty tag), and mosaic_overflow_stack (instead of moving tags, shrink it to a small always-visible "peek" in the corner).

Per-tag precedence: taglayout > tagrule layout_name > default_layout. A manual setlayout is never clobbered by a reload.

Master / stack tuning

Key Default Meaning
default_mfact 0.55 master pane fraction (0.05–0.95)
default_nmaster 1 windows in the master area
new_is_master 0 1 = new windows take the master slot
center_master_overspread 0 center_tile: master may overrun the stacks
center_when_single_stack 1 center_tile: centre master with one stack
bind = super,       i, incnmaster, +1
bind = super,       d, incnmaster, -1
bind = super,       h, setmfact,   -0.05
bind = super,       l, setmfact,   +0.05
bind = super,       g, togglegaps
bind = super+shift, g, incgaps,    +4

Scroller options

Key Default Meaning
scroller_default_proportion 0.800 column width when ≥2 columns are visible
scroller_default_proportion_single 0.800 width when one column shows
scroller_ignore_proportion_single 0 ignore the *_single value
scroller_focus_center 1 auto-centre the focused column
scroller_prefer_center 1 open new columns near the focused one
scroller_prefer_overspread 0 let columns exceed the monitor width
edge_scroller_pointer_focus 1 edge pointer scrolls + re-focuses
scroller_proportion_preset 1.000, 0.800, 0.618, 0.500 switch_proportion_preset cycle (Φ = 0.618)
bind = super, r, set_proportion, 0.618
bind = super, p, switch_proportion_preset

Dispatch actions

Bind these to a key (bind), button (mousebind), or gesture (gesturebind), or run them live with mctl dispatch <action> [args]. Comma-separated aliases are interchangeable. Generated from the same source as mctl actions --verbose.

Tags / workspaces

Action Arg Description
view <MASK> Switch to tag(s) by bitmask. Same tag twice toggles back when view_current_to_back = 1. Mask = 1<<(tag-1).
toggleview <MASK> Add/remove a tag from the active set.
tag, tagsilent <MASK> Move the focused window to tag(s); stay on the current tag.
tagview, movetagview <MASK> Move the focused window and follow it.
toggletag <MASK> Add/remove a tag from the window's mask.
tagall Show every tag at once.
viewtoleft / viewtoright Cycle to the previous / next occupied tag.
tagtoleft / tagtoright Move the window to the previous / next tag.

Focus

Action Arg Description
focusstack, focusdir <DIR> Move focus next/prev (1/-1) or directional.
exchange_client, smartmovewin <DIR> Swap the focused window with its neighbour.
focusmon <DIR> Focus another monitor.
zoom Promote the focused window to master.

Layout

Action Arg Description
setlayout <NAME> Switch the current tag's layout by name.
switch_layout Cycle the circle_layout list.
incnmaster <DELTA> Change the master-slot count.
setmfact <DELTA> Adjust the master factor (clamped 0.05–0.95).
togglegaps Toggle layout gaps.
incgaps <DELTA> Resize gaps by px.
set_proportion <RATIO> Scroller: set the focused column width (0.1–1.0).
switch_proportion_preset Scroller: cycle scroller_proportion_preset.

Window

Action Arg Description
togglefloating Tiled ↔ floating.
togglefullscreen Work-area fullscreen (bar visible).
togglefullscreen_exclusive Exclusive fullscreen (bar hidden) — mpv / games.
sticky_window, togglesticky Pin to every tag on the monitor; press again to restore.
killclient Close the focused window.
movewin <DX> <DY> Move by px (forces floating).
resizewin <DW> <DH> Resize by px (forces floating; min 50×50).
moveresize curmove|curresize Interactive pointer move/resize — for mousebind.
tagmon <DIR> Move the window to an adjacent monitor.
disable_output / enable_output / toggle_output <NAME> Soft-disable / re-enable / toggle an output (dock/undock).

Scratchpad

Action Arg Description
toggle_named_scratchpad <APPID> <TITLE|none> <SPAWN> Show/hide a named scratchpad; spawn if absent.
summon, bring_here <APPID> <TITLE|none> <SPAWN> [OP] Bring a match to the current tag, or launch it. Repeated presses cycle through matches. OP (4th field) combines appid+title: and (default) / or / difference.
focusapp, raiseapp <APPID> <TITLE|none> <SPAWN> [OP] Run-or-raise: focus the app where it is (switch to its tag), cycling; launch if none. Same matching/OP as summon.
toggle_scratchpad Toggle anonymous scratchpads on the focused monitor.
unscratchpad, exit_scratchpad Reset the window's scratchpad/floating/fullscreen state.

Overview

Action Arg Description
toggle_overview Enter/leave the zoom-out overview (also hot corner / 4-finger swipe).
overview_focus_next / overview_focus_prev alt+Tab / alt+shift+Tab thumbnails.
overview_activate Commit the selection (Enter/Esc).

System

Action Arg Description
spawn <COMMAND> Run a shell command (sh -c).
sendkey <COMBO>[,<APPID-REGEX>][,<FALLBACK>] Inject a synthetic key combo into the focused window; optional app-id gate + fallback action.
cyclekblayout, cycle_kb_layout Cycle to the next configured xkb keyboard layout.
run_script, rhai-eval <PATH> Evaluate a Rhai script live.
screenshot / screenshot-window / screenshot-region / screenshot-region-ui Capture output / window / region (last also copies) → editor → file.
reload, reload_config Reload config.conf in place.
theme, set_theme <preset> Live-swap preset: default / minimal / gaudy.
session_save / session_load Save / restore per-monitor tag + layout state.
setkeymode <MODE> Switch keymode (vim-like mode sets).
force_unlock Tear down a stuck ext_session_lock.
quit Exit the compositor cleanly.
debug_dump, diagnose Dump compositor state to the log.

Keybindings

bind = MODIFIERS, KEY, ACTION[, ARG[, ARG…]]
  • Modifiers: super, ctrl, alt, shift, or compound (super+ctrl); NONE for unmodified keys.
  • Key: keysym name (q, Return, Print, XF86AudioPlay).
  • Action: any entry from the catalogue above.
bind = super,       Return, spawn, kitty
bind = super,       q,      killclient
bind = super,       space,  togglefloating
bind = super,       1,      view, 1
bind = super+shift, 1,      tag,  1
bind = super+ctrl,  r,      reload_config

mousebind = super, btn_left,  moveresize, curmove
mousebind = super, btn_right, moveresize, curresize

mctl check-config flags shadowed/duplicate binds offline.

Gestures

Touchpad / touchscreen swipes map to dispatch actions with gesturebind, the same way keys map with bind:

gesturebind = MODIFIERS, MOTION, FINGERS, ACTION[, ARG[, ARG…]]
  • Modifiers: held keyboard modifiers (super, …) or NONE.
  • Motion: four cardinals up / down / left / right and four diagonals up_left / up_right / down_left / down_right. A swipe counts as diagonal only when clearly at an angle (both axes > 40 % of the travel); otherwise it snaps to the nearest cardinal, so diagonal binds never steal a straight swipe.
  • Fingers: 3 or 4.
  • Action: any dispatch action above; trailing fields are its args. Swipes shorter than swipe_min_threshold px are ignored.

Niri/Mango-style set — 3 fingers within a monitor, 4 fingers between tags and monitors:

# 3 fingers — horizontal: focus windows; vertical: browser-tab cycle (app-gated
# sendkey) falling back to window focus
gesturebind = NONE, left,  3, focusdir, left
gesturebind = NONE, right, 3, focusdir, right
gesturebind = NONE, up,    3, sendkey, ctrl+shift+Tab, ^(firefox|chrome.*|brave.*)$, focusdir:up
gesturebind = NONE, down,  3, sendkey, ctrl+Tab,       ^(firefox|chrome.*|brave.*)$, focusdir:down

# 4 fingers — horizontal: tag nav; vertical: overview; up-diagonal: roam monitors
gesturebind = NONE, left,      4, viewtoleft
gesturebind = NONE, right,     4, viewtoright
gesturebind = NONE, up,        4, toggle_overview
gesturebind = NONE, down,      4, toggle_overview
gesturebind = NONE, up_left,   4, focusmon, left
gesturebind = NONE, up_right,  4, focusmon, right

Mouse buttons bind with mousebind, the scroll wheel with axisbind:

mousebind = super, btn_left, moveresize, curmove
axisbind  = super, UP,       focusdir,   left   # Super + wheel → roam columns

Window rules

Match by appid regex, title regex, or both (exclude_appid / exclude_title negate). Regexes are anchored ^…$ by convention; prefix (?i) for case-insensitive.

windowrule = isfloating:1, appid:^pavucontrol$
windowrule = isfloating:1, width:800, height:560, appid:^org\.keepassxc\.KeePassXC$
windowrule = tags:1,   appid:^firefox$
windowrule = block_out_from_screencast:1, appid:^(KeePassXC|1Password)$
windowrule = isnamedscratchpad:1, appid:^kitty-scratch$

Debug without running margo:

mctl rules --appid firefox --title "" --verbose   # Match / Reject(reason) per rule

Tag rules

tagrule = id:1, layout_name:scroller, monitor_name:DP-3   # layout + home monitor
tagrule = id:9, layout_name:monocle
tagrule = id:5, wallpaper:/home/kenan/wall/lake.jpg       # per-tag wallpaper hint

monitor_name: pins the tag to an output — view N warps focus there, and windowrules targeting tags:N inherit that monitor.

Layer rules

Match the layer-shell namespace (regex) — bars, OSDs, launchers.

layerrule = noanim:1, namespace:^waybar$
layerrule = animation_type_open:slide_left, animation_type_close:slide_left, namespace:^rofi$

See also