<feed xmlns='http://www.w3.org/2005/Atom'>
<title>archsetup/dotfiles/hyprland, branch main</title>
<subtitle>Builds a full dev workstation from a bare Arch Linux install.
</subtitle>
<id>https://git.cjennings.net/archsetup/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/archsetup/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/'/>
<updated>2026-06-02T17:16:38+00:00</updated>
<entry>
<title>refactor: drop in-repo dotfiles/, move stow tooling to the dotfiles repo</title>
<updated>2026-06-02T17:16:38+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-06-02T17:16:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=b10cba594db836c0747066addad48bda4d30cd02'/>
<id>urn:sha1:b10cba594db836c0747066addad48bda4d30cd02</id>
<content type='text'>
Since the installer clones DOTFILES_REPO into ~/.dotfiles and stows from there, the in-repo dotfiles/ tree was dead weight. Nothing reads it at install time. I removed it (831 files) now that both machines are migrated.

The Makefile's stow / restow / reset / unstow / import targets and the dotfile-script unit suites moved to the dotfiles repo. They sit alongside the scripts they manage and run standalone (cd ~/.dotfiles &amp;&amp; make ...). This Makefile keeps the VM-integration targets and the installer-helper suite (safe-rm-rf).

I updated CLAUDE.md and README.md so stow operations run from ~/.dotfiles, and the dotfile-management, theme, and unit-test sections point at the standalone repo. The README was already describing the old in-repo model from before the installer switched to cloning. This brings it in line.
</content>
</entry>
<entry>
<title>feat(notify): add --silent flag, volume knob, and level sound files</title>
<updated>2026-05-22T00:16:34+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-22T00:16:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=f7079db3aa3e0073df6ce5409d4b6de0a431e26f'/>
<id>urn:sha1:f7079db3aa3e0073df6ce5409d4b6de0a431e26f</id>
<content type='text'>
The touchpad toggle's notification was too loud, and the eight notify sounds varied by ~13 dB in RMS loudness — bug and fail came out two to three times louder than info or security.

I added a --silent flag to notify (shows the popup, plays no sound) and a NOTIFY_VOLUME knob (paplay scale, default 65536) so the master level can drop without re-encoding. toggle-touchpad now passes --silent on both enable and disable. normalize-notify-sounds.sh measures each .ogg and shifts it to a uniform -31 dB mean. It writes through the file instead of mv-ing over it, so the stow symlinks survive when the script runs against the live sound dir. I re-encoded all eight sounds to the new level.

Tests: a new tests/notify suite (12 tests) covers --silent, the volume knob, flag composition, and the error paths.
</content>
</entry>
<entry>
<title>feat(hyprland): add airplane-mode waybar toggle</title>
<updated>2026-05-21T21:48:47+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-21T21:48:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=09f4d205fe463faf676f95e798d08e8bf498be96'/>
<id>urn:sha1:09f4d205fe463faf676f95e798d08e8bf498be96</id>
<content type='text'>
I added a laptop-only waybar button that drops the machine into a low-power state and restores it on a second click. Engaging turns wifi off, sets the CPU energy-performance preference to power, dims the backlight to 35%, and stops network-only services (tailscale, proton-vpn, avahi, cups, wsdd, geoclue, sshd, fail2ban, syncthing). Bluetooth is left alone so earbuds keep working.

Disengaging replays the state recorded when airplane mode was engaged rather than writing hardcoded defaults. A lever already in its low-power position is left untouched: wifi that was already off stays off, and a service that was already stopped isn't restarted.

The indicator hides itself on machines with no battery, so desktops never show the button. State lives in $XDG_RUNTIME_DIR/airplane-state, and the bar refreshes the moment the toggle fires via a realtime signal.
</content>
</entry>
<entry>
<title>feat(hyprland): rebind monitor to Super+R, touchpad toggle to Super+M</title>
<updated>2026-05-21T02:04:17+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-21T02:04:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=059833df51581216ac0b804b7fa78fef27f0f40e'/>
<id>urn:sha1:059833df51581216ac0b804b7fa78fef27f0f40e</id>
<content type='text'>
Super+M now toggles the touchpad (M for Mouse), and the monitor scratchpad moves to Super+R (R for Resources, since btop is a resource monitor). The touchpad toggle was on Super+F9, which is now free. Super+Shift+M still switches to the monocle layout.
</content>
</entry>
<entry>
<title>feat(hyprland): add touchpad state indicator to waybar</title>
<updated>2026-05-21T01:55:13+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-21T01:55:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=62e45197bb4d440e002b731715343e565cf50ff3'/>
<id>urn:sha1:62e45197bb4d440e002b731715343e565cf50ff3</id>
<content type='text'>
The $mod+F9 toggle and the toggle-touchpad / touchpad-auto scripts already worked, but the scripts lived only in ~/.local/bin and were never committed, and there was no way to see the touchpad's state at a glance.

I committed both scripts into the repo so stow installs them, and added a waybar indicator: a waybar-touchpad status script and a custom/touchpad module that shows a mouse glyph when the touchpad is on and a mouse-off glyph (in the dupre orange) when it's off. The scripts signal the module with pkill -RTMIN+9 waybar after each state change, so the icon updates the moment the touchpad toggles. touchpad-auto now runs at login via exec-once.

The waybar-touchpad script has unit tests under tests/waybar-touchpad/ covering the enabled, disabled, and missing-state-file cases.
</content>
</entry>
<entry>
<title>fix(hyprland): paint scratchpad active border goldenrod</title>
<updated>2026-05-19T13:26:11+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-19T13:26:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=d3e6bdf03f68120909aa2db69760abbdb51844be'/>
<id>urn:sha1:d3e6bdf03f68120909aa2db69760abbdb51844be</id>
<content type='text'>
Pyprland 3.4+ applies `group deny` to scratchpads, which routes their
border through col.nogroup_border* instead of col.*_border. Set
col.nogroup_border_active to #daa520 (same as col.active_border) so
the scratchpad and tiled active borders read identically.

Also drop `pseudotile = true` from the unused dwindle{} block — this
config uses layout = master, so the dwindle settings never take effect.
</content>
</entry>
<entry>
<title>chore(hyprland): capture pypr output to a per-session log file</title>
<updated>2026-05-14T17:53:02+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-14T17:53:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=ed615c754788c4bedc19f46f9e7e1f74c12cd260'/>
<id>urn:sha1:ed615c754788c4bedc19f46f9e7e1f74c12cd260</id>
<content type='text'>
Pypr was sending stderr to /dev/null. So when its keybind clients
emitted red `hyprctl notify` banners after the daemon got stuck,
there was no trace to read. I followed the waybar / dunst /
hypridle / gammastep pattern already in the same exec-once block.
</content>
</entry>
<entry>
<title>feat(hyprland): hide cursor after 2 seconds of inactivity</title>
<updated>2026-05-13T15:30:58+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-13T15:30:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=847512be1f90e4bc8be1b3f008fed8d48e03ab4f'/>
<id>urn:sha1:847512be1f90e4bc8be1b3f008fed8d48e03ab4f</id>
<content type='text'>
I set cursor:inactive_timeout to 2.0 so the cursor disappears after a couple of seconds without motion and reappears on the next move.
</content>
</entry>
<entry>
<title>fix(hyprland): keep cursor in place on keyboard focus changes</title>
<updated>2026-05-13T15:11:31+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-13T15:11:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=3e388e20865189f5f812d22ec8703c2d80f8f931'/>
<id>urn:sha1:3e388e20865189f5f812d22ec8703c2d80f8f931</id>
<content type='text'>
I set cursor:no_warps to true so super+j/k and other keyboard focus moves stop teleporting the cursor to the center of the newly focused window.
</content>
</entry>
<entry>
<title>fix(hyprland): source conf.d at end so machine-local overrides win</title>
<updated>2026-05-08T00:03:46+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-08T00:03:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=64257ff711145b22812ae54df31d8b631c01e18e'/>
<id>urn:sha1:64257ff711145b22812ae54df31d8b631c01e18e</id>
<content type='text'>
The `source = $HOME/.config/hypr/conf.d/*.conf` line was at the top of `hyprland.conf` (line 9), before the `general`, `input`, `monitor`, and other blocks. Hyprland reads top to bottom, so anything later in the main file silently overrode whatever `conf.d/local.conf` set. `local.conf` exists so one machine can override the shared defaults, for instance a HiDPI laptop bumping its monitor scale or shrinking gaps. None of that worked.

I moved the source line to the end of the file behind a labeled section comment. Now per-machine overrides take effect. To verify, I dropped a `general { gaps_in = 99 }` into a temporary file in `conf.d/` and reloaded. `hyprctl getoption general:gaps_in` came back as 99 instead of the main file's 25. I removed the test file and the value went back to 25.
</content>
</entry>
</feed>
