Mielőtt belevágnánk mai témánk a Qtile kitárgyalásába, előbb következzen egy rövidke gondolatmenet friss élményeim alapján.
Aki már foglalkozott a pálcikawm világgal, nyilván nézegetett "guruk" által létrehozott konfigurációkat, csilli-villi képernyőképekkel. Szóval ezek az urak-hölgyek túltolják! Fölösleges szkriptek tucatjai, minden sorában megváltoztatott konfigurációs állományok, több tucat billentyűkombináció, amiből jó ha tízet használsz, stb., végeredmény pedig egy túlbonyolított, sokszor hibás rendszer! A konkrét élmény pedig az Archbang Linux volt bspwm ablakozóval, ahol a vége a kitty terminál képelőnézeti funkcióinak összeomlása, és ami még nagyobb gáz, a Gtk párbeszédablakok véletlenszerű eltünedezése lett...

Szerintem a pálcikawm világ lényege a hatékonyság és egyszerűség, szóval mi haladjunk ezen az úton!

A Qtile az egyik legérdekesebb pálcikawm Linuxra. A legtöbb konkurenssel szemben — mint például az i3 vagy a bspwm — a Qtile teljes konfigurációja Pythonban történik. Ez rendkívüli rugalmasságot ad, Pythonban programozni tudóknak pedig maga a Kánaán. Én sajnos semmilyen programozó nem vagyok, de némi időráfordítással azért remekül lehet boldogulni a konfigurációval.
Tehát röviden összefoglalva, a Qtile egy dinamikus csempéző ablakkezelő, Python-alapú konfigurációs rendszerrel, X11 és Wayland támogatással, alacsony erőforrásigénnyel.
Nézzük is a konfigurációs állományomat (~/.config/qtile/config.py):
###
# Berus Qtile konfiguráció
###
import os
import subprocess
from libqtile import bar, layout, qtile, widget, hook
from libqtile.config import Click, Drag, Group, Key, Match, Screen
from libqtile.lazy import lazy
#from libqtile.utils import guess_terminal
# Alapbeállítások
mod = "mod4"
#terminal = guess_terminal()
terminal = "kitty"
# Billetyűparancsok
keys = [
# Az elérhető parancsok listája, amiket billentyűkhöz lehet kötni, itt található:
# https://docs.qtile.org/en/latest/manual/config/lazy.html
# Ablakok közötti váltás (fókusz)
Key([mod], "h", lazy.layout.left(), desc="Fókusz mozgatása balra"),
Key([mod], "l", lazy.layout.right(), desc="Fókusz mozgatása jobbra"),
Key([mod], "j", lazy.layout.down(), desc="Fókusz mozgatása lefelé"),
Key([mod], "k", lazy.layout.up(), desc="Fókusz mozgatása felfelé"),
Key([mod], "space", lazy.layout.next(), desc="Fókusz mozgatása a következő ablakra"),
# Ablakok mozgatása az oszlopok között vagy a jelenlegi stack-ben.
# Ha a Columns elrendezésben túlmegyünk a határon, új oszlop jön létre.
Key([mod, "shift"], "h", lazy.layout.shuffle_left(), desc="Ablak mozgatása balra"),
Key([mod, "shift"], "l", lazy.layout.shuffle_right(), desc="Ablak mozgatása jobbra"),
Key([mod, "shift"], "j", lazy.layout.shuffle_down(), desc="Ablak mozgatása lefelé"),
Key([mod, "shift"], "k", lazy.layout.shuffle_up(), desc="Ablak mozgatása felfelé"),
# Ablakok átméretezése (növelés). Ha az ablak a képernyő szélén van és abba az
# irányba toljuk tovább, az ablak zsugorodni fog.
Key([mod, "control"], "h", lazy.layout.grow_left(), desc="Ablak növelése balra"),
Key([mod, "control"], "l", lazy.layout.grow_right(), desc="Ablak növelése jobbra"),
Key([mod, "control"], "j", lazy.layout.grow_down(), desc="Ablak növelése lefelé"),
Key([mod, "control"], "k", lazy.layout.grow_up(), desc="Ablak növelése felfelé"),
Key([mod], "n", lazy.layout.normalize(), desc="Ablakméretek alaphelyzetbe állítása"),
# Váltás az osztott (split) és nem osztott oldalak között.
# Split = minden ablak megjelenik
# Unsplit = csak 1 ablak látszik (mint a Max elrendezésnél), de több stack-kel
Key(
[mod, "shift"],
"Return",
lazy.layout.toggle_split(),
desc="Váltás az osztott és nem osztott nézet között",
),
Key([mod], "Return", lazy.spawn(terminal), desc="Terminál indítása"),
# Váltás az alább definiált elrendezések (layouts) között
Key([mod], "Tab", lazy.next_layout(), desc="Váltás az elrendezések között"),
Key([mod], "q", lazy.window.kill(), desc="Fókuszált ablak bezárása"),
Key(
[mod],
"f",
lazy.window.toggle_fullscreen(),
desc="Teljes képernyős mód ki/be",
),
Key([mod], "t", lazy.window.toggle_floating(), desc="Lebegő mód ki/be"),
Key([mod, "control"], "r", lazy.reload_config(), desc="Konfiguráció újratöltése"),
Key([mod, "shift"], "e", lazy.shutdown(), desc="Qtile leállítása"),
Key([mod], "r", lazy.spawncmd(), desc="Parancs futtatása prompt widget segítségével"),
Key([mod], "d", lazy.spawn("rofi -show drun"), desc="Alkalmazásindító"),
]
# VT (virtuális terminál) váltás Wayland alatt.
# Nem tudjuk ellenőrizni a qtile.core.name-et az alapértelmezett konfigban,
# mert az előbb töltődik be, mint a qtile. Ezért a .when(func=...) használatával késleltetjük.
for vt in range(1, 8):
keys.append(
Key(
["control", "mod1"],
f"f{vt}",
lazy.core.change_vt(vt).when(func=lambda: qtile.core.name == "wayland"),
desc=f"Váltás a(z) VT{vt} terminálra",
)
)
# Asztalok, panel létrehozása és elrendezése
groups = [Group(i) for i in "123456789"]
for i in groups:
keys.extend(
[
# mod + csoport száma = váltás az adott csoportra
Key(
[mod],
i.name,
lazy.group[i.name].toscreen(),
desc=f"Váltás a(z) {i.name}. csoportra",
),
# mod + shift + csoport száma = ablak mozgatása a csoportba és váltás oda
Key(
[mod, "shift"],
i.name,
lazy.window.togroup(i.name, switch_group=True),
desc=f"Ablak mozgatása és váltás a(z) {i.name}. csoportra",
),
# Vagy használd az alábbit, ha nem akarsz oda is váltani:
# Key([mod, "shift"], i.name, lazy.window.togroup(i.name),
# desc="Ablak mozgatása a(z) {}. csoportba".format(i.name)),
]
)
layouts = [
layout.Columns(margin=10, border_focus_stack=["#d75f5f", "#8f3d3d"], border_width=2, border_on_single=True),
layout.Max(),
# További elrendezések kipróbálásához vedd ki a kommentet:
# layout.Stack(num_stacks=2),
# layout.Bsp(),
# layout.Matrix(),
# layout.MonadTall(),
# layout.MonadWide(),
# layout.RatioTile(),
# layout.Tile(),
# layout.TreeTab(),
# layout.VerticalTile(),
# layout.Zoomy(),
]
widget_defaults = dict(
font="sans",
fontsize=12,
padding=3,
)
extension_defaults = widget_defaults.copy()
screens = [
Screen(
bottom=bar.Bar(
[
widget.GroupBox(),
widget.Prompt(),
widget.WindowName(),
widget.Chord(
chords_colors={
"launch": ("#ff0000", "#ffffff"),
},
name_transform=lambda name: name.upper(),
),
# FIGYELEM: A Systray nem kompatibilis a Waylanddel, használd helyette a StatusNotifiert
# widget.StatusNotifier(),
widget.CurrentLayout(),
widget.TextBox("|"),
widget.Clock(format="%Y-%m-%d %a %I:%M %p"),
#widget.QuickExit(),
widget.Systray(),
],
24,
# border_width=[2, 0, 2, 0], # Alsó-felső szegély
# border_color=["ff00ff", "000000", "ff00ff", "000000"] # Magenta szegélyek
),
# Vedd ki a kommentet, ha X11 alatt a lebegő ablakok átméretezése/mozgatása akadna.
# Alapértelmezés szerint késleltetve kezeljük ezeket a teljesítmény javítása érdekében.
# x11_drag_polling_rate = 60,
),
]
# Lebegő ablakok egérrel való kezelése
mouse = [
Drag([mod], "Button1", lazy.window.set_position_floating(), start=lazy.window.get_position()),
Drag([mod], "Button3", lazy.window.set_size_floating(), start=lazy.window.get_size()),
Click([mod], "Button2", lazy.window.bring_to_front()),
]
dgroups_key_binder = None
dgroups_app_rules = [] # típus: lista
follow_mouse_focus = True
bring_front_click = False
floats_kept_above = True
cursor_warp = False
floating_layout = layout.Floating(
float_rules=[
# Használd az `xprop` eszközt az ablak wm_class és name lekéréséhez.
*layout.Floating.default_float_rules,
Match(wm_class="confirmreset"), # gitk
Match(wm_class="makebranch"), # gitk
Match(wm_class="maketag"), # gitk
Match(wm_class="ssh-askpass"), # ssh-askpass
Match(title="branchdialog"), # gitk
Match(title="pinentry"), # GPG kulcs jelszó bekérő
]
)
auto_fullscreen = True
focus_on_window_activation = "smart"
reconfigure_screens = True
# Ha bizonyos programok minimalizálni akarják magukat fókuszvesztéskor,
# figyelembe vegyük-e ezt?
auto_minimize = True
# Wayland backend használata esetén itt konfigurálhatók a beviteli eszközök.
wl_input_rules = None
# xcursor téma (string vagy None) és méret (egész szám) Waylandhez
wl_xcursor_theme = None
wl_xcursor_size = 24
# XXX: Itt "hazudunk". Valójában senkit nem érdekel ez a string a Java UI toolkit-eken kívül;
# Számos fórum és dokumentáció javasolja ennek beállítását, ha a Java alkalmazások nem működnek jól.
# Úgy teszünk, mintha egy támogatott ablakkezelő lennénk.
#
# Az LG3D-t választottuk az irónia kedvéért: ez egy Java-ban írt 3D-s WM, ami rajta van a Java fehérlistáján.
wmname = "LG3D"
## Automatikus indítás szkript
@hook.subscribe.startup_once
def autostart():
home = os.path.expanduser("~/.config/qtile/autostart.sh")
subprocess.Popen([home])Némi magyarázat hozzá!
Mindjárt az elején, ha a rendszerben alapértelmezett terminált akarjuk használni, vegyük ki a kommentet ezek elől: #from libqtile.utils import guess_terminal és #terminal = guess_terminal().
A konfigurációmban a kitty-t választottam alapértelmezett terminálnak, módosító pedig a megszokott bal Win billentyű.
A Vim-stílusú navigáció (mod+ h, j, k, l) alapvető nálam. A fókusz mozgatása mellett a 'control' billentyűvel kombinálva az ablakok átméretezése történik. Ha pedig káosz van, a 'mod + n' gombbal lehet rendet rakni.
A konfiguráció automatikusan generál 9 munkaasztalt: groups = [Group(i) for i in "123456789"].
Alapvetően a "Columns" elrendezést használom: layout.Columns(margin=10, border_focus_stack=["#d75f5f", "#8f3d3d"], border_width=2, border_on_single=True), tehát térköz 10-re állítva, keret színezése (azért használjuk a border_focus_stack formulát, mert így a 'max' elrendezésnél is látjuk, ha több ablak van egymáson), keret szélessége 2, és ha csak egy ablakunk van, akkor is legyen keret.
A képernyő alján lévő panelen (bottom=bar.Bar) is takarítottam kicsit, itt látszanak a virtuális asztalok (GroupBox), az éppen aktív ablak neve (WindowName), az elrendezés (CurrentLayout), az óra (Clock), és a rendszertálca (Systray). Itt jelenik meg a Qtile saját programindítója is (mod+r), de nálam telepítve van a Rofi indító is (mod+d).
A konfiguráció helyességét a következő paranccsal ellenőrizhetjük: python -m py_compile ~/.config/qtile/config.py.
Következzen az autostart.sh szkriptem:
#!/usr/bin/env bash # Ha már futnak, lőjük le őket killall picom nm-applet redshift-gtk # Most indítsuk el őket újra picom & redshift-gtk & nm-applet & # A háttérkép beállítása (ez általában felülírja az előzőt, nem kell pkill) /home/berus/.fehbg & # Hang # Ha már futnak, lőjük le őket killall pipewire wireplumber pipewire-pulse pasystray # Indítsuk el a folyamatokat sorban # Fontos a sorrend és a háttérbe küldés (&) pipewire & sleep 1 wireplumber & sleep 1 pipewire-pulse & sleep 1 # Jöhet a tálca ikon pasystray &
Elég egyértelmű, de azért a hangkeltésről ejtsünk néhány szót...! Szóval jelenlegi Linuxos életem egyik fontos eleme, hogy próbálok szabadulni a systemd nevezetű borzalomtól, sikerrel! De ez néha megnehezíti az életet, így pl. Devuan+ Sysv+ Qtile (vagy bármelyik pálcikawm) esetén a pipewire hangmodul életre keltése nem triviális, a fentebb látható módon az autostart.sh szkriptben kezeljük, és ahogy ott is írtam, figyeljünk az indítási sorrendre!
Kedvcsinálónak ennyit, barátunk a man, és rengeteg példát találunk a hálón, ahonnan szedegethetünk ötleteket!
Berus

Hozzászólások
Konfig változás!
Beküldte berus -
Értékelés:
Közben változtattam a koncepción, minden elrendezéshez (layouts) ugyanazt a beállítást használom, a layout_theme rész került a konfigba!
layout_theme = { "border_width": 2, "margin": 10, "border_focus": "6c757d", "border_normal": "343a40", "border_focus_stack": "a77eff", "border_on_single": True } layouts = [ layout.Columns(**layout_theme),