infobar (7154B)
1 #!/bin/sh 2 3 # Copyright (C) Raymond Cole <rc@wolog.xyz> 4 # License: GPL-3.0-or-later 5 6 cleanup() { 7 set -- $(cat "$tmpdir"/pid/* 2>/dev/null) 8 [ $# -eq 0 ] || kill "$@" 9 rm -rf "$tmpdir" 10 } 11 12 humanize() { 13 n="$1" 14 b="$2" 15 shift 2 16 for u in "$@"; do 17 [ "$n" -ge "$b" ] || break 18 n=$(( (n + b / 2) / b )) 19 done 20 echo "$n$u" 21 } 22 23 runinformer() { 24 f="$1"; shift 25 [ -p "$tmpdir/fifo/$f" ] || mkfifo "$tmpdir/fifo/$f" || exit 26 [ -e "$tmpdir/pid/$f" ] && kill "$(cat "$tmpdir/pid/$f")" 27 "$@" >"$tmpdir/fifo/$f" & 28 echo "$!" >"$tmpdir/pid/$f" 29 } 30 31 updatebat() { 32 set -- "$(cat /sys/class/power_supply/BAT0/capacity)" "$bat" 33 for bat in '20:' '40:' '60:' '80:' '100:'; do 34 [ "$1" -lt "${bat%:*}" ] && break 35 done 36 bat="${bat#*:} $1%" 37 if grep -xFq Charging /sys/class/power_supply/BAT0/status; then 38 bat="$bat " 39 fi 40 [ "$bat" != "$2" ]; return # return the result of the test 41 } 42 43 updateclk() { 44 case "$bar" in 45 *%C*) clk="$(date +'%a %b %d %T %Z %Y')" ;; 46 *) clk="$(date +'%a %b %d %H:%M')" ;; 47 esac 48 return 0 49 } 50 51 updatecpu() { 52 o="$cpu" 53 set -- $(cat /proc/loadavg) 54 cpu=" $1" 55 case "$bar" in 56 *%P*) 57 set -- $(head -n 1 /proc/stat) 58 shift 59 u=$(( $1 + $2 + $3 + $6 + $7 )) 60 s=$(( u + $4 + $5 )) 61 if [ -n "$cpuuse$cpusum" ]; then 62 cpu="$cpu $(( (u - cpuuse) * 100 / (s - cpusum) ))%" 63 fi 64 cpuuse="$u" 65 cpusum="$s" 66 if f="$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)"; then 67 t="$(humanize "$(( f * 10 ))" 1000 '' K M G)" 68 f="${t%[[:digit:]]*}" 69 f="${f:-0}.${t#$f}" 70 cpu="$cpu ${f}Hz" 71 fi 72 ;; 73 esac 74 [ "$cpu" != "$o" ]; return 75 } 76 77 updatemem() { 78 set -- $(free | sed -n '2{p;q}') 79 shift 80 o="$mem" 81 x="$(humanize "$(( $1 * 10 ))" 1024 Ki Mi Gi)" 82 t="${x%[[:digit:]]*}" 83 t="${t:-0}.${x#$t}B" 84 x="$(humanize "$(( $2 * 10 ))" 1024 Ki Mi Gi)" 85 u="${x%[[:digit:]]*}" 86 u="${u:-0}.${x#$u}B" 87 mem=" $u/$t" 88 [ "$mem" != "$o" ]; return 89 } 90 91 updatenet() { 92 set -- "$net" $(ip route | sed -n 's/^default\( via \([^ ]*\)\)* dev \([^ ]*\).*/\3 \2/p;q') 93 if [ $# -ge 2 ] && grep -xFq up "/sys/class/net/$2/operstate"; then 94 case "$2" in 95 en*|eth*) net='' ;; 96 wl*) net='' ;; 97 ww*) net='' ;; 98 *) net="$2" ;; 99 esac 100 [ -n "$3" ] || net="$net " 101 case "$bar" in 102 *%N*) 103 case "$2" in 104 wl*) 105 x="$(sed -n "s/^$2:"' *[^ ]* *[^ ]* *\([^.]*\).*/\1/p' /proc/net/wireless)" 106 net="$net ${x}dBm" 107 ;; 108 esac 109 x="$(cat "/sys/class/net/$2/statistics/rx_bytes")" 110 [ -z "$netrx" ] || net="$net $(humanize $(( x - netrx )) 1024 B KiB MiB)" 111 netrx="$x" 112 x="$(cat "/sys/class/net/$2/statistics/tx_bytes")" 113 [ -z "$nettx" ] || net="$net $(humanize $(( x - nettx )) 1024 B KiB MiB)" 114 nettx="$x" 115 ;; 116 esac 117 else 118 net='' 119 fi 120 [ "$net" != "$1" ]; return 121 } 122 123 updatevol() { 124 set -- $(amixer sget Master | sed -n 's/^.*\[\([0-9]\+\)%\].*\[\(on\|off\)\]/\1 \2/p;tL;d;:L;q') 125 if [ "$2" = on ]; then 126 for vol in '0:' '30:' '100:'; do 127 [ "$1" -le "${vol%:*}" ] && break 128 done 129 vol="${vol#*:} $1%" 130 else 131 vol=" $1%" 132 fi 133 return 0 134 } 135 136 setbar() { 137 bar="$1" 138 modules= 139 o= 140 s="$IFS" 141 IFS=' %' 142 for x in $bar; do 143 modules="$x $modules" 144 case "$x" in 145 [[:upper:]]) o="s${o#s}" ;; 146 [bc]) o="${o%m}m" ;; 147 esac 148 done 149 IFS="$s" 150 if [ "$ttopts" != "$o" ]; then 151 runinformer t ticktack ${o:+-$o} 152 ttopts="$o" 153 fi 154 } 155 156 changebar() { 157 setbar "${bar%%"$1"*}$2${bar#*"$1"}" 158 } 159 160 putbar() { 161 s="$IFS" 162 IFS=% 163 for x in $bar; do 164 t="${x%% *}" 165 case "${t#%}" in 166 b) t="$bat" ;; 167 [Cc]) t="$clk" ;; 168 M) t="$mem" ;; 169 [Nn]) t="$net" ;; 170 [Pp]) t="$cpu" ;; 171 v) t="$vol" ;; 172 esac 173 printf '%s' "$t${x##*[! ]}" 174 done 175 IFS="$s" 176 echo 177 } 178 179 tmpdir="/tmp/infobar.$$" 180 ttopts= 181 bat= 182 clk= 183 cpu= 184 cpuuse= 185 cpusum= 186 mem= 187 net= 188 netrx= 189 nettx= 190 vol= 191 192 trap cleanup INT TERM EXIT 193 mkdir "$tmpdir" && mkdir "$tmpdir/fifo" && mkdir "$tmpdir/pid" || exit 194 195 # Some available modules: 196 # 197 # + %n - network connection (depends on the ip command) 198 # + %v - volume and mutedness (depends on alsactl) 199 # + %p - processor load over the last minute 200 # + %b - battery percentage and charging state (depends on acpi_listen) 201 # + %c - clock with the precision of minutes 202 # 203 # Among them %n and %v are updated upon relevant output of `ip monitor 204 # route` and `alsactl monitor`, respectively. %p, %b and %c are updated 205 # upon every minute. %b is in addition updated upon relevant output of 206 # `acpi_listen`. 207 # 208 # The other modules have uppercase names and are updated every second: 209 # 210 # + %N - like %n but also shows signal strength (if wireless) and network traffic 211 # + %P - like %p but also shows CPU usage and frequency 212 # + %C - like %c but more detailed and shows seconds 213 # + %M - memory usage 214 # 215 # Generally, the modules should be used in a specific format: Modules 216 # should be separated by two or more spaces and nothing else. No module 217 # should appear more than once, and a lowercase module and its uppercase 218 # counterpart shouldn't both be used. The freedom lies mainly in deciding 219 # which modules are included and in what order. 220 221 setbar ' %n %v %p %b %c ' 222 223 # remove the %b module if there is no BAT0 (e.g. on desktop computer) 224 [ -r /sys/class/power_supply/BAT0/capacity ] || changebar ' %b ' '' 225 226 for mod in $modules; do 227 case "$mod" in 228 b) 229 runinformer a acpi_listen 230 updatebat 231 ;; 232 [Cc]) 233 updateclk 234 ;; 235 M) 236 updatemem 237 ;; 238 [Nn]) 239 runinformer n ip monitor route 240 updatenet 241 ;; 242 [Pp]) 243 updatecpu 244 ;; 245 v) 246 runinformer v alsactl monitor 247 updatevol 248 ;; 249 esac 250 done 251 252 putbar 253 254 fifolog - "$tmpdir"/fifo/* | while read -r src tok toks; do 255 case "$src" in 256 -) 257 for mod in $modules; do 258 [ "$tok" -gt 1 ] || break 259 tok=$(( tok - 1 )) 260 done 261 button="${toks%% *}" 262 case "$mod" in 263 [Cc]) 264 if [ "$button" -eq 1 ]; then 265 if [ "$mod" = c ]; then 266 changebar %c %C 267 else 268 changebar %C %c 269 fi 270 updateclk && putbar 271 fi 272 ;; 273 [MPp]) 274 if [ "$button" -eq 1 ]; then 275 case "$bar" in 276 *'%P %M'*) 277 changebar '%P %M' %p 278 cpuuse= 279 cpusum= 280 updatecpu 281 putbar 282 ;; 283 *%p*) 284 changebar %p '%P %M' 285 updatecpu 286 updatemem 287 putbar 288 ;; 289 esac 290 fi 291 ;; 292 N) 293 if [ "$button" -eq 1 ]; then 294 changebar %N %n 295 netrx= 296 nettx= 297 updatenet && putbar 298 fi 299 ;; 300 n) 301 if [ "$button" -eq 1 ]; then 302 changebar %n %N 303 updatenet && putbar 304 fi 305 ;; 306 v) 307 if [ "$button" -eq 3 ]; then 308 amixer -q set Master toggle 309 updatevol && putbar 310 elif [ "$button" -eq 4 ]; then 311 amixer -q set Master 5%+ 312 updatevol && putbar 313 elif [ "$button" -eq 5 ]; then 314 amixer -q set Master 5%- 315 updatevol && putbar 316 fi 317 ;; 318 esac 319 ;; 320 a) 321 case "$bar" in 322 *%b*) 323 [ "$tok" = ac_adapter ] && updatebat && putbar 324 ;; 325 esac 326 ;; 327 [Nn]) 328 case "$tok" in 329 Deleted|default) 330 updatenet && putbar 331 ;; 332 esac 333 ;; 334 t) 335 tokbar="$tok$bar" 336 case "$tokbar" in 337 [sm]*%b*) updatebat && putbar ; 338 esac 339 case "$tokbar" in 340 m*%c*|[sm]*%C*) updateclk && putbar ;; 341 esac 342 case "$tokbar" in 343 [sm]*%M*) updatemem && putbar ;; 344 esac 345 case "$tokbar" in 346 [sm]*%N*) updatenet && putbar ;; 347 esac 348 case "$tokbar" in 349 [sm]*%[Pp]*) updatecpu && putbar ;; 350 esac 351 ;; 352 v) 353 updatevol && putbar 354 ;; 355 !) 356 [ "$tok" = t ] || exit 1 357 ;; 358 esac 359 done