1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#!/bin/sh
# Combined system status bar module
# Toggle each section on/off (1=on, 0=off)
SHOW_CPU=1
SHOW_CPUBARS=0
SHOW_MEMORY=1
SHOW_DISK=1
# Refresh interval per module (seconds)
# The script itself should be called at the shortest interval (e.g. 5s)
INTERVAL_CPU=5
INTERVAL_CPUBARS=15
INTERVAL_MEMORY=60
INTERVAL_DISK=10800
# Disk mountpoint (only used if SHOW_DISK=1)
DISK_LOCATION=${1:-/}
# Cache directory
CACHE_DIR=/tmp/sb-system
mkdir -p "$CACHE_DIR"
# Clear stale caches on first run (e.g. dwmblocks restart)
LOCK="$CACHE_DIR/.started"
if [ ! -f "$LOCK" ]; then
rm -f "$CACHE_DIR"/cpu "$CACHE_DIR"/cpubars "$CACHE_DIR"/cpubars_prev "$CACHE_DIR"/memory "$CACHE_DIR"/disk*
touch "$LOCK"
fi
# ── Helper: check if cache is stale ────────────────────────
# usage: is_stale <cache_file> <interval_seconds>
is_stale() {
[ ! -f "$1" ] && return 0
last=$(stat -c %Y "$1" 2>/dev/null || echo 0)
now=$(date +%s)
[ $((now - last)) -ge "$2" ]
}
# ── Click handlers ──────────────────────────────────────────
case $BLOCK_BUTTON in
1)
[ "$SHOW_CPU" = 1 ] && notify-send "🖥 CPU hogs" "$(ps axch -o cmd,%cpu | awk '{cmd[$1]+=$2} END {for (i in cmd) print i, cmd[i]}' | sort -nrk2 | head)\\n(100% per core)"
[ "$SHOW_MEMORY" = 1 ] && notify-send "🐏 Memory hogs" "$(ps axch -o cmd,%mem | awk '{cmd[$1]+=$2} END {for (i in cmd) print i, cmd[i]}' | sort -nrk2 | head)"
[ "$SHOW_DISK" = 1 ] && notify-send "💽 Disk space" "$(df -h --output=target,used,size)"
;;
2) setsid -f "$TERMINAL" -e htop ;;
3) notify-send "🖥 System module" "CPU temp, CPU bars, Memory, Disk usage
Left click: show hogs & disk info
Middle click: open htop
Right click: this help" ;;
6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
esac
# ── Module: CPU temperature ─────────────────────────────────
if [ "$SHOW_CPU" = 1 ]; then
cf="$CACHE_DIR/cpu"
if is_stale "$cf" "$INTERVAL_CPU"; then
sensors | awk '/Tctl:/ {gsub(/[+°C]/,"",$2); printf "🧁%s°", $2}' >"$cf"
fi
fi
# ── Module: CPU bars ────────────────────────────────────────
if [ "$SHOW_CPUBARS" = 1 ]; then
cf="$CACHE_DIR/cpubars"
if is_stale "$cf" "$INTERVAL_CPUBARS"; then
prev_cache="$CACHE_DIR/cpubars_prev"
stats=$(awk '/cpu[0-9]+/ {printf "%d %d %d\n", substr($1,4), ($2 + $3 + $4 + $5), $5 }' /proc/stat)
[ ! -f "$prev_cache" ] && echo "$stats" >"$prev_cache"
old=$(cat "$prev_cache")
echo "$stats" | while read -r row; do
id=${row%% *}
rest=${row#* }
total=${rest%% *}
idle=${rest##* }
case "$(echo "$old" | awk '{if ($1 == id)
printf "%d\n", (1 - (idle - $3) / (total - $2))*100 /12.5}' \
id="$id" total="$total" idle="$idle")" in
"0") printf "▁" ;; "1") printf "▂" ;; "2") printf "▃" ;; "3") printf "▄" ;;
"4") printf "▅" ;; "5") printf "▆" ;; "6") printf "▇" ;; "7" | "8") printf "█" ;;
esac
done >"$cf"
echo "$stats" >"$prev_cache"
fi
fi
# ── Module: Memory + NVMe temp ──────────────────────────────
if [ "$SHOW_MEMORY" = 1 ]; then
cf="$CACHE_DIR/memory"
if is_stale "$cf" "$INTERVAL_MEMORY"; then
width=$(xrandr | grep "\*" | awk '{print $1}' | sed 's/x[0-9]*//g' | head -n1)
nvme_temp=$(sensors 2>/dev/null |
awk '/Composite:/ {gsub(/[+°C]/,"",$2); print $2; exit}')
if [ -n "$width" ] && [ "$width" -eq "$width" ] 2>/dev/null; then
if [ "$width" -lt 1920 ]; then
free --mebi | sed -n '2{p;q}' |
awk -v t="$nvme_temp" '{printf "🌡%s° 🐏%d%%", t, ($3/$2)*100+0.5}' >"$cf"
else
free --mebi | sed -n '2{p;q}' |
awk -v t="$nvme_temp" '{printf "🌡%s° 🐏%dGB/%dGB", t, $3/1000+0.5, $2/1000+0.5}' >"$cf"
fi
fi
fi
fi
# ── Module: Disk usage ──────────────────────────────────────
if [ "$SHOW_DISK" = 1 ] && [ -d "$DISK_LOCATION" ]; then
disk_key=$(printf "%s" "$DISK_LOCATION" | tr '/' '_')
cf="$CACHE_DIR/disk${disk_key}"
if is_stale "$cf" "$INTERVAL_DISK"; then
case "$DISK_LOCATION" in
"/home"*) icon="💾" ;; "/mnt"*) icon="" ;; *) icon="💻" ;;
esac
printf "%s%s" "$icon" "$(df -hP "$DISK_LOCATION" | awk '/[0-9]/ {print $5}')" >"$cf"
fi
fi
# ── Clean up disabled module caches ───────────────────────────
[ "$SHOW_CPU" = 0 ] && rm -f "$CACHE_DIR/cpu"
[ "$SHOW_CPUBARS" = 0 ] && rm -f "$CACHE_DIR/cpubars" "$CACHE_DIR/cpubars_prev"
[ "$SHOW_MEMORY" = 0 ] && rm -f "$CACHE_DIR/memory"
disk_key=$(printf "%s" "$DISK_LOCATION" | tr '/' '_')
[ "$SHOW_DISK" = 0 ] && rm -f "$CACHE_DIR/disk${disk_key}"
# ── Assemble output ─────────────────────────────────────────
out=""
for mod in cpu cpubars memory "disk${disk_key}"; do
f="$CACHE_DIR/$mod"
[ -f "$f" ] && val=$(cat "$f") && [ -n "$val" ] && {
[ -n "$out" ] && out="$out "
out="$out$val"
}
done
printf "%s\n" "$out"
|