1313 ; Variables with polling - set initial values to avoid empty string errors
1414 (defpoll time :interval "1s" :initial "00:00" "date '+%H:%M'")
1515 (defpoll date :interval "60s" :initial "0000-00-00" "date '+%Y-%m-%d'")
16- (defpoll cpu :interval "2s" :initial 0 "${ lib . getExe cpuScript } ")
16+ (defpoll cpu :interval "2s" :initial '{"usage": 0, "load": "0.00", "freq": 0}' "${ lib . getExe cpuScript } ")
1717 (defpoll memory :interval "2s" :initial 0 "${ lib . getExe memScript } ")
18- (defpoll temperature :interval "2s" :initial 0 "${ lib . getExe tempScript } ")
18+ (defpoll temperature :interval "2s" :initial '{"temp": 0, "fan": 0}' "${ lib . getExe tempScript } ")
1919 (defpoll battery :interval "10s" :initial '{"capacity": "100", "icon": "", "watts": "0", "time_remaining": "--", "status": "Full"}' "${ lib . getExe batteryScript } ")
2020 (defpoll volume :interval "1s" :initial '{"level": "0", "icon": ""}' "${ lib . getExe volumeScript } ")
2121 (defpoll network :interval "5s" :initial " ..." "${ lib . getExe networkScript } ")
22+ (defpoll brightness :interval "1s" :initial 100 "${ lib . getExe brightnessScript } ")
23+ (defpoll idle-inhibited :interval "0.5s" :initial "false" "${ lib . getExe idleStatusScript } ")
2224 (deflisten workspaces :initial '[]' "${ lib . getExe workspacesScript } ")
2325
2426 ; Widget definitions
4042 (box :class "right" :orientation "h" :space-evenly false :halign "end" :spacing 8
4143 (network-widget)
4244 (volume-widget)
43- (graph-widget :value cpu :icon "" :class "cpu" :unit "%")
45+ (graph-widget :value { cpu.usage} :icon "" :class "cpu" :unit "%" :tooltip "Load: '' ${cpu.load} | '' ${cpu.freq} MHz ")
4446 (graph-widget :value memory :icon "" :class "memory" :unit "%")
45- (graph-widget :value temperature :icon "" :class "temp" :unit "°")
47+ (graph-widget :value {temperature.temp} :icon "" :class "temp" :unit "°" :tooltip "Fan: '' ${temperature.fan} RPM")
48+ (brightness-widget)
4649 (battery-widget)
50+ (idle-inhibitor)
4751 (label :class "date" :text "'' ${date}")
4852 (systray :class "systray" :icon-size 18 :spacing 4)))
4953
5458 :onclick "swaymsg workspace '' ${ws.name}"
5559 {ws.name}))))
5660
57- (defwidget graph-widget [value icon class unit]
61+ (defwidget graph-widget [value icon class unit ?tooltip ]
5862 (box :class "graph-module '' ${class}" :orientation "h" :space-evenly false :spacing 4
63+ :tooltip {tooltip ?: ""}
5964 (graph :class "graph"
6065 :value value
6166 :thickness 3
8085 (box :class "network" :orientation "h" :space-evenly false
8186 (label :text "'' ${network}")))
8287
88+ (defwidget brightness-widget []
89+ (button :class "brightness" :onclick "/run/current-system/sw/bin/switch-theme toggle"
90+ (label :text "'' ${brightness}% ")))
91+
92+ (defwidget idle-inhibitor []
93+ (button :class {idle-inhibited == "true" ? "idle-inhibitor active" : "idle-inhibitor"}
94+ :onclick "${ lib . getExe idleToggleScript } "
95+ {idle-inhibited == "true" ? "" : ""}))
96+
8397 ; Window definition - screen name passed as argument
8498 (defwindow bar [screen]
8599 :monitor screen
@@ -153,13 +167,27 @@ let
153167 min-height: 20px;
154168 }
155169
156- .battery, .volume, .network, .date {
170+ .battery, .volume, .network, .date, .brightness {
157171 padding: 0 8px;
158172 margin: 0 2px;
159173 border-radius: 4px;
160174 background-color: #24283b;
161175 }
162176
177+ .idle-inhibitor {
178+ padding: 0 8px;
179+ margin: 0 2px;
180+ border-radius: 4px;
181+ background-color: #24283b;
182+ &.active {
183+ background-color: #bb9af7;
184+ color: #1a1b26;
185+ }
186+ &:hover {
187+ background-color: #414868;
188+ }
189+ }
190+
163191 .systray {
164192 padding: 0 8px;
165193 margin: 0 2px;
176204
177205 cpuScript = pkgs . writeShellApplication {
178206 name = "eww-cpu" ;
207+ runtimeInputs = [ pkgs . jq ] ;
179208 text = ''
180209 STATE_FILE="/tmp/eww-cpu-state"
181210 read -r _cpu user nice system idle _rest < /proc/stat
@@ -186,14 +215,34 @@ let
186215 diff_total=$((total - prev_total))
187216 diff_idle=$((idle - prev_idle))
188217 if [ "$diff_total" -gt 0 ]; then
189- echo $((100 * (diff_total - diff_idle) / diff_total))
218+ usage= $((100 * (diff_total - diff_idle) / diff_total))
190219 else
191- echo 0
220+ usage= 0
192221 fi
193222 else
194- echo 0
223+ usage= 0
195224 fi
196225 echo "$total $idle" > "$STATE_FILE"
226+
227+ # Get load average (1 min)
228+ load=$(cut -d' ' -f1 /proc/loadavg)
229+
230+ # Get average CPU frequency in MHz
231+ freq=0
232+ count=0
233+ for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq; do
234+ if [ -f "$f" ]; then
235+ val=$(cat "$f")
236+ freq=$((freq + val))
237+ count=$((count + 1))
238+ fi
239+ done
240+ if [ "$count" -gt 0 ]; then
241+ freq=$((freq / count / 1000))
242+ fi
243+
244+ jq -n --argjson usage "$usage" --arg load "$load" --argjson freq "$freq" \
245+ '{usage: $usage, load: $load, freq: $freq}'
197246 '' ;
198247 } ;
199248
207256
208257 tempScript = pkgs . writeShellApplication {
209258 name = "eww-temp" ;
259+ runtimeInputs = [ pkgs . jq ] ;
210260 text = ''
211- temp_raw=$(cat /sys/class/thermal/thermal_zone0/temp)
212- echo $((temp_raw / 1000))
261+ temp_raw=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null || echo 0)
262+ temp=$((temp_raw / 1000))
263+
264+ # Find gpdfan hwmon for fan speed
265+ fan=0
266+ for hwmon in /sys/class/hwmon/hwmon*; do
267+ if [ "$(cat "$hwmon/name" 2>/dev/null)" = "gpdfan" ]; then
268+ fan=$(cat "$hwmon/fan1_input" 2>/dev/null || echo 0)
269+ break
270+ fi
271+ done
272+
273+ jq -n --argjson temp "$temp" --argjson fan "$fan" '{temp: $temp, fan: $fan}'
213274 '' ;
214275 } ;
215276
340401 '' ;
341402 } ;
342403
404+ brightnessScript = pkgs . writeShellApplication {
405+ name = "eww-brightness" ;
406+ runtimeInputs = [ pkgs . brightnessctl ] ;
407+ text = ''
408+ brightnessctl -m | cut -d, -f4 | tr -d '%'
409+ '' ;
410+ } ;
411+
412+ idleToggleScript = pkgs . writeShellApplication {
413+ name = "eww-idle-toggle" ;
414+ runtimeInputs = [ pkgs . systemd ] ;
415+ text = ''
416+ if systemctl --user is-active --quiet sway-idle-inhibit.service; then
417+ systemctl --user stop sway-idle-inhibit.service
418+ else
419+ systemctl --user start sway-idle-inhibit.service
420+ fi
421+ '' ;
422+ } ;
423+
424+ idleStatusScript = pkgs . writeShellApplication {
425+ name = "eww-idle-status" ;
426+ runtimeInputs = [ pkgs . systemd ] ;
427+ text = ''
428+ if systemctl --user is-active --quiet sway-idle-inhibit.service; then
429+ echo "true"
430+ else
431+ echo "false"
432+ fi
433+ '' ;
434+ } ;
435+
343436 ewwConfigDir = pkgs . runCommand "eww-config" { } ''
344437 mkdir -p $out
345438 cp ${ ewwYuck } $out/eww.yuck
378471 pkgs . bash
379472 pkgs . sway
380473 ] ;
474+ environment . EWW_CONFIG = "${ ewwConfigDir } " ;
381475 serviceConfig = {
382476 Type = "simple" ;
383- ExecStart = "${ pkgs . eww } /bin/eww daemon --config ${ ewwConfigDir } --no-daemonize" ;
384- ExecStop = "${ pkgs . eww } /bin/eww --config ${ ewwConfigDir } kill" ;
477+ ExecStart = "${ lib . getExe pkgs . eww } daemon --config ${ ewwConfigDir } --no-daemonize" ;
478+ ExecStop = "${ lib . getExe pkgs . eww } --config ${ ewwConfigDir } kill" ;
385479 Restart = "on-failure" ;
386480 RestartSec = 1 ;
387481 } ;
388482 } ;
389483
484+ # Idle inhibit service - toggled by eww button
485+ systemd . user . services . sway-idle-inhibit = {
486+ description = "Inhibit idle/sleep" ;
487+ serviceConfig = {
488+ Type = "simple" ;
489+ ExecStart = "${ pkgs . systemd } /bin/systemd-inhibit --what=idle:sleep --who=eww --why='User requested' --mode=block sleep infinity" ;
490+ } ;
491+ } ;
492+
390493 # eww bar per output - template unit using output name (e.g. eww-bar@eDP-1.service)
391494 systemd . user . services . "eww-bar@" = {
392495 description = "Eww bar on output %i" ;
0 commit comments