Creating a minimal display manager in bash
Not so long ago I decided to try out dwl as a new tiling window manager. I currently use dwm with is a minimalist window manager from the suckless team. dwl is a rewrite of dwm to use wayland instead of x11.
Since I do not have a login manager, and I want to be able to switch between the two easily, I came up with this script:
#!/bin/bash
LOGDIR="$HOME/.local/state/winman"
CACHEDIR="$HOME/.cache/winman"
LOGFILE="$HOME/.local/state/winman/winman.log"
WMFILE="$HOME/.cache/winman/wm"
DWMXINITRC="$HOME/.cache/winman/dwm-xinitrc"
DWMDIR="$HOME/code/dwm"
DWLDIR="$HOME/code/dwl"
install_dwm() {
echo "installing dwm"
cd "$DWMDIR"
cp -f config.def.h config.h
sudo make clean install
}
install_dwl() {
echo "installing dwl"
cd "$DWLDIR"
cp -f config.def.h config.h
sudo make clean install
}
install() {
install_dwl
install_dwm
}
switch() {
local wm="$1"
echo "$wm" > "$WMFILE"
pkill -x dwm
pkill -x dwl
}
run_dwm() {
echo "[INFO] Starting dwm..." >> $LOGFILE
[ -z "$DBUS_SESSION_BUS_ADDRESS" ] && eval "$(dbus-launch --sh-syntax)"
[ -z "$SSH_AUTH_SOCK" ] && eval "$(ssh-agent -s)" >/dev/null
export XDG_SESSION_TYPE=x11
export GDK_BACKEND=auto
export QT_QPA_PLATFORM=auto
export ELECTRON_OZONE_PLATFORM_HINT=auto
cat > "$DWMXINITRC" <<EOF
#!/bin/bash
[ -n "\$XTERM_VERSION" ] && transset-df --id "\$WINDOWID" >/dev/null
xset r rate 200 50
xcompmgr &
unclutter &
setbg &
fcitx5 &
dunst &
dwmblocks &
exec dwm >> "$LOGFILE" 2>&1
EOF
chmod +x "$DWMXINITRC"
startx "$DWMXINITRC"
}
run_dwl() {
echo "[INFO] Starting dwl..." >> "$LOGFILE"
# Start ssh-agent if needed
[ -z "$SSH_AUTH_SOCK" ] && eval "$(ssh-agent -s)" >/dev/null
# windows session
export XDG_SESSION_TYPE=wayland
export GDK_BACKEND=wayland
export QT_QPA_PLATFORM=wayland
export ELECTRON_OZONE_PLATFORM_HINT=wayland
fcitx5 &
dunst &
dwl >> "$LOGFILE" 2>&1
}
run() {
switch "$1"
while :
do
local wm=$(cat "$WMFILE")
case "$wm" in
dwm)
run_dwm
;;
dwl)
run_dwl
;;
none)
exit 0
;;
*)
exit 1
;;
esac
sleep 0.2
done
}
print_help() {
cat <<EOF
Usage: $(basename "$0") <command> [args]
Commands:
run [dwm|dwl] Start the selected window manager. If none is given, uses the last one set.
switch [dwm|dwl] Switch to the specified window manager and restart it.
quit Stop the running window manager.
reload Restart the currently active window manager.
install Build and install both dwm and dwl from source.
Examples:
$(basename "$0") switch dwm # Switch to dwm and restart it
$(basename "$0") run # Run the last selected window manager
$(basename "$0") install # Build and install both dwm and dwl
$(basename "$0") quit # Quit the current window manager
EOF
exit 1
}
main() {
mkdir -p "$LOGDIR"
mkdir -p "$CACHEDIR"
case "$1" in
run)
run "$2"
;;
switch)
switch "$2"
;;
quit)
switch none
;;
install)
install
;;
reload)
local curr_wm=$(cat "$WMFILE")
switch "$curr_wm"
;;
*)
print_help
;;
esac
}
main "$@"
exit 0
I called this script winman as it launch my WINdow MANager
in such a way, I can start my window manager like this
#!/bin/zsh
. ~/.env
[ "$(tty)" = "/dev/tty1" ] && exec winman run dwm
and then change window manager this way:
winman switch dwm
Reload this way:
winman reload
and quit this way:
winman quit
Here are the biggest struggle I had when writing this script:
vscodeandelectronapplications need some variable to be set depending on wether you use x11 or wayland. I solve this issue with:
export ELECTRON_OZONE_PLATFORM_HINT=wayland
but at this time, I still haven’t found a way to make brave work without having to modify the way I call it on the command line
startxis a pain to work with. the man page is not very descriptive and chatgpt hallucinate a lot. After spending way too much time trying to make it work without creating a file (by usingstartx /bin/bash -...) I decided to create a file at runtime, in this way I can easily feed my script variable to it (seestartxin the script).- When you play with your window manager launcher and something is broken, then you end up debugging in the
tty. Debugging in tty is not easy (despite what Arch Linux chad tries to make you think). To avoid spending as much time as possible in this environnement I decided to always have a.xinitrcready to launch my dwm if something does wrong. Then I can debug from my sweet sweet dwm setup.