diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..d2781da --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,14 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:elkowar.github.io)", + "WebFetch(domain:github.com)", + "WebFetch(domain:raw.githubusercontent.com)", + "WebSearch", + "WebFetch(domain:deepwiki.com)", + "Bash(amdgpu_top -J -s 1000 -d 1)", + "Bash(amdgpu_top -J -s 1000 -n 1)", + "Bash(sensors -j)" + ] + } +} diff --git a/modules/home/wayland/apps/eww/bar/css/_colors.scss b/modules/home/wayland/apps/eww/bar/css/_colors.scss new file mode 100644 index 0000000..b780c9c --- /dev/null +++ b/modules/home/wayland/apps/eww/bar/css/_colors.scss @@ -0,0 +1,29 @@ +$base00: #000000; +$base01: #060a0f; +$base02: #212c38; +$base03: #3f5268; +$base04: #617b9a; +$base05: #90a7c1; +$base06: #c9d3df; +$base07: #fcfcfc; +$base08: #ffac56; +$base09: #feea74; +$base0A: #bffe8a; +$base0B: #4cfefa; +$base0C: #62acfd; +$base0D: #9b9bfd; +$base0E: #fe9bda; +$base0F: #fc8999; + + +$fg: $base07; +$bg0: $base00; +$bg1: $base01; + +$border-color: $base03; +$border-color-focus: $base04; +$border-radius: 8px; +$border-width: 2px; + +$gaps-screen: 8px; +$gaps-window: 4px; \ No newline at end of file diff --git a/modules/home/wayland/apps/eww/bar/css/_net.scss b/modules/home/wayland/apps/eww/bar/css/_net.scss index 516d914..d457638 100644 --- a/modules/home/wayland/apps/eww/bar/css/_net.scss +++ b/modules/home/wayland/apps/eww/bar/css/_net.scss @@ -1,8 +1,9 @@ - -.net { - color: $base07; +.net-icon { + font-size: 14px; + padding: 3pt 0; } -.blt { - color: $base0C; -} \ No newline at end of file +.net-active { color: $base07; } +.net-dim { color: $base02; } +.blt-on { color: $base07; } +.blt-connected { color: $base0D; } diff --git a/modules/home/wayland/apps/eww/bar/css/_sys.scss b/modules/home/wayland/apps/eww/bar/css/_sys.scss index d189c65..b4e5a08 100644 --- a/modules/home/wayland/apps/eww/bar/css/_sys.scss +++ b/modules/home/wayland/apps/eww/bar/css/_sys.scss @@ -1,69 +1,186 @@ -.cpubar { -color: $base0C; -} - -.gpubar { -color: $base0E; -} - -.membar { -color: $base08; -} - -.batbar { -color: $base0B; -} - -.cpubar, -.gpubar, -.membar, -.batbar { - background-color: $bg0; - margin: $gaps-window 0; -} - -.cpu-core-usage, .gpu-core-usage, .memory-usage { - background-color: $bg0; - border-radius: $border-radius; - padding: 2pt; - margin: 1pt; - -} - -.cpu-core-usage trough * { - background-color: $base0C; - border-radius: $border-radius; - padding: 2pt; -} -.gpu-core-usage trough * { - background-color: $base0E; - border-radius: $border-radius; - padding: 2pt; -} - -.memory-usage trough * { - background-color: $base08; - border-radius: $border-radius; - padding: 2pt; -} - - -.spacer { - color: $bg1; - padding: $gaps-window; - margin:0; +// Bar module rings +.cpubar { color: $base0C; } +.gpubar { color: $base0E; } +.membar { color: $base08; } +.batbar { color: $base0B; } + +.cpubar, .gpubar, .membar, .batbar { + background-color: $bg0; + margin: $gaps-window 0; } +// Window .sys-win { - // @include window; - // background-color: $bg1; - // color: $fg; - // margin: $gaps-win; - padding: 5pt; + padding: 10pt; +} + +.sys-section { + margin-bottom: 0; +} + +.sys-section-header { + margin-bottom: 10pt; } .sys-label { - font-weight: bolder; - color: $base04; -} \ No newline at end of file + font-size: 0.72em; + font-weight: bold; + letter-spacing: 0.14em; + color: $base05; +} + +.section-accent { + min-width: 3px; + border-radius: 2px; + margin-right: 8pt; +} + +.cpu-accent { background-color: $base0C; } +.gpu-accent { background-color: $base0E; } +.ram-accent { background-color: $base08; } +.bat-accent { background-color: $base0B; } + +.section-sep { + background-color: $base02; + min-height: 2px; + margin: 6pt 0 10pt 0; +} + +.sys-sublabel { + font-size: 0.72em; + color: $base04; + margin-right: 8pt; +} + +// CPU grid +.cpu-usage-ring { + color: $base0C; + background-color: $bg0; + margin: 3pt; +} + +// Inner freq ring — margin shrinks it inside overlay for concentric effect +// 0% = cpu min freq, 100% = cpu max freq +.cpu-freq-ring { + color: $base0D; + background-color: $bg0; + margin: 12px; +} + +.cpu-core-label { + font-size: 0.7em; + color: $base05; +} + +// GPU rings +.gpu-ring { + color: $base0E; + background-color: $bg0; + margin: 3pt; +} + +.gpu-freq-ring { + color: $base0D; + background-color: $bg0; + margin: 13px; +} + +.gpu-ring-value { + font-size: 0.82em; + font-weight: bold; + color: $base05; +} + +.gpu-ring-label { + font-size: 0.62em; + color: $base04; + margin-top: 2pt; +} + +// GPU stats row +.gpu-stats-row { + margin-top: 6pt; + margin-bottom: 2pt; +} + +.gpu-stat-value { + font-size: 0.85em; + font-weight: bold; + color: $base05; +} + +.gpu-stat-label { + font-size: 0.62em; + color: $base04; +} + +// VRAM bar +.vram-row { + margin-top: 6pt; +} + +.vram-bar { + background-color: $bg0; + border-radius: $border-radius; + padding: 4pt; +} + +.vram-bar trough * { + background-color: $base0E; + border-radius: $border-radius; +} + +.vram-usage-label { + font-size: 0.62em; + color: $base04; + margin-top: 2pt; +} + +// RAM ring +.ram-ring { + color: $base08; + background-color: $bg0; + margin: 4pt; +} + +.ram-cached-ring { + color: $base02; + background-color: transparent; + margin: 4pt; +} + +.ram-used-label { + font-size: 0.95em; + font-weight: bold; + color: $base05; +} + +.ram-total-label { + font-size: 0.72em; + color: $base04; +} + +// Swap ring +.swap-ring { + color: $base09; + background-color: $bg0; + margin: 3pt; +} + +.swap-section-label { + font-size: 0.62em; + color: $base04; + margin-top: 2pt; +} + +// Battery ring +.bat-ring { + background-color: $bg0; + margin: 4pt; +} + +.bat-ring-label { + font-size: 0.7em; + color: $base05; +} diff --git a/modules/home/wayland/apps/eww/bar/modules/net.yuck b/modules/home/wayland/apps/eww/bar/modules/net.yuck index baaa57b..24b2bbf 100644 --- a/modules/home/wayland/apps/eww/bar/modules/net.yuck +++ b/modules/home/wayland/apps/eww/bar/modules/net.yuck @@ -1,17 +1,23 @@ -(deflisten net :initial '{"name":"","icon":""}'"scripts/net/net") +(deflisten net + :initial '{"wifi":{"connected":false,"icon":"󰤮","ssid":""},"ethernet":{"connected":false}}' + "scripts/net/net") + +(deflisten bluetooth + :initial '{"powered":false,"connected":false,"device":""}' + "scripts/net/bluetooth") (defwidget net-mod [] (module - (box - :orientation "v" - (button - :class "net" - :tooltip {net.name} - {net.icon}) - - (button - :class "blt" - (label :class "icon-text" :text "B")) - ) - ) -) \ No newline at end of file + (box :orientation "v" + (label + :class "net-icon ${net.ethernet.connected ? 'net-active' : 'net-dim'}" + :tooltip {net.ethernet.connected ? "Ethernet: Connected" : "Ethernet: Disconnected"} + :text "󰈀") + (label + :class "net-icon ${net.wifi.connected ? 'net-active' : 'net-dim'}" + :tooltip {net.wifi.connected ? "WiFi: ${net.wifi.ssid}" : "WiFi: Disconnected"} + :text {net.wifi.icon}) + (label + :class "net-icon ${bluetooth.connected ? 'blt-connected' : bluetooth.powered ? 'blt-on' : 'net-dim'}" + :tooltip {bluetooth.connected ? "Bluetooth: ${bluetooth.device}" : bluetooth.powered ? "Bluetooth: On" : "Bluetooth: Off"} + :text {bluetooth.connected ? "󰂱" : bluetooth.powered ? "󰂯" : "󰂲"})))) diff --git a/modules/home/wayland/apps/eww/bar/modules/sys.yuck b/modules/home/wayland/apps/eww/bar/modules/sys.yuck index 348c8af..0d70bfe 100644 --- a/modules/home/wayland/apps/eww/bar/modules/sys.yuck +++ b/modules/home/wayland/apps/eww/bar/modules/sys.yuck @@ -1,6 +1,6 @@ (deflisten cpu :initial '{}' "scripts/sys/cpu") -(deflisten gpu :initial '{"devices":[{"GRBM2":{}}]}' "scripts/sys/gpu") -(deflisten memory :initial '{"human":{"used":"0G","total":"0G"},"used":0.0,"total":1.0}' "scripts/sys/memory") +(deflisten gpu :initial '{"gfx_pct":0,"mem_pct":0,"media_pct":0,"sclk":0,"mclk":0,"sclk_pct":0,"mclk_pct":0,"vclk":0,"vclk_pct":0,"temp":0,"power":0,"vram_used":0,"vram_total":1}' "scripts/sys/gpu") +(deflisten memory :initial '{"human":{"used":"0G","total":"0G","cached":"0G"},"used":0.0,"total":1.0,"cached":0.0}' "scripts/sys/memory") (deflisten battery :initial '{"visible":false,"percentage":0.0,"color":"#FFFFFF"}' "scripts/sys/battery") @@ -8,35 +8,26 @@ (module (eventbox :onclick "(sleep 0.1 && eww-open-on-current-screen sys --toggle)" - (box - :orientation "v" - (circular-progress - :value {EWW_CPU.avg} - :class "cpubar" - :thickness 6 - (label :class "icon-text" :text "C")) - - (circular-progress - :value {gpu.devices[0].GRBM2?.CommandProcessor-Graphics?.value?:0} - :class "gpubar" - :thickness 6 - (label :class "icon-text" :text "G")) + (box :orientation "v" + (circular-progress + :value {EWW_CPU.avg} + :class "cpubar" + :width 28 :height 28 :thickness 6 + :tooltip "CPU ${round(EWW_CPU.avg, 0)}%") + (circular-progress + :value {gpu.gfx_pct} + :class "gpubar" + :width 28 :height 28 :thickness 6 + :tooltip "GPU ${round(gpu.gfx_pct, 0)}%") (circular-progress :value {100*memory.used/memory.total} :class "membar" - :thickness 6 - :tooltip "${memory.human.used} / ${memory.human.total}" - (label :class "icon-text" :text "M")) - + :width 28 :height 28 :thickness 6 + :tooltip "RAM ${memory.human.used} / ${memory.human.total}") (circular-progress :value {battery.percentage} :class "batbar" :visible {battery.visible} :style "color: ${battery.color};" - :thickness 6 - :tooltip "${battery.status} @ ${battery.wattage}" - (label :class "icon-text" :text "B")) - ) - ) - ) -) + :width 28 :height 28 :thickness 6 + :tooltip "Bat ${round(battery.percentage, 0)}% · ${battery.status} @ ${battery.wattage}"))))) diff --git a/modules/home/wayland/apps/eww/bar/scripts/net/bluetooth b/modules/home/wayland/apps/eww/bar/scripts/net/bluetooth new file mode 100755 index 0000000..3aa33be --- /dev/null +++ b/modules/home/wayland/apps/eww/bar/scripts/net/bluetooth @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +emit() { + local powered=false connected=false device="" + + if bluetoothctl show 2>/dev/null | grep -q "Powered: yes"; then + powered=true + while IFS= read -r line; do + mac=$(echo "$line" | awk '{ print $2 }') + info=$(bluetoothctl info "$mac" 2>/dev/null) + if echo "$info" | grep -q "Connected: yes"; then + device=$(echo "$info" | awk -F': ' '/^\tName:/ { print $2; exit }') + connected=true + break + fi + done < <(bluetoothctl devices 2>/dev/null) + fi + + printf '{"powered":%s,"connected":%s,"device":"%s"}\n' "$powered" "$connected" "$device" +} + +emit +bluetoothctl monitor 2>/dev/null | while IFS= read -r line; do + case "$line" in + *"Powered"*|*"Connected"*|*"Device"*) emit ;; + esac +done diff --git a/modules/home/wayland/apps/eww/bar/scripts/net/net b/modules/home/wayland/apps/eww/bar/scripts/net/net index aa6935b..0630be7 100755 --- a/modules/home/wayland/apps/eww/bar/scripts/net/net +++ b/modules/home/wayland/apps/eww/bar/scripts/net/net @@ -1,81 +1,47 @@ -#!/usr/bin/env zsh +#!/usr/bin/env bash -function get_time_ms { - date -u +%s%3N -} - -icons=("󰤯" "󰤟" "󰤢" "󰤥" "󰤨") - -function get_wifi_interface() { +get_wifi_iface() { awk 'NR > 2 { gsub(":", "", $1); print $1; exit }' /proc/net/wireless } -function toggle() { - status=$(rfkill | grep wlan | awk '{print $4}') - - if [ "$status" = "unblocked" ]; then - rfkill block wlan - else - rfkill unblock wlan - fi +signal_icon() { + local dbm="$1" + if [ -z "$dbm" ]; then echo "󰤮"; return; fi + if [ "$dbm" -ge -50 ]; then echo "󰤨" + elif [ "$dbm" -ge -60 ]; then echo "󰤥" + elif [ "$dbm" -ge -70 ]; then echo "󰤢" + elif [ "$dbm" -ge -80 ]; then echo "󰤟" + else echo "󰤯"; fi } -function gen_wifi() { - wifi_iface=$(get_wifi_interface) - signal=$(awk -v iface="$wifi_iface" '$1 == iface ":" { print $3; exit }' /proc/net/wireless) - level=$(awk -v n="$signal" 'BEGIN{print int((n-1)/20)}') - if [ "$level" -gt 4 ]; then - level=4 +make_content() { + local wifi_iface eth_iface + + wifi_iface=$(get_wifi_iface) + eth_iface=$(ip link | awk '/^[0-9]+: en[po]/ { gsub(":",""); print $2; exit }') + + # Ethernet + local eth_connected=false + if [ -n "$eth_iface" ]; then + eth_state=$(ip link show "$eth_iface" 2>/dev/null | awk '/state/ { print $9 }') + [ "$eth_state" = "UP" ] && eth_connected=true fi - icon=${icons[$level]} - ip="-" - class="net-connected" - name_raw=$(wpa_cli -g "/run/wpa_supplicant/$wifi_iface" status | grep \^ssid= | sed 's/ssid=//g') - name=$(printf "%s" "$name_raw") -} - -function gen_ethernet() { - icon="󰈀" - class="net-connected" - ip="" - name=Wired -} - -function make_content() { - local ethernet wifi wifi_iface - ethernet=$(ip link | rg "^[0-9]+: en[po]+" | head -n1 | sed 's/[a-zA-Z0-9_,><:\ -]*state //g' | sed 's/ mode [a-zA-Z0-9 ]*//g') - wifi_iface=$(get_wifi_interface) - if [ -n "$wifi_iface" ]; then - wifi=$(wpa_cli -g "/run/wpa_supplicant/$wifi_iface" status | rg "^wpa_state=" | sed 's/wpa_state=//g') + # WiFi — use IP presence as connection indicator (more reliable than wpa_cli) + local wifi_connected=false wifi_icon="󰤮" wifi_ssid="" + if [ -n "$wifi_iface" ] && ip -4 addr show "$wifi_iface" 2>/dev/null | grep -q "inet "; then + wifi_connected=true + wifi_ssid=$(wpa_cli -g "/run/wpa_supplicant/$wifi_iface" status 2>/dev/null \ + | awk -F= '/^ssid=/ { print $2 }') + signal=$(awk -v iface="$wifi_iface" '$1 == iface ":" { gsub(/\./, "", $4); print $4; exit }' /proc/net/wireless) + wifi_icon=$(signal_icon "$signal") fi - # test ethernet first - if [[ $ethernet == "UP" ]]; then - gen_ethernet - elif [[ $wifi == "COMPLETED" ]]; then - gen_wifi - else - icon="󰤮" - ip="-" - class="net-disconnected" - name="Disconnected" - fi - - echo '{"icon": "'$icon'", "name": "'$name'", "ip": "'$ip'", "class": "'$class'"}' + printf '{"wifi":{"connected":%s,"icon":"%s","ssid":"%s"},"ethernet":{"connected":%s}}\n' \ + "$wifi_connected" "$wifi_icon" "$wifi_ssid" "$eth_connected" } -if [ "$1" = "toggle" ]; then - toggle -else - last_time=$(get_time_ms) +make_content +ip monitor | while read -r _; do make_content - ip monitor | while read -r _; do - current_time=$(get_time_ms) - delta=$((current_time - last_time)) - if [[ $delta -gt 50 ]]; then - make_content - last_time=$(get_time_ms) - fi - done -fi +done diff --git a/modules/home/wayland/apps/eww/bar/scripts/sys/cpugrid b/modules/home/wayland/apps/eww/bar/scripts/sys/cpugrid new file mode 100644 index 0000000..6b06792 --- /dev/null +++ b/modules/home/wayland/apps/eww/bar/scripts/sys/cpugrid @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +COLS=4 +declare -A prev_idle prev_total + +emit_grid() { + local rows=() row_items=() + while IFS= read -r line; do + [[ $line =~ ^cpu([0-9]+) ]] || continue + local core="${BASH_REMATCH[1]}" + read -ra f <<< "$line" + local idle=$(( f[4] + f[5] )) + local total=0 + for x in "${f[@]:1}"; do (( total += x )); done + + local usage="0.0" + if [[ -n "${prev_total[$core]+x}" ]]; then + local dt=$(( total - prev_total[$core] )) + local di=$(( idle - prev_idle[$core] )) + (( dt > 0 )) && usage=$(awk "BEGIN{printf \"%.1f\", 100*(1-$di/$dt)}") + fi + prev_idle[$core]=$idle + prev_total[$core]=$total + + local freq=0 + local fpath="/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_cur_freq" + [[ -r $fpath ]] && freq=$(( $(< "$fpath") / 1000 )) + + row_items+=("{\"core\":$core,\"usage\":$usage,\"freq\":$freq}") + + if (( ${#row_items[@]} == COLS )); then + local row; printf -v row '%s,' "${row_items[@]}"; row="${row%,}" + rows+=("[$row]") + row_items=() + fi + done < /proc/stat + + if (( ${#row_items[@]} > 0 )); then + local row; printf -v row '%s,' "${row_items[@]}"; row="${row%,}" + rows+=("[$row]") + fi + + local out; printf -v out '%s,' "${rows[@]}"; out="${out%,}" + echo "[$out]" +} + +while true; do + emit_grid + sleep 2 +done diff --git a/modules/home/wayland/apps/eww/bar/scripts/sys/cputemp b/modules/home/wayland/apps/eww/bar/scripts/sys/cputemp new file mode 100755 index 0000000..94f9a54 --- /dev/null +++ b/modules/home/wayland/apps/eww/bar/scripts/sys/cputemp @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +dir=$(grep -rl k10temp /sys/class/hwmon/*/name 2>/dev/null | head -1 | xargs dirname) +awk '{printf "%.0f\n", $1/1000}' "$dir/temp1_input" diff --git a/modules/home/wayland/apps/eww/bar/scripts/sys/gpu b/modules/home/wayland/apps/eww/bar/scripts/sys/gpu index 44ff401..ccea39a 100755 --- a/modules/home/wayland/apps/eww/bar/scripts/sys/gpu +++ b/modules/home/wayland/apps/eww/bar/scripts/sys/gpu @@ -1,3 +1,22 @@ -#!/usr/bin/env zsh - -amdgpu_top -J -s 5000 | sed 's/ //g' \ No newline at end of file +#!/usr/bin/env bash +amdgpu_top -J -s 5000 | jq -c --unbuffered '.devices[0] | { + gfx_pct: (.gpu_activity.GFX.value // 0), + mem_pct: (.gpu_activity.Memory.value // 0), + media_pct: (.gpu_activity.MediaEngine.value // 0), + sclk: (.Sensors.GFX_SCLK.value // 0), + mclk: (.Sensors.GFX_MCLK.value // 0), + sclk_pct: (if (.Info["GPU Clock"].max != .Info["GPU Clock"].min) then + 100 * ((.Sensors.GFX_SCLK.value // 0) - .Info["GPU Clock"].min) / (.Info["GPU Clock"].max - .Info["GPU Clock"].min) + else 0 end), + mclk_pct: (if (.Info["Memory Clock"].max != .Info["Memory Clock"].min) then + 100 * ((.Sensors.GFX_MCLK.value // 0) - .Info["Memory Clock"].min) / (.Info["Memory Clock"].max - .Info["Memory Clock"].min) + else 0 end), + vclk: (.gpu_metrics.average_vclk_frequency // 0), + vclk_pct: (if (.Info["GPU Clock"].max > 0) then + 100 * (.gpu_metrics.average_vclk_frequency // 0) / .Info["GPU Clock"].max + else 0 end), + temp: (.Sensors["Edge Temperature"].value // 0), + power: (.Sensors["Average Power"].value // 0), + vram_used: (.VRAM["Total VRAM Usage"].value // 0), + vram_total: (.VRAM["Total VRAM"].value // 1) +}' diff --git a/modules/home/wayland/apps/eww/bar/scripts/sys/memory b/modules/home/wayland/apps/eww/bar/scripts/sys/memory index 08de4d5..512d88a 100755 --- a/modules/home/wayland/apps/eww/bar/scripts/sys/memory +++ b/modules/home/wayland/apps/eww/bar/scripts/sys/memory @@ -8,5 +8,6 @@ human() { free --si -s 3 | rg --line-buffered Mem | while read -r line; do used=$(echo "$line" | awk '{print $3}') - echo '{"human": { "total": "'$(human "$total")'", "used": "'$(human "$used")'"}, "total": "'$total'" , "used": "'$used'"}' -done \ No newline at end of file + cached=$(echo "$line" | awk '{print $6}') + echo '{"human": {"total": "'$(human "$total")'", "used": "'$(human "$used")'", "cached": "'$(human "$cached")'"}, "total": "'$total'", "used": "'$used'", "cached": "'$cached'"}' +done diff --git a/modules/home/wayland/apps/eww/bar/scripts/sys/swap b/modules/home/wayland/apps/eww/bar/scripts/sys/swap new file mode 100755 index 0000000..19301e8 --- /dev/null +++ b/modules/home/wayland/apps/eww/bar/scripts/sys/swap @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +free --si | awk '/Swap/ { + used=$3; total=$2 + u = sprintf("%.1fG", used/1000000) + t = sprintf("%.1fG", total/1000000) + printf "{\"used\":%d,\"total\":%d,\"human\":{\"used\":\"%s\",\"total\":\"%s\"}}\n", used, total, u, t +}' diff --git a/modules/home/wayland/apps/eww/bar/windows/sys.yuck b/modules/home/wayland/apps/eww/bar/windows/sys.yuck index b759d40..fc40524 100644 --- a/modules/home/wayland/apps/eww/bar/windows/sys.yuck +++ b/modules/home/wayland/apps/eww/bar/windows/sys.yuck @@ -1,130 +1,212 @@ +(defpoll swap :interval "5s" "scripts/sys/swap") + +(defpoll cpu-freq-min :interval "60s" + "awk '{print $1/1000}' /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq") +(defpoll cpu-freq-max :interval "60s" + "awk '{print $1/1000}' /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq") +(defpoll cpu-temp :interval "2s" + "scripts/sys/cputemp") +(defpoll cpu-freq-avg :interval "2s" + "awk '{sum+=$1; count++} END {printf \"%.1f\", sum/count/1000000}' /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq") + +(deflisten cpu-grid :initial '[[{"core":0,"usage":0,"freq":0}]]' + "bash scripts/sys/cpugrid") + +; --- Shared --- + +(defwidget section-header [title accent] + (box :orientation "h" :space-evenly false :valign "center" :class "sys-section-header" + (box :class "section-accent ${accent}") + (label :class "sys-label" :text title))) + +; --- CPU --- + +(defwidget cpu-core-cell [core] + (overlay + (circular-progress + :width 60 :height 60 + :value {core.usage} + :start-at 0 + :clockwise true + :thickness 7 + :class "cpu-usage-ring") + (circular-progress + :value {100 * (core.freq - cpu-freq-min) / (cpu-freq-max - cpu-freq-min)} + :start-at 0 + :clockwise true + :thickness 4 + :class "cpu-freq-ring") + (box :halign "center" :valign "center" + (label :class "cpu-core-label" :text "${core.core}")) + ) +) + (defwidget cpu-sys-win [] - (box - :orientation "v" - :space-evenly false - (box :class "sys-label" "CPU") - (box - :orientation "v" - (for core in {EWW_CPU.cores} - (box - :space-evenly false - :class "cpu-core ${core.core}" - (progress - :value {core.usage} - :orientation "h" - :flipped true - :class "cpu-core-usage" - :tooltip "${core.core} @ ${core.freq}Mhz" - ) - ) - ) - ) + (box :orientation "v" :space-evenly false :class "sys-section" + (section-header :title "CPU" :accent "cpu-accent") + (box :orientation "v" :space-evenly false :halign "center" + (for row in {cpu-grid} + (box :orientation "h" :space-evenly false + (for core in {row} + (cpu-core-cell :core {core}))))) + (box :orientation "h" :space-evenly true :class "gpu-stats-row" + (box :orientation "v" :halign "center" :space-evenly false + (label :class "gpu-stat-value" :text "${cpu-temp}°C") + (label :class "gpu-stat-label" :text "temp")) + (box :orientation "v" :halign "center" :space-evenly false + (label :class "gpu-stat-value" :text "${cpu-freq-avg}GHz") + (label :class "gpu-stat-label" :text "avg clk")) + (box :orientation "v" :halign "center" :space-evenly false + (label :class "gpu-stat-value" :text "${round(EWW_CPU.avg, 0)}%") + (label :class "gpu-stat-label" :text "usage"))) ) ) +; --- GPU --- + (defwidget gpu-sys-win [] - (box - :orientation "v" - :space-evenly false - (box :class "sys-label" "GPU") - (progress - :value {gpu.devices[0].GRBM2?.CommandProcessor-Compute?.value?:0.0} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "Compute" - ) - (progress - :value {gpu.devices[0].GRBM2?.CommandProcessor-Fetcher?.value?:0.0} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "Fetcher" - ) - (progress - :value {gpu.devices[0].GRBM2?.CommandProcessor-Graphics?.value?:0.0} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "Graphics" - ) - (box :class "spacer") - (progress - :value {gpu.devices[0]?.gpu_activity?.GFX?.value?:0.0} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "GFX" - ) - (progress - :value {gpu.devices[0]?.gpu_activity?.Memory?.value?:0.0} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "Memory" - ) - (progress - :value {gpu.devices[0]?.gpu_activity?.MediaEngine?.value?:0.0} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "Media" - ) - (box :class "spacer") - (progress - :value {100*(gpu.devices[0]?.VRAM?.TotalVRAMUsage?.value?:0.0)/(gpu.devices[0]?.VRAM?.TotalVRAM?.value?:1.0)} - :orientation "h" - :flipped true - :class "gpu-core-usage" - :tooltip "VRAM" + (box :orientation "v" :space-evenly false :class "sys-section" + (section-header :title "GPU" :accent "gpu-accent") + (box :orientation "h" :space-evenly true + ; GFX — outer: activity%, inner: clock% of range + (box :orientation "v" :space-evenly false :halign "center" + (overlay + (circular-progress :width 68 :height 68 + :value {gpu.gfx_pct} + :start-at 0 :clockwise true :thickness 7 + :class "gpu-ring" + :tooltip "GFX ${round(gpu.gfx_pct, 1)}%\nClock ${gpu.sclk} MHz (${round(gpu.sclk_pct, 0)}% of range)") + (circular-progress + :value {gpu.sclk_pct} + :start-at 0 :clockwise true :thickness 4 + :class "gpu-freq-ring") + (box :halign "center" :valign "center" + (label :class "gpu-ring-value" :text "${round(gpu.gfx_pct, 0)}%"))) + (label :class "gpu-ring-label" :text "GFX" :halign "center")) + ; Memory — outer: activity%, inner: memory clock% of range + (box :orientation "v" :space-evenly false :halign "center" + (overlay + (circular-progress :width 68 :height 68 + :value {gpu.mem_pct} + :start-at 0 :clockwise true :thickness 7 + :class "gpu-ring" + :tooltip "Memory ${round(gpu.mem_pct, 1)}%\nClock ${gpu.mclk} MHz (${round(gpu.mclk_pct, 0)}% of range)") + (circular-progress + :value {gpu.mclk_pct} + :start-at 0 :clockwise true :thickness 4 + :class "gpu-freq-ring") + (box :halign "center" :valign "center" + (label :class "gpu-ring-value" :text "${round(gpu.mem_pct, 0)}%"))) + (label :class "gpu-ring-label" :text "Mem" :halign "center")) + ; Media — outer: activity%, inner: video clock% of GPU clock max + (box :orientation "v" :space-evenly false :halign "center" + (overlay + (circular-progress :width 68 :height 68 + :value {gpu.media_pct} + :start-at 0 :clockwise true :thickness 7 + :class "gpu-ring" + :tooltip "Media Engine ${round(gpu.media_pct, 1)}%\nVideo Clock ${gpu.vclk} MHz") + (circular-progress + :value {gpu.vclk_pct} + :start-at 0 :clockwise true :thickness 4 + :class "gpu-freq-ring") + (box :halign "center" :valign "center" + (label :class "gpu-ring-value" :text "${round(gpu.media_pct, 0)}%"))) + (label :class "gpu-ring-label" :text "Med" :halign "center"))) + (box :orientation "v" :space-evenly false :class "vram-row" + (progress + :value {100 * gpu.vram_used / gpu.vram_total} + :orientation "h" :flipped true :hexpand true + :class "vram-bar" + :tooltip "VRAM ${round(100 * gpu.vram_used / gpu.vram_total, 1)}%") + (box :orientation "h" :space-evenly false + (label :class "vram-usage-label" :halign "start" :hexpand true :text "VRAM") + (label :class "vram-usage-label" :halign "end" + :text "${round(gpu.vram_used / 1024, 1)} / ${round(gpu.vram_total / 1024, 1)} GiB"))) + (box :orientation "h" :space-evenly true :class "gpu-stats-row" + (box :orientation "v" :halign "center" :space-evenly false + (label :class "gpu-stat-value" :text "${gpu.temp}°C") + (label :class "gpu-stat-label" :text "temp")) + (box :orientation "v" :halign "center" :space-evenly false + (label :class "gpu-stat-value" :text "${gpu.power}W") + (label :class "gpu-stat-label" :text "power"))) + ) +) + +; --- RAM --- + +(defwidget ram-sys-win [] + (box :orientation "v" :space-evenly false :class "sys-section" + (section-header :title "RAM" :accent "ram-accent") + (box :orientation "h" :space-evenly false :halign "center" :spacing 16 :valign "center" + (overlay + (circular-progress + :width 88 :height 88 + :value {100*memory.used/memory.total} + :start-at 0 + :clockwise true + :thickness 9 + :class "ram-ring" + :tooltip "RAM\nUsed ${memory.human.used} / ${memory.human.total}\nCached ${memory.human.cached}") + (circular-progress + :value {100*memory.cached/memory.total} + :start-at {100*memory.used/memory.total} + :clockwise true + :thickness 9 + :class "ram-cached-ring") + (box :orientation "v" :valign "center" :halign "center" :space-evenly false + (label :class "ram-used-label" :text "${memory.human.used}") + (label :class "ram-total-label" :text "${memory.human.total}"))) + (box :orientation "v" :space-evenly false :halign "center" :valign "center" + (overlay + (circular-progress + :width 60 :height 60 + :value {100*swap.used/swap.total} + :start-at 0 :clockwise true :thickness 7 + :class "swap-ring" + :tooltip "Swap\n${swap.human.used} / ${swap.human.total}") + (box :orientation "v" :valign "center" :halign "center" :space-evenly false + (label :class "ram-used-label" :text "${swap.human.used}") + (label :class "ram-total-label" :text "${swap.human.total}")))) ) ) ) -(defwidget ram-sys-win [] - (box - :orientation "v" - :space-evenly false - (box :class "sys-label" "RAM") - (progress - :value {100*memory.used/memory.total} - :orientation "h" - :flipped true - :class "memory-usage" - :tooltip "RAM" - ) +; --- Battery --- + +(defwidget bat-sys-win [] + (box :orientation "v" :space-evenly false :class "sys-section" :visible {battery.visible} + (section-header :title "Battery" :accent "bat-accent") + (overlay + (circular-progress + :width 60 :height 60 + :value {battery.percentage} + :start-at 0 + :clockwise true + :thickness 6 + :class "bat-ring" + :style "color: ${battery.color};" + :tooltip "Battery ${round(battery.percentage, 0)}%\n${battery.status} @ ${battery.wattage}") + (label :class "bat-ring-label" + :text "${round(battery.percentage, 0)}%")) ) ) +; --- Root --- + (defwidget sys-win [] (box :class "sys-win" :space-evenly false - :orientation "h" - (box - :space-evenly false - :orientation "v" - (cpu-sys-win) - (box :class "spacer") - (box :class "spacer") - (gpu-sys-win) - (box :class "spacer") - (box :class "spacer") - (ram-sys-win) - ) - (box - :visible {battery.visible} - :height 200 - (graph - :height 200 - :value {battery.percentage} - :time-range "30min" - :min "0.0" - :max "100.0" - :dynamic true - ) - ) + :orientation "v" + (cpu-sys-win) + (box :class "section-sep") + (gpu-sys-win) + (box :class "section-sep") + (ram-sys-win) + (box :class "section-sep" :visible {battery.visible}) + (bat-sys-win) ) ) @@ -134,7 +216,7 @@ :geometry (geometry :x "0%" :y "0%" - :anchor "bottom right" - :width "0px" + :anchor "bottom right" + :width "320px" :height "0px") (window (sys-win))) diff --git a/modules/nixos/system/hw/base/default.nix b/modules/nixos/system/hw/base/default.nix index d7e34a3..16c7c86 100644 --- a/modules/nixos/system/hw/base/default.nix +++ b/modules/nixos/system/hw/base/default.nix @@ -1,4 +1,4 @@ { ... }: { services.fwupd.enable = true; - hardware.enableAllFirmware = true; + hardware.enableAllFirmware = false; }