Compare commits

..

14 Commits

Author SHA1 Message Date
funman300 ef4d8cb44d docs: spec for fan-profile auto mode
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:58:54 -07:00
funman300 d4daad2071 waybar: reformat config.jsonc (editor auto-format)
Trailing commas added throughout and modules-right expanded to one
key per line. Semantically identical — waybar's JSONC parser accepts
trailing commas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:53:46 -07:00
funman300 c27f72a8a8 packages: add starship; swap swww for awww
starship is required by fish/config.fish (starship init fish | source)
but was missing — fresh installs would have a broken shell prompt.

swww was listed but the actually-installed wallpaper daemon is awww
(matching the niri/config.kdl change in the previous commit).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:53:46 -07:00
funman300 2b4054b44b niri: fix broken spawn-at-startup commands
- swww-daemon → awww-daemon (swww is not installed; awww 0.12.0-1 is)
- polkit-gnome-authentication-agent-1 → absolute path; the binary
  lives in /usr/lib/polkit-gnome/ which is not on PATH

Both daemons were silently failing to start at every login.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:53:46 -07:00
funman300 6372695b16 remove orphan files: autostart.sh and tracked mako/config
scripts/autostart.sh was never symlinked or referenced — niri's
spawn-at-startup directives cover everything it launched.

mako/config is gitignored (install.sh generates it from
theme/colors.json) but was still tracked from the initial commit.
The stale ~/.config/mako/config symlink that pointed at the repo
caused install.sh's writes to land back in the repo. Removed both
so install.sh now correctly produces a real generated file in
~/.config/mako/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:53:46 -07:00
funman300 c21a2834b7 revert tray drawer feature and remove mouse-battery module
The tray drawer added complexity (drawer config, custom chevron module,
state-feedback CSS) for what amounts to a small visual refinement.
Removed in favour of the original always-visible tray. The mouse-battery
indicator was also removed from the bar.

Deletes:
- waybar/mouse-battery.sh + symlink + install.sh entry
- group/tray-drawer + custom/mouse-battery blocks in config.jsonc
- #custom-tray-arrow rules from style.css
- docs/superpowers/{specs,plans} for the drawer feature

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:41:00 -07:00
funman300 2c851c7561 add waybar-restart script and Mod+Shift+B keybind
scripts/waybar-restart.sh: kills waybar, waits for it to exit, then
relaunches detached via setsid. Symlinked into ~/.local/bin and bound
to Mod+Shift+B in niri.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:59:33 -07:00
funman300 1305b1cda1 docs: sync tray drawer plan with shipped color-shift implementation
Plan was originally written assuming `transform: rotate` would work
in GTK 3 CSS; it doesn't. Spec was already updated in 1646dfc; this
brings the plan in line so historical readers see the same approach
across spec, plan, and code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:35:57 -07:00
funman300 67fbea93a4 waybar: drop unused children-class from tray drawer
No CSS rule targets .tray-drawer-child — speculative key with no
consumer. YAGNI cleanup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:30:35 -07:00
funman300 1646dfcd90 waybar: drop unsupported CSS transform from tray drawer arrow
GTK 3 CSS (used by waybar) treats `transform` as a fatal parse error,
so the rotation approach killed waybar entirely. Use a color shift
from @tn-fg-muted to @tn-fg as the expanded-state feedback instead.
Matches the existing style.css convention (battery/cpu/temperature
states all use color shifts, not transforms).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:29:58 -07:00
funman300 8b35df2989 waybar: style tray drawer chevron with rotation feedback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 21:27:00 -07:00
funman300 51353cecd0 waybar: collapse tray icons behind a click-to-reveal drawer
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:22:48 -07:00
funman300 17abe4651e waybar: switch clock display to 12hr format
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:22:48 -07:00
funman300 412034ea9f docs: spec for waybar tray drawer (collapsible icons)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 21:14:13 -07:00
9 changed files with 178 additions and 49 deletions
@@ -0,0 +1,142 @@
# Fan-Profile "Auto" Mode Design
**Date:** 2026-05-01
**Status:** Approved
## Summary
Add a virtual `auto` strategy to the waybar fan-profile module. When auto is on, `scripts/fan-profile.sh` keeps `fw-fanctrl` in sync with the active `power-profiles-daemon` profile — `power-saver``lazy`, `balanced``medium`, `performance``agile`. Reconciliation rides waybar's existing 5 s poll; no new daemon, no udev hooks, no fw-fanctrl strategy edits.
## Current Behaviour
`scripts/fan-profile.sh` is invoked by waybar's `custom/fan-profile` module on a 5 s interval and on click:
- **Status emit:** runs `fw-fanctrl print`, parses out the active strategy and current speed, prints a JSON line with an icon and tooltip.
- **`--menu`:** runs `fw-fanctrl print list`, pipes the strategy names through wofi, calls `fw-fanctrl use <choice>`, signals `pkill -RTMIN+9 waybar` so the bar refreshes.
The strategy list is whatever `fw-fanctrl print list` returns: `laziest, lazy, medium, agile, very-agile, deaf, aeolus`. There is currently no notion of an automatic mode.
## Target Behaviour
### Wofi menu
A new entry `auto` is prepended to the strategy list before passing it to wofi. Selecting it:
1. Touches the state file `~/.local/state/fan-profile-auto`.
2. Resolves the current power profile and calls `fw-fanctrl use <mapped>` once.
3. Signals waybar to refresh.
Selecting any non-`auto` strategy:
1. Removes the state file (if it exists).
2. Calls `fw-fanctrl use <choice>` (current behaviour, unchanged).
3. Signals waybar to refresh.
### Status emit (every 5 s)
```
state file exists?
├── yes → read powerprofilesctl get
│ ├── ok → resolve mapped strategy
│ │ ├── differs from fw-fanctrl's active → fw-fanctrl use <mapped>
│ │ └── matches → no-op
│ │ emit JSON: text="auto", tooltip="auto → <mapped>", class="auto"
│ └── error → emit JSON: text="auto (?)", tooltip="auto: power-profiles-daemon unreachable", class="auto"
└── no → existing behaviour: emit fw-fanctrl's active strategy
```
### Mapping
| power-profiles-daemon | fw-fanctrl |
|---|---|
| `power-saver` | `lazy` |
| `balanced` | `medium` |
| `performance` | `agile` |
Hardcoded in the script — small, stable, doesn't need a config file. If a profile name comes back unrecognized (e.g. a custom profile), the script falls into the error branch above (`auto (?)`).
## Implementation
### `scripts/fan-profile.sh` (only file changed)
Three additions to the existing script:
1. **State path constant** at top:
```bash
STATE_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/fan-profile-auto"
```
2. **Mapping function**:
```bash
map_profile_to_strategy() {
case "$1" in
power-saver) echo lazy ;;
balanced) echo medium ;;
performance) echo agile ;;
*) return 1 ;;
esac
}
```
3. **Menu branch** — prepend `auto` and route the choice:
```bash
if [ "$1" = "--menu" ]; then
STRATS=$(fw-fanctrl print list 2>/dev/null | grep "^-" | sed 's/^- //')
CHOICE=$(printf 'auto\n%s\n' "$STRATS" | wofi --dmenu --prompt "Fan Strategy:" \
--width 260 --height 320 --hide-scroll --no-actions --insensitive)
[ -z "$CHOICE" ] && exit
if [ "$CHOICE" = "auto" ]; then
mkdir -p "$(dirname "$STATE_FILE")"
touch "$STATE_FILE"
PROFILE=$(powerprofilesctl get 2>/dev/null) && \
MAPPED=$(map_profile_to_strategy "$PROFILE") && \
fw-fanctrl use "$MAPPED"
else
rm -f "$STATE_FILE"
fw-fanctrl use "$CHOICE"
fi
pkill -RTMIN+9 waybar
exit
fi
```
4. **Status branch** — wrap the existing emit with auto-mode handling:
```bash
if [ -f "$STATE_FILE" ]; then
PROFILE=$(powerprofilesctl get 2>/dev/null)
MAPPED=$(map_profile_to_strategy "$PROFILE" 2>/dev/null)
if [ -n "$MAPPED" ]; then
ACTIVE=$(fw-fanctrl print 2>/dev/null | awk -F"'" '/^Strategy:/{print $2}')
[ "$ACTIVE" != "$MAPPED" ] && fw-fanctrl use "$MAPPED" >/dev/null 2>&1
printf '{"text": "󰈐 auto", "tooltip": "Auto fan strategy\\nProfile: %s → %s\\nClick to change", "class": "auto"}\n' "$PROFILE" "$MAPPED"
else
printf '{"text": "󰈐 auto (?)", "tooltip": "Auto: power-profiles-daemon unreachable or unknown profile\\nClick to change", "class": "auto"}\n'
fi
exit
fi
# ... existing status emit (fw-fanctrl print → icon/level → JSON) ...
```
### Reconciliation cadence
Waybar polls `custom/fan-profile` every 5 s (`"interval": 5` in `waybar/config.jsonc`). Each poll runs the script, which reads the state file and reconciles. No additional daemon, signal, or hook is needed. Worst-case desync: 5 s after a power-profile change.
The existing `pkill -RTMIN+9 waybar` from `power-profile.sh --menu` will trigger an immediate refresh when the user changes profile via the bar — so in the common case, the fan strategy switches within waybar's render cycle, not 5 s later.
### Persistence
State file lives at `$XDG_STATE_HOME/fan-profile-auto` (default `~/.local/state/fan-profile-auto`). XDG state dir survives reboot, so auto stays on across sessions. Removing the file (or selecting any non-auto strategy) disables auto mode.
## Files Touched
- `scripts/fan-profile.sh` — three additions (state constant, mapping function, two new branches in menu and status handlers).
No CSS, no waybar config, no install.sh changes.
## Out of Scope
- Syncing the auto-on state across machines (would require moving the state file into `~/.config/` and tracking it in the dotfiles repo).
- Mapping to strategies other than `lazy`/`medium`/`agile`. The user can edit the mapping function inline if they want different curves later.
- Reacting to anything other than power-profiles-daemon (CPU temp, AC vs battery, etc.). Those were rejected during brainstorming in favour of the cleaner power-profile coupling.
- A separate icon for auto mode. Reuses the existing `󰈐` glyph; the `auto` text in the bar is the differentiator.
- Tracking `/etc/fw-fanctrl/config.json` in the dotfiles repo (raised during clarifications, not adopted — auto doesn't need any new fw-fanctrl strategies).
+1 -1
View File
@@ -25,7 +25,6 @@ ln -sf "$(pwd)/networkmanager-dmenu/config.ini" ~/.config/networkmanager-dmenu/c
ln -sf "$(pwd)/niri/config.kdl" ~/.config/niri/config.kdl
ln -sf "$(pwd)/waybar/config.jsonc" ~/.config/waybar/config.jsonc
ln -sf "$(pwd)/waybar/style.css" ~/.config/waybar/style.css
ln -sf "$(pwd)/waybar/mouse-battery.sh" ~/.config/waybar/mouse-battery.sh
mkdir -p ~/.config/theme
ln -sf "$(pwd)/theme/colors.css" ~/.config/theme/colors.css
ln -sf "$(pwd)/wofi/config" ~/.config/wofi/config
@@ -59,6 +58,7 @@ ln -sf "$(pwd)/scripts/clipboard.sh" ~/.local/bin/clipboard-picker
ln -sf "$(pwd)/scripts/power-profile.sh" ~/.local/bin/power-profile
ln -sf "$(pwd)/scripts/fan-profile.sh" ~/.local/bin/fan-profile
ln -sf "$(pwd)/scripts/screenshot.sh" ~/.local/bin/screenshot
ln -sf "$(pwd)/scripts/waybar-restart.sh" ~/.local/bin/waybar-restart
echo "==> Enabling systemd user services"
mkdir -p ~/.config/systemd/user
-5
View File
@@ -1,5 +0,0 @@
background-color=#1d1f21
text-color=#c5c8c6
border-size=2
border-color=#81a2be
default-timeout=4000
+3 -2
View File
@@ -33,9 +33,9 @@ input {
spawn-at-startup "waybar"
spawn-at-startup "mako"
spawn-at-startup "swww-daemon"
spawn-at-startup "awww-daemon"
spawn-at-startup "nm-applet" "--indicator"
spawn-at-startup "polkit-gnome-authentication-agent-1"
spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
spawn-at-startup "swayidle" "-w" "timeout" "300" "niri msg action power-off-monitors" "timeout" "600" "gtklock" "-d" "timeout" "1800" "systemctl suspend" "before-sleep" "gtklock" "-d"
spawn-at-startup "wl-paste" "--watch" "cliphist" "store"
spawn-at-startup "blueman-applet"
@@ -52,6 +52,7 @@ binds {
Mod+Return { spawn "alacritty"; }
Mod+D { spawn "wofi" "--show" "drun"; }
Mod+E { spawn "thunar"; }
Mod+Shift+B { spawn "waybar-restart"; }
Mod+H { focus-column-left; }
Mod+L { focus-column-right; }
+2 -1
View File
@@ -3,7 +3,7 @@ waybar
wofi
mako
alacritty
swww
awww
grim
slurp
swappy
@@ -38,3 +38,4 @@ xwayland-satellite
power-profiles-daemon
fw-fanctrl
satty
starship
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
waybar &
mako &
swww-daemon &
nm-applet --indicator &
polkit-gnome-authentication-agent-1 &
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
pkill -x waybar
while pgrep -x waybar >/dev/null; do sleep 0.05; done
setsid -f waybar </dev/null >/dev/null 2>&1
+25 -23
View File
@@ -5,14 +5,16 @@
"modules-left": ["niri/workspaces"],
"modules-center": ["custom/clock"],
"modules-right": ["cpu", "temperature", "custom/power-profile", "custom/fan-profile", "pulseaudio", "network", "battery", "custom/mouse-battery", "tray"],
"custom/mouse-battery": {
"exec": "~/.config/waybar/mouse-battery.sh",
"interval": 60,
"format": " {output}",
"tooltip": false
},
"modules-right": [
"cpu",
"temperature",
"custom/power-profile",
"custom/fan-profile",
"pulseaudio",
"network",
"battery",
"tray",
],
"cpu": {
"format": " {usage}%",
"format-tooltip": "{usage}% total\n{icon0} {icon1} {icon2} {icon3}\n{icon4} {icon5} {icon6} {icon7}\n{icon8} {icon9} {icon10} {icon11}",
@@ -20,8 +22,8 @@
"interval": 3,
"states": {
"warning": 60,
"critical": 85
}
"critical": 85,
},
},
"temperature": {
@@ -31,8 +33,8 @@
"format-critical": " {temperatureC}°C",
"states": {
"warm": 60,
"critical": 80
}
"critical": 80,
},
},
"custom/power-profile": {
@@ -40,7 +42,7 @@
"return-type": "json",
"interval": 30,
"signal": 8,
"on-click": "~/.local/bin/power-profile --menu"
"on-click": "~/.local/bin/power-profile --menu",
},
"custom/fan-profile": {
@@ -48,40 +50,40 @@
"return-type": "json",
"interval": 5,
"signal": 9,
"on-click": "~/.local/bin/fan-profile --menu"
"on-click": "~/.local/bin/fan-profile --menu",
},
"custom/clock": {
"exec": "date '+%a %b %d %H:%M'",
"exec": "date '+%a %b %d %-I:%M %p'",
"interval": 30,
"format": "{}",
"tooltip": false
"tooltip": false,
},
"battery": {
"format": "{capacity}% {icon}",
"format-charging": "{capacity}% ",
"format-plugged": "{capacity}% ",
"format-icons": ["","","","",""],
"format-icons": ["", "", "", "", ""],
"states": {
"warning": 30,
"critical": 15
}
"critical": 15,
},
},
"tray": {
"spacing": 8
"spacing": 8,
},
"network": {
"format-wifi": " {essid}",
"format-ethernet": "󰈀",
"format-disconnected": "⚠",
"on-click": "networkmanager_dmenu"
"on-click": "networkmanager_dmenu",
},
"pulseaudio": {
"format": " {volume}%",
"format-muted": ""
}
"format-muted": "",
},
}
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash
# Generic mouse battery script for Waybar
MOUSE_BATTERY=$(upower -e | grep -i mouse | head -n1)
if [ -n "$MOUSE_BATTERY" ]; then
upower -i "$MOUSE_BATTERY" | awk '/percentage:/ { print $2 }'
else
echo "N/A"
fi