skynet/herbstluftwm/panel.sh

453 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
hostname=$(hostname)
hc() { herbstclient "$@" ;}
panel_height=20
for monitor in $(hc list_monitors | cut -d: -f1); do
hc pad "$monitor" "$panel_height" 0 0 0
done
{ sleep 1; exec trayer --SetPartialStrut false --edge top --height 20 --widthtype request --align right --tint 0x11111b --transparent true --alpha 0; } &
fggreen='%{F#a6e3a1}'
fgblue='%{F#89b4fa}'
fgred='%{F#f38ba8}'
fgdark='%{F#313244}'
fgend='%{F-}'
bggreen='%{B#a6e3a1}'
bgblue='%{B#89b4fa}'
bgred='%{B#f38ba8}'
bglight='%{B#313244}'
bgend='%{B-}'
ulblue='%{U#89b4fa+u}'
ulend='%{-u}'
handle_signal() {
FORCE_REFRESH=1
}
handle_kill() {
kill 0
rm "$fifo"
exit 0
}
trap handle_signal SIGUSR1
trap handle_kill SIGINT
fifo="/tmp/panel_text"
if [ ! -p "$fifo" ]; then
mkfifo "$fifo"
fi
msgfifo="/tmp/panel_msg"
if [ ! -p "$msgfifo" ]; then
mkfifo "$msgfifo"
fi
# process to handle lemonbar clicks
{
while IFS= read -r line; do
IFS="-" read -r -a command <<< "$line"
if [ "${command[0]}" = "tag" ]; then
# not sure how to specify a monitor, but probably don't need to anyway
monitor="${command[1]}"
index=$(( "${command[2]}" - 1 ))
if [ "$index" -eq -1 ]; then
index=9
fi
herbstclient chain , lock , focus_monitor "$monitor" , use_index "$index" , spawn stickyctl get-sticky , unlock
fi
done < "$msgfifo"
} &
tail -f "$fifo" | stdbuf -oL lemonbar -d -p -a 100 -g "x${panel_height}" -f "Drafting* Mono:pixelsize=18:antialias=true" -f "Unifont:pixelsize=18:antialias=true" -B "#11111b" -F "#cdd6f4" > "$msgfifo" &
append_segment() {
local seconds=$1
local name=$2
local param=$3
shift
local now=$SECONDS
local escparam
segment_text=''
escparam="${param//\//_}"
eval "local lastrun=\$${name}${escparam}_lastrun"
if [ -z "$lastrun" ]; then
lastrun=0
fi
if [ -n "$FORCE_REFRESH" ] || [ "$lastrun" -eq 0 ] || (( SECONDS - lastrun >= seconds )); then
"$@"
eval "${name}${escparam}_lastrun=\$now"
eval "${name}${escparam}_lastoutput=\"$segment_text\""
panel_text="$panel_text$segment_text"
else
eval "panel_text=\"\$panel_text\$${name}${escparam}_lastoutput\""
fi
}
append_separator() {
panel_text="$panel_text "
}
append_percent_icon() {
local pct=$1
segment_text="$segment_text$bglight"
if (( pct < 12 )); then
segment_text="$segment_text"
elif (( pct < 25 )); then
segment_text="$segment_text"
elif (( pct < 38 )); then
segment_text="$segment_text"
elif (( pct < 51 )); then
segment_text="$segment_text"
elif (( pct < 64 )); then
segment_text="$segment_text"
elif (( pct < 77 )); then
segment_text="$segment_text"
elif (( pct < 90 )); then
segment_text="$segment_text"
else
segment_text="$segment_text"
fi
segment_text="$segment_text$bgend%{O5}"
}
append_battery_icon() {
local pct=$1
segment_text="$segment_text$bglight"
if (( pct < 10 )); then
segment_text="$segment_text"
elif (( pct < 20 )); then
segment_text="$segment_text"
elif (( pct < 30 )); then
segment_text="$segment_text"
elif (( pct < 40 )); then
segment_text="$segment_text"
elif (( pct < 50 )); then
segment_text="$segment_text"
elif (( pct < 60 )); then
segment_text="$segment_text"
elif (( pct < 70 )); then
segment_text="$segment_text"
elif (( pct < 80 )); then
segment_text="$segment_text"
elif (( pct < 90 )); then
segment_text="$segment_text"
else
segment_text="$segment_text"
fi
segment_text="$segment_text$bgend%{O5}"
}
segment_tags() {
local monitor=$1
local tags
local prefix
local tagclass
IFS=$'\t' read -ra tags <<< "$(hc tag_status "$monitor")"
segment_text=''
for i in "${tags[@]}"; do
prefix=${i:0:1}
case $prefix in
'.') tagclass=$fgend$bgend ;;
'+') tagclass=$bgblue$fgdark ;;
'#') tagclass=$bggreen$fgdark ;;
'!') tagclass=$bgred$fgdark ;;
'-') tagclass=$ulblue$bglight$fgblue ;;
'%') tagclass=$ulblue$bglight$fgblue ;;
*) tagclass=$bglight ;;
esac
segment_text="$segment_text%{A:tag-$monitor-${i:1}:}$tagclass%{O8}${i:1}%{O8}%{A}$fgend$bgend$ulend"
done
}
segment_timew() {
local curday
local active
local twclass
local twicon
if hash timew 2>/dev/null; then
active=$(timew get dom.active)
if [ "$active" = "1" ]; then
twicon=""
twclass=$fggreen
else
twicon=""
twclass=$fgred
fi
curday=$(timew summary | tail -n2 | head -n1 | awk '{ print $1 }')
if [ "$curday" = "No" ]; then
curday='0:00'
else
curday="${curday%:*}"
fi
segment_text="${twclass}${twicon}${fgend}%{O5}$curday"
fi
}
segment_keyboard() {
local kblayout
local kbclass
local kbicon
kblayout=$(setxkbmap -query | grep variant | awk '{ print $2 }' | tr -d ',')
if [ "$kblayout" = "dvorak" ]; then
kbclass=$fgred
kbicon=""
else
kbclass=$fggreen
kbicon=""
fi
segment_text="$kbclass$kbicon$fgend"
}
segment_network() {
local net
local neticon
local btpower
local btconn
local bticon
local nasavpn
local nasaicon
local vnc
local vncicon
# network device
net=$(ip route get 1.1.1.1 | grep -Po '(?<=dev\s)\w+' | cut -f1 -d ' ')
if ! [ "$net" ]; then
neticon="%{O3}$fgred$fgend"
else
neticon="%{O3}$fggreenﯱ$fgend"
fi
if hash bluetoothctl 2>/dev/null; then
# bluetooth status
btpower=$(bluetoothctl show | grep Powered | awk '{ print $2 }')
if [ "$btpower" = "yes" ]; then
btconn=$(bluetoothctl devices | cut -f2 -d' ' | while read uuid; do bluetoothctl info $uuid; done | grep "Connected: yes")
if [ -z "$btconn" ]; then
bticon="${fggreen}$fgend"
else
bticon="${fgblue}$fgend"
fi
else
bticon="${fgred}$fgend"
fi
fi
if hash docker 2>/dev/null; then
nasavpn=$(docker ps --format "{{.Names}}" | grep nasavpn)
if [ -n "$nasavpn" ]; then
nasaicon="%{O3}${fggreen}$fgend"
else
nasaicon="%{O3}${fgred}$fgend"
fi
vnc=$(docker ps --format "{{.Names}}" | grep novnc)
if [ -n "$vnc" ]; then
vncicon="%{O3}${fggreen}$fgend"
else
vncicon="%{O3}${fgred}$fgend"
fi
fi
segment_text="$bticon$nasaicon$vncicon$neticon"
}
segment_memory() {
local mempct
local memclass
mempct=$(free | grep Mem | awk '{ print int($3/$2 * 100.0 + 0.5) }')
if [ "$mempct" -gt 75 ]; then
memclass=$fgred
elif [ "$mempct" -gt 50 ]; then
memclass=$fgblue
else
memclass=$fggreen
fi
segment_text=$memclass
append_percent_icon "$mempct"
segment_text="${segment_text}$fgend"
}
segment_disk() {
local dpath=$1
local diskpct
local diskclass
local diskicon
if [ "$dpath" = "/" ]; then
diskicon=""
else
diskicon=""
fi
diskpct=$(df --output=pcent "$dpath" | sed 1d | sed 's/^[ \t]*//' | sed 's/%.*//')
if [ "$diskpct" -gt 90 ]; then
diskclass=$fgred
elif [ "$diskpct" -gt 75 ]; then
diskclass=$fgblue
else
diskclass=$fggreen
fi
segment_text=$diskclass
append_percent_icon "$diskpct"
segment_text="${segment_text}$diskicon$fgend"
}
segment_cpu() {
local cpupct
local cpuclass
cpupct=$(awk '{u=$2+$4; t=$2+$4+$5; if (NR==1){u1=u; t1=t;} else print ($2+$4-u1) * 100 / (t-t1); }' <(grep 'cpu ' /proc/stat) <(sleep 1;grep 'cpu ' /proc/stat) | awk '{print int($1+0.5)}')
if [ "$cpupct" -gt 90 ]; then
cpuclass=$fgred
elif [ "$cpupct" -gt 25 ]; then
cpuclass=$fgblue
else
cpuclass=$fggreen
fi
segment_text=$cpuclass
append_percent_icon "$cpupct"
segment_text="${segment_text}$fgend"
}
segment_audio() {
local audiohdmi
local audiobt
local audicon
local volpct
if hash pactl 2>/dev/null; then
# audio output device (hdmi/analog)
audiohdmi=$(pactl get-default-sink | grep hdmi)
audiobt=$(pactl get-default-sink | grep bluez)
fi
if [ -n "$audiobt" ]; then
audclass=$fgblue
audicon='﫽'
else
audclass=$fggreen
if [ "$hostname" != "ellison" ]; then
if [ -z "$audiohdmi" ]; then
audicon=''
else
audicon='蓼'
fi
else
audicon='蓼'
fi
fi
if hash pamixer 2>/dev/null; then
volpct=$(pamixer --get-volume-human | sed 's/%//')
if [ "$volpct" = "muted" ]; then
audclass=$fgred
volpct="0"
fi
fi
segment_text=$audclass
append_percent_icon "$volpct"
segment_text="$segment_text$audicon$fgend"
}
segment_battery() {
local battpct
local batstat
local baticon
local batclass
if hash upower 2>/dev/null; then
# battery charge percent
battpct="$(upower --show-info $(upower --enumerate | grep -i 'BAT') | grep -E "percentage" | awk '{print $2}')"
battpct="${battpct%\%}"
# battery status (charging/charged/etc)
batstat="$(upower --show-info $(upower --enumerate | grep -i 'BAT') | grep -E "state" | awk '{print $2}')"
if (( battpct > 80 )); then
batclass=$fggreen
elif (( battpct < 20 )); then
batclass=$fgred
else
batclass=$fgblue
fi
segment_text="$batclass"
if [ "$batstat" = "charging" ]; then
segment_text="${segment_text}"
elif [ "$batstat" = "fully-charged" ]; then
segment_text="${segment_text}"
else
append_battery_icon "$battpct"
fi
segment_text="$segment_text$fgend"
else
segment_text="$fggreenﮣ$fgend"
fi
}
segment_date() {
segment_text="$(date +$'%a %b %d') $fgblue$(date +$'%H:%M')$fgend"
}
last_text=''
while true; do
{
full_text=''
for monitor in $(herbstclient list_monitors | cut -d: -f1); do
panel_text="%{S$monitor}%{l}"
append_segment 0 segment_tags "$monitor"
panel_text="$panel_text%{l}%{r}"
append_segment 60 segment_timew
append_separator
append_segment 60 segment_keyboard
append_separator
append_segment 10 segment_network
append_separator
panel_text="$panel_text%{A:conky:}"
append_segment 10 segment_memory
append_separator
append_segment 60 segment_disk "/"
append_separator
if [ "$hostname" != "ellison" ]; then
append_segment 60 segment_disk "/home"
append_separator
fi
append_segment 5 segment_cpu
append_separator
append_segment 60 segment_audio
append_separator
append_segment 30 segment_battery
panel_text="$panel_text%{A}"
append_separator
append_segment 60 segment_date
if [ "$monitor" -eq 0 ]; then
tray_width=$(xdotool search --classname panel | xargs -n1 xprop -id | grep 'program specified minimum size' | cut -d ' ' -f 5)
tray_width=$(( tray_width + 5 ))
panel_text="$panel_text%{O$tray_width}"
fi
panel_text="$panel_text%{r}"
full_text="$full_text$panel_text"
done
if [ "$full_text" != "$last_text" ]; then
echo -e "$full_text"
last_text="$full_text"
fi
} >> "$fifo"
unset FORCE_REFRESH
sleep 1
done