suckless/README-en.md
alejandrogs73 bea3bdbb62
zram: swap comprimida en RAM por delante de la del disco
zramen con zstd, hasta la mitad de la RAM (máximo 8 GB) y la prioridad
más alta; la swap del NVMe queda de reserva. swappiness 180 y
page-cluster 0, lo normal con zram.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5v1qWDwgkaVM5kjVHGGh8
2026-09-28 16:25:39 +02:00

254 lines
13 KiB
Markdown

# suckless
[Español](README.md) · **English**
My dotfiles for Void Linux: dwm, st, dmenu, slstatus, slock, scroll and
clipmenu, plus the session setup (xinitrc, bash, picom, dunst...).
Everforest theme and Fira Code font everywhere.
Scripts, install steps and some folders have Spanish names (`enlaces`,
`volumen`, `marcadores`...). They are kept as they are because those are the
real names you type; this README explains what each one does.
## Layout
| Folder | Contents |
|---|---|
| `suckless/` | The programs, each with its own `config.h` and patches |
| `home/` | Files that go in `~`, at the same path (they are symlinked) |
| `sistema/` | Files that go in `/` (acpid, zzz, turnstile, udev, doas, xbps, runit) |
| `install.sh` | Installs everything on a fresh Void system |
## Install
On a fresh Void install, as your normal user (it asks for the root
password when needed: through sudo until doas is ready, then through doas):
git clone ssh://forgejo@ssh.alejandrogs.es/alejandrogs73/suckless.git ~/suckless
cd ~/suckless && ./install.sh
It runs seven steps, which can also be run on their own (`./install.sh enlaces`,
for example) and repeated safely:
1. `paquetes` (packages): installs with xbps everything the setup uses.
2. `suckless`: builds the programs and installs them in `/usr/local`.
3. `enlaces` (links): symlinks every file in `home/` into `~`. If a different
file was already there, it is kept as `.bak`. Since they are symlinks,
editing `~/.bashrc` edits the repo. Links to files deleted from the repo
are removed. It also creates the user folders and
sets `~/.ssh` to 700.
4. `gtk`: builds the [Everforest
GTK](https://github.com/Fausto-Korpsvart/Everforest-GTK-Theme) theme
(green, dark, medium palette) in `~/.themes` from a pinned commit, links it
for GTK 4 apps and makes the Papirus folders green. Icons are Papirus-Dark
everywhere. Qt 5 apps (the hplip windows) use qt5ct (`QT_QPA_PLATFORMTHEME`
in `.xinitrc`) with the Fusion style and an Everforest palette
(`home/.config/qt5ct/`). If a `papirus-icon-theme` update turns the folders
blue again, just run this step again.
5. `gnupg`: for after copying `~/.gnupg` by hand (from a USB stick, for
example). It fixes the permissions, sets `pinentry-dmenu` with the dmenu
colours (`pinentry-curses` on a tty: `home/.local/bin/pinentry-menu`
picks one), enables gpg's SSH agent, adds the authentication subkeys
to `sshcontrol` and caches the passphrase for one hour. `.bashrc` already
points `SSH_AUTH_SOCK` at the agent. If `~/.gnupg` does not exist yet, it
does nothing.
6. `sistema` (system): copies `sistema/` into `/`, sets up
`wpa_supplicant.conf` so wheel users can use `wpa_cli` without root and
save networks, enables the runit services (dbus, turnstiled,
wpa_supplicant, dhcpcd, bluetoothd, acpid, openntpd, tlp, zramen,
automontaje, cupsd), removes NetworkManager, elogind, chronyd, avahi-daemon
(the printer has a fixed IP), sshd (nobody SSHes into the laptop),
nix-daemon and polkitd (if something asks for polkit, like libvirt, D-Bus
starts it on its own) and adds the user to the audio, video, input,
network, bluetooth, lpadmin (printer management) and `_pipewire` (realtime
priority for audio without rtkit) groups. `doas.conf` is checked with `doas
-C` before it is installed with mode 400.
7. `quitar` (remove): uninstalls what the repo no longer uses because
something else replaces it: sudo (doas), feh (xwallpaper and nsxiv),
gammastep (sct), autorandr (`pantallas`), blueman and pavucontrol (the
`bluetooth` and `volumen` scripts), pinentry-gtk (pinentry-dmenu), vlc
(mpv), btop, NetworkManager and tlp-rdw (wpa_supplicant, dhcpcd and the
`wifi` script), rtkit, elogind (turnstile), xss-lock (`inactivo`, with
xssstate), chrony (openntpd), avahi and nss-mdns (also removed from
`/etc/nsswitch.conf`), nemo with upower (yazi; gvfs and udisks2 go with
nemo), obs and qt6ct, and nix (webcord; Discord runs in Firefox). Once the
nix package is gone, it also deletes `/nix` and the user's Nix profile.
sudo can be removed thanks to `sistema/etc/xbps.d/sin-sudo.conf`
(base-system depends on it), and it is only removed once `/etc/doas.conf`
is installed.
Afterwards, log out and back in (for the groups) and run `startx`.
## Without elogind
elogind is systemd's logind on its own, and it is not needed here:
- `XDG_RUNTIME_DIR` (`/run/user/UID`) is created by turnstile at login
(`sistema/etc/turnstile/turnstiled.conf`: only that, no user services).
- Xorg runs as root through `Xorg.wrap` (`needs_root_rights = yes` in
`/etc/X11/Xwrapper.config`, shipped by Void).
- The lid and the power and suspend buttons are handled by acpid, which
calls `zzz`. Power off and reboot are runit's.
- Devices (sound, video, input, bluetooth) are reached through the user's
groups, not through the ACLs elogind gave the active session.
What stops working: mounting disks from a graphical file manager (udisks2
asked polkit for an active session; now there is neither a file manager nor
udisks2). USB sticks are mounted by `automontaje`.
## Rebuilding after changing the config
cd suckless/dwm && make && doas make install
## Updating from upstream
Each program was imported with `git subtree --squash`:
git subtree pull --prefix=suckless/dwm https://git.suckless.org/dwm master --squash
git subtree pull --prefix=suckless/clipmenu https://github.com/cdown/clipmenu develop --squash
The rest work like dwm, changing the name in `--prefix` and in the URL.
## dwm shortcuts
`Mod` is `Super` (it is `Alt` in stock dwm). Mouse bindings use `Super` too.
Only shortcuts that differ from stock dwm or are new are listed; the rest are
unchanged. The st, scroll, dmenu and slock shortcuts are untouched.
### Changed
| Action | Stock | Now |
|---|---|---|
| Open a terminal (`st`) | Mod+Shift+Return | Mod+Return |
| zoom (move the window to the master area) | Mod+Return | Mod+Shift+Return |
| Close window | Mod+Shift+c | Mod+q |
| Quit dwm | Mod+Shift+q | Mod+Shift+m |
### New
| Shortcut | Action |
|---|---|
| Mod+v | clipmenu (same palette and font as dmenu) |
| Mod+Shift+l | Lock the screen with `slock` |
| Mod+n | Show the last notification again (dunst history) |
| Mod+Shift+n | Close all notifications |
| Mod+Shift+Escape | Session menu: lock, suspend, quit dwm, reboot or power off (the last three ask for confirmation) |
| Mod+`-` / Mod+`+` | Shrink / grow the gaps |
| Mod+Shift+`+` | Gaps to 0 |
| Volume up / down key | Volume ±5% with `wpctl` (100% max) |
| Mute key | Mute or unmute the audio |
| Mic mute key or Mod+ñ | Mute or unmute the microphone (ñ is the key right of L on a Spanish keyboard) |
| Print Screen | Full screenshot with `maim` |
| Shift+Print Screen | Screenshot of a region |
The audio keys (and clicks on VOL in the bar) use the `volumen` script
(`home/.local/bin/volumen`): it changes the volume with `wpctl`, refreshes
slstatus and shows a notification with the level.
The script menus (`apagado`, `bluetooth`, `volumen salida`...) use `menu`,
which is dmenu with the dwm font and colours.
Screenshots are saved in `~/Images/Screenshots`, copied to the clipboard and
shown in a notification.
## Bar (slstatus)
[ CPU: 12% ] [ RAM: 40% ] [ WiFi: Livebox6 ] [ BAT: 80% + ] [ VOL: 50% ] [ BT: OFF ] [ 28/09/26 12:30 ]
The network, VOL, BT and date blocks are clickable (dwm's `statuscmd`
patch). What each click does is in `statuscmds`, in `suckless/dwm/config.h`,
and which area is which is marked by the `\001`...`\004` bytes in
`suckless/slstatus/config.h`.
| Block | Shows | Left | Middle | Right | Wheel |
|---|---|---|---|---|---|
| CPU, RAM | Usage in % | | | | |
| Network | `ETH` on cable; otherwise `WiFi:` and the network | `wifi` menu: networks by signal, connect, ask for and save the password | | `wpa_cli` in a floating st | |
| BAT | Percentage and state (`+` charging, `-` discharging) | | | | |
| VOL | Volume; `MUT` if muted, `MIC OFF` if the mic is | Pick the audio output (`volumen salida`) | Mute | Mute the mic | Up / down |
| BT | `OFF`, or the connected device and its battery if it reports it (`VJ 901 100%`) | `bluetooth` menu: connect, disconnect, scan and pair, power off | | Power on or off | |
| Date | Day and time | This month's calendar (`calendario`) | | | |
VOL and BT are not read every 2 s like the rest, but every 10 s or as soon as
`SIGUSR1` arrives (`lento` component in slstatus's `config.h`): `volumen`,
`bluetooth`, `wifi` and the clicks send it, so your own changes show up at
once and wpctl and bluetoothctl are not spawned every 2 s.
After changing dwm's `config.h`, reinstall and restart it for new clicks to
work: `pkill -HUP dwm` restarts it without closing windows (restartsig and
preserveonrestart patches).
## Session
- Logging in on tty1 starts `startx` automatically (`.bash_profile`); other
ttys do not.
- `.xinitrc` also starts `luz` (warm light with `sct` from 20:00 to 8:00,
with a one-hour transition) and `bateria` (warns at 15 % and, in red, at
5 %; at 3 % it suspends with `doas -n zzz`). Suspend, power off and reboot
need no password (`sistema/etc/doas.conf`).
- Screens: `pantallas` (`sistema/usr/local/bin`) lines them up with `xrandr`
(the laptop one on the left and as primary) at startup and whenever one is
plugged or unplugged (udev rule in `sistema/`), then repaints the
wallpaper with `xwallpaper`.
- Memory: compressed swap in RAM with zram (`zramen` service, up to half the
RAM, with zstd) ahead of the disk swap, which stays as a fallback
(`sistema/etc/sv/zramen/conf` and `sistema/etc/sysctl.d/99-zram.conf`).
- Audio: `.xinitrc` runs pipewire, wireplumber and pipewire-pulse in a loop,
so if one of them dies it comes back a second later (without wireplumber
everything goes to "Dummy Output").
- WiFi: `wifi` scans with `wpa_cli` and lists the networks in dmenu by
signal (`*` is the current one). For a new network it asks for the
password (hidden while typing) and saves it in
`/etc/wpa_supplicant/wpa_supplicant.conf` only if the connection works.
dhcpcd handles the cable on its own.
- Left click on the date in the bar: this month's calendar in a notification
(`calendario`), with today in green.
- bash: 10 000-entry history, without duplicates and shared between
terminals; the prompt shows the git branch (`*` unstaged changes, `+`
staged).
- `~/.ssh/config` with aliases: `ssh server` and `forgejo`, both through the
domain so they work at home and away. No keys in it: gpg-agent provides
them.
- Firefox bookmarks backup (`marcadores`, started from `.xinitrc`): once a
day it uploads to the server the backup Firefox already makes on its own
(`bookmarkbackups/*.jsonlz4`), to `/var/storage/PUBLIC/backup_void/marcadores`:
`diario/` keeps 7 days and `semanal/` one per week, forever. It only tries
when the SSH key is already unlocked (so pinentry never pops up) and
retries every hour. `marcadores ya` uploads it right away. To restore:
Firefox > Bookmarks > Manage bookmarks > Import and Backup > Restore.
- After 30 minutes idle the screen locks with slock (`inactivo`, which
watches the X screensaver with `xssstate`) and one minute later it turns
off. Videos that ask to keep the screen on (mpv, Firefox) prevent it.
- USB sticks and SD cards: the `automontaje` service (runit, as root) mounts
them in `/mnt/LABEL`, or `/mnt/sdXY` if they have no label, and unmounts
them when removed, with a notification. FAT, exFAT and NTFS are owned by
the user; internal disks are never touched. Before pulling a stick you
wrote to, run `sync` (or `doas umount /mnt/...`).
- User folders in English and without accents (`user-dirs.dirs`):
Documents, Downloads and Images.
- Folders ("Open folder" in Firefox, `xdg-open`) open in yazi inside st
(`home/.local/share/applications/yazi-st.desktop`).
- `ex file...` extracts almost anything with `bsdtar` (a `.bashrc`
function).
## Notes
- The personal config lives in `config.h`. `config.def.h` is the upstream one
plus the patches. If a patch changes `config.def.h`, the change has to be
copied to `config.h` by hand: `make` only copies it if `config.h` does not
exist.
- The applied patches are in `suckless/<program>/patches/`.
- dwm: fullgaps, restartsig, preserveonrestart, statuscmd-nosignal and
swallow.
- st: kitty-graphics, alpha, glyph-wide-support and ligatures, in that
order. kitty-graphics already includes anysize. glyph-wide-support and
the combination with ligatures come from the `graphics-with-patches`
branch of [st-graphics](https://github.com/sergei-grechanik/st-graphics),
without boxdraw.
- In st, Ctrl+Shift+right click on an image opens it in `nsxiv`.
- st shows images with the kitty graphics protocol; yazi detects it on its
own and shows previews without ueberzugpp.
- slstatus.c has a hand-made change (not a patch): it counts `SIGUSR1`
signals so `lento` knows when to refresh.
- slock is modified by hand (not a patch): clock, date, battery and a bottom
bar with the state colour.