PálcikaWM VI. : Herbstluftwm

enlightened Ez az oldal a közösségért készül. heart Kövess minket máshol is:  Linux Mint Magyar Közösség a Mastodon-on  Telegram csatorna – csak hírek  Beszélgessünk a Telegram – Linux csevegő csoport  Hírek olvasása RSS segítségével  Linux Mint Hivatalos Magyar Közösség a Facebook-on      Linux Mint Baráti Kör a Facebook-on
wink Ha hasznosnak találod, és szeretnéd, hogy folytatódjon, támogasd a munkát Ko-fi vagy Paypal segítségével. laugh

A herbstluftwm egy rendkívül rugalmas, erőforrás kímélő, manuális csempéző ablakkezelő az X11-hez. Legfőbb filozófiai jellemzője, hogy nincs hagyományos statikus konfigurációs fájlja, a teljes beállítás futásidejű (runtime) parancsokon keresztül történik a  herbstclient  nevű segédprogram segítségével. A konfiguráció lényegében egy shell szkript (autostart), amely indításkor herbstclient parancsok sorozatát hajtja végre.

Először tisztázzuk a herbstluftwm fogalmait:

- Tag-ek (Címkék / Virtuális asztalok): A virtuális asztalokat "tag"-eknek hívjuk. Minden asztal egy önálló elrendezési fát (layout tree) és az azon lévő ablakokat (klienseket) tartalmazza. Az összes asztal egy közös készletben van, amelyet a virtuális monitorok megoszthatnak.
- Frame-ek (Keretek) és Layout (Elrendezés): Az elrendezés egy bináris fát alkot, egy keret (frame) kétféle lehet. (1. Tartalmazó: Ablakokat (klienseket) tartalmaz, amelyeket az aktuális layout algoritmus szerint rendez el ( vertical ,  horizontal ,  max ,  grid ). (2. Osztott: Két alkeretre (subframe) van osztva vízszintesen vagy függőlegesen, egy megadott arányban (fraction, pl. 0.5 = 50%).
- Kliensek (Ablakok): Minden ablak a csempézett (tiling) rétegben vagy a lebegő (floating) rétegben helyezkedik el. A lebegő ablakok a csempézett réteg felett jelennek meg, és szabadon mozgathatók.
- Monitorok: A képernyőterület szabadon felosztható virtuális monitorokra, amelyek nem feltétlenül egyeznek meg a fizikai hardver elrendezéssel. Ez lehetővé teszi, hogy egy nagy felbontású monitoron egyszerre két asztal tartalmát is lásd.

A képernyő egy bináris fába van szervezve. A gyökér (root) egy keret, amelyet két részre oszthatsz (`split`). Minden keret vagy tovább osztható, vagy ablakokat tartalmaz:

- `split vertical 0.5`: A jelenlegi keretet függőlegesen két egyenlő részre osztja (bal-jobb).
- `split horizontal 0.5`: Vízszintesen osztja (fent-lent).
- `split explode`: Intelligens: a jelenlegi ablak kivételével mindent új keretbe tesz.
- `remove`: Törli az aktuális keretet és eggyé olvasztja a szülővel.

A fa-struktúra miatt nincs "oszlop" vagy "sor" fogalom, minden felosztás egy új ág a fában.

Egy kereten belül az ablakok elrendezésének lehetőségei:

- `vertical`: Ablakok egymás alatt (alapértelmezett).
- `horizontal`: Ablakok egymás mellett.
- `max`: Csak az aktív ablak látszik (tab-szerű).
- `grid`: Rácsos elrendezés.

Ezeket a `cycle_layout` váltja, vagy `set_layout` paranccsal állíthatod.

A konfiguráció kizárólag a `herbstclient` (gyakran `hc` alias-szal) parancsokon keresztül történik. Nézzük az enyémet (~/.config/herbstluftwm/autostart):

#!/usr/bin/env bash
# Berus ~/.config/herbstluftwm/autostart

# Segédfüggvény a herbstclient hívások egyszerűsítésére és rövidebbé tételére
hc() {
    herbstclient "$@"
}

# Értesítés (hook) küldése a panelnek vagy egyéb scripteknek az újratöltésről
hc emit_hook reload

# Háttérszín beállítása (ha nincs panel, vagy amíg a panel betölt)
xsetroot -solid '#2A2A2A'

# ==========================================
# 1. MÓDOSÍTÓ GOMB (MODIFIER) BEÁLLÍTÁSA
# ==========================================
# Mod1 = Alt, Mod4 = Super (Windows gomb).
Mod=Mod4

# ==========================================
# 2. GYORSBILLENTYŰK (KEYBINDINGS) TÖRLÉSE ÉS ÚJRADEFINIÁLÁSA
# ==========================================
hc keyunbind --all # Töröljük az alapértelmezetteket a tiszta lap érdekében

# Rendszervezérlés
hc keybind $Mod-Shift-e quit                   # WM bezárása
hc keybind $Mod-Shift-r reload                 # Konfiguráció újratöltése
hc keybind $Mod-q close                        # Fókuszált ablak bezárása
hc keybind $Mod-Return spawn kitty             # Terminál indítása
hc keybind $Mod-d spawn rofi -show drun        # Program indító
hc keybind Print spawn ~/.local/bin/scrot.sh   # Képernyőkép

# ==========================================
# 3. TAG-EK (VIRTUÁLIS ASZTALOK) KEZELÉSE
# ==========================================
TAG_NAMES=( {1..9} )
TAG_KEYS=( {1..9} 0 ) # Az 1-9 és a 0 gombokhoz rendeljük a tag-eket

# Az alapértelmezett "default" tag átnevezése "1"-re
hc rename default "${TAG_NAMES[0]}" || true
for i in "${!TAG_NAMES[@]}"; do
    hc add "${TAG_NAMES[$i]}"
    key="${TAG_KEYS[$i]}"
    if [ -n "$key" ]; then
        # Ugrás a kiválasztott tag-re
        hc keybind "$Mod-$key" use_index "$i"
        # Fókuszált ablak áthelyezése a tag-re és ugrás oda
        hc keybind "$Mod-Shift-$key" move_index "$i"
    fi
done

# ==========================================
# 4. ELRENDEZÉS (LAYOUT) ÉS FRAME KEZELÉS
# ==========================================
# Frame elrendezés váltása a fókuszált keretben 
hc keybind $Mod-space cycle_layout 1

# Keret felosztása (0.5 = 50% arány)
hc keybind $Mod-u split vertical 0.5    # Függőleges osztás (fel/le)
hc keybind $Mod-o split horizontal 0.5  # Vízszintes osztás (bal/jobb)

# Keret eltávolítása (összevonás a szomszédos kerettel)
hc keybind $Mod-r remove

# ==========================================
# 5. ABLAKOK MOZGATÁSA ÉS ÁTMÉRETEZÉSE (Vim-szerű navigáció)
# ==========================================
# Fókusz váltása a keretek között
hc keybind $Mod-h focus left
hc keybind $Mod-j focus down
hc keybind $Mod-k focus up
hc keybind $Mod-l focus right
hc keybind $Mod-Left  focus left
hc keybind $Mod-Down  focus down
hc keybind $Mod-Up    focus up
hc keybind $Mod-Right focus right

# Ablak áthelyezése a szomszédos keretbe
hc keybind $Mod-Shift-h shift left
hc keybind $Mod-Shift-j shift down
hc keybind $Mod-Shift-k shift up
hc keybind $Mod-Shift-l shift right
hc keybind $Mod-Shift-Left  shift left
hc keybind $Mod-Shift-Down  shift down
hc keybind $Mod-Shift-Up    shift up
hc keybind $Mod-Shift-Right shift right

# Keret átméretezése (lépésköz: 5%)
RESIZESTEP=0.05
hc keybind $Mod-Control-h resize left +$RESIZESTEP
hc keybind $Mod-Control-j resize down +$RESIZESTEP
hc keybind $Mod-Control-k resize up +$RESIZESTEP
hc keybind $Mod-Control-l resize right +$RESIZESTEP
hc keybind $Mod-Control-Left  resize left +$RESIZESTEP
hc keybind $Mod-Control-Down  resize down +$RESIZESTEP
hc keybind $Mod-Control-Up    resize up +$RESIZESTEP
hc keybind $Mod-Control-Right resize right +$RESIZESTEP

# ==========================================
# 6. ABLAK ÁLLAPOTOK (FLOATING, FULLSCREEN, PSEUDOTILE)
# ==========================================
hc keybind $Mod-s floating toggle        # Lebegő mód ki/bekapcsolása az aktuális tag-en
hc keybind $Mod-f fullscreen toggle      # Teljes képernyős mód
hc keybind $Mod-p pseudotile toggle      # Pszeudo-csempézés

# ==========================================
# 7. EGÉR VEZÉRLÉS (MOUSEBINDINGS)
# ==========================================
hc mouseunbind --all
hc mousebind $Mod-Button1 move           # Bal gomb + Mod: ablak mozgatása
hc mousebind $Mod-Button2 resize         # Középső gomb + Mod: ablak átméretezése
hc mousebind $Mod-Button3 zoom           # Jobb gomb + Mod: ablak maximalizálása a keretben

# ==========================================
# 8. MEGJELENÉS ÉS SZÍNEK (THEME)
# ==========================================
hc set frame_border_active_color '#83b8e7'   # Aktív keret színe
hc set frame_border_normal_color '#101010'   # Inaktív keret színe
hc set frame_bg_transparent 1                # Keret háttere átlátszó
hc set frame_border_width 1                  # Keret szegélyvastagsága
hc set window_border_width 2                 # Ablak szegélyvastagsága
hc set window_border_normal_color '#215668'  # Inaktív ablak szegélye
hc set window_border_active_color '#83b8e7'  # Aktív ablak szegélye
hc set always_show_frame 1                   # Mindig mutassa a kereteket (segít a navigációban)
hc set window_gap 4                          # Rés az ablakok között (pixel)

# ==========================================
# 9. ABLAK SZABÁLYOK (RULES)
# ==========================================
hc unrule -F # Összes meglévő szabály törlése újratöltéskor

# Alapértelmezett: ne adjon fókuszt az új ablakoknak (kivéve, ha szabály felülírja)
hc rule focus=off

# Kivétel: a terminálok kapjanak fókuszt (reguláris kifejezéssel)
hc rule class~'(.*[Rr]xvt.*|.*[Tt]erm|Konsole|Alacritty|Kitty)' focus=on

# Kivétel: párbeszédablakok (dialog) legyenek pszeudo-csempézettek és kapjanak fókuszt
hc rule windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)' pseudotile=on
hc rule windowtype='_NET_WM_WINDOW_TYPE_DIALOG' focus=on

# Kivétel: értesítések és dock alkalmazások (pl. wbar, conky, polybar) kezelése
# manage=off: a herbstluftwm egyáltalán nem kezeli ezeket az ablakokat, így nem zavarják a layoutot
hc rule windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK)' manage=off
hc rule class~'[Ww]bar' manage=off
hc rule class~'[Cc]onky' manage=off
hc rule class~'polybar' manage=off

# ==========================================
# 10. MULTIMONITOR ÉS PANEL BEÁLLÍTÁSOK
# ==========================================
# Padding beállítása: hc pad <monitor> <top> <right> <bottom> <left>
# Ez helyet hagy a panelnek a képernyő tetején (pl. 20 pixel), hogy az ablakok ne takarják ki
hc pad 0 24 0 0 0

# Panel indítása minden monitoron (ha létezik a panel.sh)
panel=~/.config/herbstluftwm/panel.sh
[ -x "$panel" ] || panel=/etc/xdg/herbstluftwm/panel.sh
for monitor in $(hc list_monitors | cut -d: -f1); do
    $panel "$monitor" &
done

# WM feloldása (zárás után újra aktív)
hc unlock

# ==========================================
# AUTOMATIKUSAN INDULÓ PROGRAMOK
# ==========================================

# 1. Numlock bekapcsolása , Caps Lock -> ESC
# Ezek rövid parancsok, nem kell '&'
numlockx on
setxkbmap -option caps:escape_shifted_capslock

# 2. Redshift (képernyő színhőmérsékletének állítása)
# Folyamatosan fut, ezért kell a '&' a végére!
# Opcionálisan megadhatod a koordinátáidat is (-l földrajzi szélesség -g hosszúság)
redshift &

# 3. Kompozitor (árnyékok, átlátszóság, animációk)
# Ha picom-ot használsz:
picom &
# Vagy ha a régebbi compton-ot:
# compton --daemon &

# 4. Értesítési daemon (Notification server)
# Nélküle a programok értesítései (pl. hangerőváltozás, letöltés vége) nem jelennek meg.
dunst &

# 5. Háttérkép beállítása (feh)
"$HOME/.fehbg"

# ==========================================
# HANGERŐ SZABÁLYOZÁS NUMPAD GOMBOKKAL
# ==========================================

# PulseAudio hangerő beállítása 30%-ra
pactl set-sink-volume @DEFAULT_SINK@ 30%

hc keybind $Mod+KP_Add       spawn pactl set-sink-volume @DEFAULT_SINK@ +5%
hc keybind $Mod+KP_Subtract  spawn pactl set-sink-volume @DEFAULT_SINK@ -5%
hc keybind $Mod+KP_Multiply  spawn pactl set-sink-mute @DEFAULT_SINK@ toggle

Szokás szerint igyekeztem magyarázatokkal ellátni, nem is ragoznám túl...
Amire viszont felhívnám a figyelmet, hogy manuális csempézőt használunk, tehát először keretet nyitunk (Mod+o vagy +u), majd a keretben nyitjuk az ablakot, ill. az ablak bezárása után a keretet is el kell távolítanunk, ha már nem akarjuk használni (Mod+r). Ezt adott esetben azért szokni kell...

Amit én nem használok, de téged érdekelhet...
- Egy monitor két virtuális monitorra osztása, pl.: hc set_monitors 960x1080+0+0 960x1080+960+0.
- Szabály létrehozása, pl. Firefox a 2-es tag-re: hc rule class=Firefox tag=2. Egyéb szabályok is létrehozhatók, pl. floating=on lebegő mód, fullscreen=on teljes képernyő, manage=off ne kezelje a WM, stb..

Alapértelmezetten egy dzen2 alapú panel jár hozzá, ami iszonyú szívás... Órákat töltöttem el vele, mire a Skynet segítségével sikerült rábírnom, hogy azt és ott jelenítse meg, ahogyan én szeretném, kegyetlen (vagy csak én vagyok hülye hozzá, és inkább Windowst kéne használnom)... Na mindegy, megküzdöttem vele és most már müxik, következzen a konfigurációja (~/.config/herbstluftwm/panel.sh):

#!/usr/bin/env bash

# ============================================================
# Berus - herbstluftwm panel - 3-sávos verzió
#
# Elrendezés 2560x1080 monitoron:
#
#   |----- BAL (asztalok [tag]) -----|---- KÖZÉP (cím) ----|---- JOBB (hangerő|dátum) ----|
#
# A panel három KÜLÖNÁLLÓ dzen2 példányból áll, mindegyik a
# saját szélességén belül a dzen2 SAJÁT text-align (-ta)
# funkciójával igazítja a szöveget.
# ============================================================

# ============================================================
# 1. ALAPBEÁLLÍTÁSOK
# ============================================================

# Modern Xft font.
FONT="xft:JetBrains Mono:size=10"

# Catppuccin Mocha
BG_COLOR="#1e1e2e"
FG_COLOR="#cdd6f4"

TAG_ACT="#a6e3a1"
TAG_OCC="#74c7ec"
TAG_MUT="#f38ba8"

VOL_COLOR="#cba6f7"
DATE_COLOR="#b4befe"

# Panel magassága.
PANEL_HEIGHT=24

# Belső margók (konstansok, NEM szövegszélesség-függők,
# ezért font-cserétől függetlenül biztonságosak).
LEFT_MARGIN=15
RIGHT_MARGIN=15

# A három sáv szélessége a monitor szélességének arányában.
# Állítsd tetszés szerint, ha más elosztás kell.
LEFT_PERCENT=30
CENTER_PERCENT=40
# A jobb sáv a maradék, hogy kerekítési hiba miatt
# ne maradjon/lógjon ki pixel.

# A monitor száma.
#
# Használat:
#
#   ./panel.sh
#   ./panel.sh 0
#   ./panel.sh 1
#
MON_NUM="${1:-0}"

# ============================================================
# 2. MONITOR GEOMETRIA
# ============================================================

eval "$(herbstclient monitor_rect "$MON_NUM" |
    awk '{print "X="$1" Y="$2" W="$3" H="$4}')"

if [ -z "$W" ] || [ "$W" -le 0 ]; then
    echo "Hiba: nem sikerült lekérni a monitor szélességét." >&2
    exit 1
fi

if [ -z "$H" ] || [ "$H" -le 0 ]; then
    echo "Hiba: nem sikerült lekérni a monitor magasságát." >&2
    exit 1
fi

# ============================================================
# 3. A HÁROM SÁV GEOMETRIÁJA
# ============================================================

LEFT_W=$((W * LEFT_PERCENT / 100))
CENTER_W=$((W * CENTER_PERCENT / 100))
RIGHT_W=$((W - LEFT_W - CENTER_W))

LEFT_X=$X
CENTER_X=$((X + LEFT_W))
RIGHT_X=$((X + LEFT_W + CENTER_W))

# ============================================================
# 4. PANEL HELYFOGLALÁSA
# ============================================================

herbstclient pad \
    "$MON_NUM" \
    "$PANEL_HEIGHT" \
    0 0 0

# ============================================================
# 5. FIFO-K ÉS A HÁROM DZEN2 PÉLDÁNY INDÍTÁSA
# ============================================================
#
# Mindhárom sáv folyamatosan él, saját named pipe-ból olvas.
# A -ta l/c/r beállítás miatt a dzen2 saját maga igazítja
# a szöveget a sávon belül — mi csak a nyers szöveget adjuk át.
# ============================================================

TMP_DIR="$(mktemp -d)"

FIFO_LEFT="${TMP_DIR}/panel-left-${MON_NUM}"
FIFO_CENTER="${TMP_DIR}/panel-center-${MON_NUM}"
FIFO_RIGHT="${TMP_DIR}/panel-right-${MON_NUM}"

mkfifo "$FIFO_LEFT" "$FIFO_CENTER" "$FIFO_RIGHT"

cleanup() {
    exec {FD_LEFT}>&- 2>/dev/null
    exec {FD_CENTER}>&- 2>/dev/null
    exec {FD_RIGHT}>&- 2>/dev/null
    kill "$DZEN_LEFT_PID" "$DZEN_CENTER_PID" "$DZEN_RIGHT_PID" 2>/dev/null
    rm -rf "$TMP_DIR"
}
trap cleanup EXIT INT TERM

dzen2 \
    -x "$LEFT_X" -y "$Y" -w "$LEFT_W" -h "$PANEL_HEIGHT" \
    -fn "$FONT" -bg "$BG_COLOR" -fg "$FG_COLOR" \
    -ta l \
    < "$FIFO_LEFT" &
DZEN_LEFT_PID=$!

dzen2 \
    -x "$CENTER_X" -y "$Y" -w "$CENTER_W" -h "$PANEL_HEIGHT" \
    -fn "$FONT" -bg "$BG_COLOR" -fg "$FG_COLOR" \
    -ta c \
    < "$FIFO_CENTER" &
DZEN_CENTER_PID=$!

dzen2 \
    -x "$RIGHT_X" -y "$Y" -w "$RIGHT_W" -h "$PANEL_HEIGHT" \
    -fn "$FONT" -bg "$BG_COLOR" -fg "$FG_COLOR" \
    -ta r \
    < "$FIFO_RIGHT" &
DZEN_RIGHT_PID=$!

# Az fd-ket egyszer nyitjuk meg, hogy a FIFO ne záruljon be
# minden echo után (elkerülve az ismételt blokkoló nyitást).
exec {FD_LEFT}>"$FIFO_LEFT"
exec {FD_CENTER}>"$FIFO_CENTER"
exec {FD_RIGHT}>"$FIFO_RIGHT"

# ============================================================
# 6. ESEMÉNYEK ÉS ÓRA
# ============================================================

(
    while true; do
        echo "tick"
        sleep 1
    done &

    herbstclient --idle

) | while read -r event args; do

    # ========================================================
    # 7. HANGERŐ
    # ========================================================

    VOL_PERC="$(
        pactl get-sink-volume @DEFAULT_SINK@ 2>/dev/null |
        awk '{print $5}' |
        head -n1
    )"

    VOL_MUTE="$(
        pactl get-sink-mute @DEFAULT_SINK@ 2>/dev/null |
        awk '{print $2}'
    )"

    if [ -z "$VOL_PERC" ]; then

        VOL_OUT="^fg(${TAG_MUT})Vol: N/A^fg()"

    elif [ "$VOL_MUTE" = "yes" ]; then

        VOL_OUT="^fg(${TAG_MUT})Vol: MUTE^fg()"

    else

        VOL_OUT="^fg(${VOL_COLOR})Vol: ${VOL_PERC}^fg()"

    fi

    # ========================================================
    # 8. DÁTUM ÉS IDŐ
    # ========================================================

    DATE_TEXT="$(date '+%Y-%m-%d %H:%M')"

    DATE_OUT="^fg(${DATE_COLOR})${DATE_TEXT}^fg()"

    # ========================================================
    # 9. TAG-EK
    # ========================================================

    TAGS_OUT=""

    TAG_STATUS="$(herbstclient tag_status "$MON_NUM")"

    for tag in $TAG_STATUS; do

        TAG_NAME="${tag:1}"

        CLICK_START="^ca(1,herbstclient use $TAG_NAME)"
        CLICK_END="^ca()"

        case "${tag:0:1}" in

            '#')
                TAGS_OUT+="${CLICK_START}^bg(#313244)^fg(${TAG_ACT}) ${TAG_NAME} ^fg()^bg()${CLICK_END}"
                ;;

            '+')
                TAGS_OUT+="${CLICK_START}^bg(#313244)^fg(${TAG_OCC}) ${TAG_NAME} ^fg()^bg()${CLICK_END}"
                ;;

            ':')
                TAGS_OUT+="${CLICK_START}^fg(${TAG_OCC}) ${TAG_NAME} ^fg()${CLICK_END} "
                ;;

            *)
                TAGS_OUT+="${CLICK_START}^fg(#45475a) ${TAG_NAME} ^fg()${CLICK_END} "
                ;;

        esac

    done

    # ========================================================
    # 10. ABLAKCÍM
    # ========================================================

    WIN_TITLE="$(
        herbstclient attr clients.focus.title 2>/dev/null
    )"

    if [ -z "$WIN_TITLE" ]; then
        WIN_TITLE=""
    fi

    # Maximális hossz karakterben — a dzen2 elvágja/igazítja
    # a sáv szélén belül, de egy ésszerű felső korlát azért
    # jól jön hosszú ablakcímeknél.
    if [ "${#WIN_TITLE}" -gt 80 ]; then
        WIN_TITLE="${WIN_TITLE:0:77}..."
    fi

    WIN_OUT="^fg(${FG_COLOR})${WIN_TITLE}^fg()"

    # ========================================================
    # 11. SZÖVEGEK ÖSSZEÁLLÍTÁSA — NINCS ^pa(), NINCS
    #     PIXELSZÁMOLÁS. Mindhárom sáv a saját ablakán belül,
    #     a saját -ta beállítása szerint igazít.
    # ========================================================

    LEFT_LINE="${TAGS_OUT}"
    CENTER_LINE="${WIN_OUT}"
    RIGHT_LINE="${VOL_OUT}  |  ${DATE_OUT}"

    # ========================================================
    # 12. KIÍRÁS A HÁROM SÁVBA
    # ========================================================

    echo -e "$LEFT_LINE"   >&$FD_LEFT
    echo -e "$CENTER_LINE" >&$FD_CENTER
    echo -e "$RIGHT_LINE"  >&$FD_RIGHT

done

Ezt is alaposan elláttam magyarázatokkal (magamnak is, ne keljen még egyszer ennyit szívni vele), nem boncolgatnám tovább (amúgy EWMH szabványú panelekkel, pl. Polybar kiváltható)...

A herbstluftwm egy rendkívül hatékony kis jószág, szerintem bármin elfut. A manuális csempézés megszokást kíván, de megvannak a maga előnyei, én lelkesen használom, ugyanakkor a pálcikawm világgal való ismerkedésre nem feltétlen ajánlanám, némi elszántság azért kell hozzá...!
Nyilván lehetne még farigcsálni, akinek erre van késztetése, annak barátja a man!

Berus