<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=8c32bbbf9fab115dc51afa17c081e0763cbee717'/>
<id>urn:sha1:8c32bbbf9fab115dc51afa17c081e0763cbee717</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=8fa87052ed0070077900ab348ecedf7ed010a916'/>
<id>urn:sha1:8fa87052ed0070077900ab348ecedf7ed010a916</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=539b5db3f7e86233ed493d735732d9f2fd26021f'/>
<id>urn:sha1:539b5db3f7e86233ed493d735732d9f2fd26021f</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=e38faddffbb6a7a7bd62bfb32a54a0d72ba14af8'/>
<id>urn:sha1:e38faddffbb6a7a7bd62bfb32a54a0d72ba14af8</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=8bb842ca37c348b3fb885c6d0f83d7e284800955'/>
<id>urn:sha1:8bb842ca37c348b3fb885c6d0f83d7e284800955</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=5871ee7bdd9a618ca330e1bd58176f57aefc4dbe'/>
<id>urn:sha1:5871ee7bdd9a618ca330e1bd58176f57aefc4dbe</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=56cb549ad3b2295295b1a31265ddff02a421b951'/>
<id>urn:sha1:56cb549ad3b2295295b1a31265ddff02a421b951</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=800995ecbd5c56ef194496c9e2d63835a28f8b5c'/>
<id>urn:sha1:800995ecbd5c56ef194496c9e2d63835a28f8b5c</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=77d67de1056e5b91f6a1a450c7f99fde0591c011'/>
<id>urn:sha1:77d67de1056e5b91f6a1a450c7f99fde0591c011</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=c69ad4399c0d61418ace1863d2240c1e0400ee61'/>
<id>urn:sha1:c69ad4399c0d61418ace1863d2240c1e0400ee61</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>
