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