#!/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