Building My Own i3 Desktop
For a long time, my Linux desktop was either a full desktop environment or a window manager that still felt like a pile of loose parts.
This setup is the attempt to close that gap.
It is still i3 at the centre. I like i3 because it is direct, keyboard friendly, and easy to reason about. A config file says what happens, and that is mostly what happens. But a usable daily desktop needs more than tiling windows. It needs a launcher, a status bar, notifications, power controls, media keys, network management, monitor switching, screenshots, clipboard history, notes, lock screen behaviour, theming, and enough recovery paths that I am not stuck when something changes.
The result now lives in my ~/.dots repo. It is managed with GNU Stow and installed through a small init.sh script. The repo contains the i3 config, i3blocks config, rofi theme, dunst config, picom config, kitty and qutebrowser setup, theme environment, package manifest, and a collection of i3-* helper scripts under .local/bin.
That sounds like a lot, but the goal is not complexity for its own sake. The goal is a desktop I understand.
Why build it this way
I do not want a desktop where every behaviour depends on a large hidden service. I also do not want to wire together raw commands every time I need to change Wi-Fi, switch audio output, or take a screenshot.
The middle ground is small scripts around standard tools.
The network menu wraps nmcli. Bluetooth wraps bluetoothctl. Audio wraps wpctl. Monitor layout uses xrandr. Media keys use playerctl, with a separate path for radio through mpv. Notifications are handled by dunst and controlled with dunstctl. Screenshots use maim and xclip. Clipboard history is CopyQ, but without a tray icon. The status bar is i3blocks with shell scripts behind each block.
That gives me menus and shortcuts for normal use, while keeping the underlying implementation boring and inspectable.
If something breaks, I can run the command in a terminal. If I forget a shortcut, there is a searchable cheat sheet. If a menu is missing rofi, most scripts fall back to dmenu. If a service is not installed, the scripts tell me instead of failing silently.
The shape of the desktop
The i3 config starts a curated session rather than trying to recreate GNOME autostart. It sets the environment, applies the theme, starts the wallpaper, dunst, CopyQ, picom, xss-lock, monitor layout, keyboard layout, and a low battery monitor.
The main entry point is a rofi control centre on Mod+u. From there I can get to apps, windows, the scratchpad terminal, wallpaper gallery, keybinding help, notes, media, radio, monitor layout, keyboard layout, audio, network, Bluetooth, clipboard, notifications, screenshots, Pomodoro timer, power, lock, and i3 reload.
Most of those also have direct keybindings. The control centre is not there because I want a dashboard. It is there because a desktop becomes much easier to use when there is one obvious place to look.
The bar sits at the top and uses i3blocks. It shows only what is useful: notification state, network, battery, disk, memory, CPU, load, media, radio, volume, Pomodoro, and time. Several blocks are clickable. Clicking the network block opens the network menu. Clicking the volume block opens audio controls or changes volume with scroll. Media and radio blocks appear only when there is something useful to show.
The whole thing is themed around Catppuccin Frappe with a mauve accent. That is in i3, rofi, kitty, qutebrowser chrome, dunst, i3blocks, the lock screen, and the GTK/Qt environment. It is not just cosmetic. Consistent colours make the system feel like one desktop rather than ten unrelated tools.
What changed
The biggest change is that the desktop now has its own behaviour.
The scratchpad terminal opens in the working directory of the focused terminal when possible. Notes are Markdown files under ~/.local/share/notes, with daily notes, quick capture, search, recent notes, and a scratch file. Radio stations live in a local-only TSV file, and radio playback has its own status block. Media keys work for normal MPRIS players and also step through radio playlists when radio is the active context.
Monitor layout has modes for laptop, external, docked, extended, and mirrored displays. There is also a scaling menu because mixed displays always need adjustment. Keyboard layout switching remembers whether I am using the UK laptop keyboard or a US external keyboard. Audio, network, and Bluetooth each have menus built around the command-line tools I would otherwise use manually.
Locking is intentionally plain. A fast solid-colour i3lock is enough. Before locking, suspending, logging out, rebooting, or shutting down, playback is stopped so I do not leave audio running. xss-lock handles locking before suspend, and the low-battery monitor warns, escalates, and eventually locks and suspends if the battery gets too low.
What this series covers
This series is a tour of the pieces that make the setup feel like a complete desktop:
- the curated i3 session and autostart
- the launcher, control centre, and searchable keybinding help
- the i3blocks status bar
- media controls and internet radio
- clipboard history, notifications, and screenshots
- monitor, keyboard, network, Bluetooth, and audio menus
- Markdown notes and the scratchpad terminal
- theming across apps
- the visual wallpaper picker and its saved state
- power, lock, suspend, and battery behaviour
- the Pomodoro timer in the bar
The common thread is simple: use small scripts to make common actions quick, but keep the system built from tools I can understand.
That is the part I care about. I do not want the desktop to be impressive. I want it to stay out of the way, tell me what is happening, and make the common paths easy.