Files
literate-dotfiles/polybar.org

42 KiB

Polybar Configuration

Colors

[colors]
bg = ${xrdb:background}
red = ${xrdb:color1}
green = ${xrdb:color2}
yellow = ${xrdb:color3}
blue = ${xrdb:color4}
purple = ${xrdb:color5}
aqua = ${xrdb:color6}
gray = ${colors.color7}
darkgray = ${colors.color8}
darkred = ${xrdb:color9}
darkgreen = ${xrdb:color10}
darkyellow = ${xrdb:color11}
darkblue = ${xrdb:color12}
darkpurple = ${xrdb:color13}
darkaqua = ${xrdb:color14}
fg = ${xrdb:foreground}

VM

[global/wm]
margin-top = 0
margin-bottom = 0

Top Bar

[bar/top]
enable-ipc = true
# override-redirect = false
bottom = false
fixed-center = false

width = 100%
height = 27
radius = 0.0

background = ${colors.bg}
foreground = ${colors.fg}

line-size = 2

border-size = 0

padding-left = 2
padding-right = 2

module-margin-left = 1
module-margin-right = 1

font-0 = Hack Nerd Font:style=Regular:pixelsize=10;1
font-1 = unifont:fontformat=truetype:size=8:antialias=false;0

modules-left = i3 xwindow
modules-center =
modules-right = pipewire music tunnel_homelab tunnel_esrf dunst lockscreen cursor unread_mail calendar timer battery date tray

# wm-restack = i3

Tray

[module/tray]
type = internal/tray
# format-margin = 8px
tray-background = ${colors.bg}
tray-spacing = 2px

Show Windows Title

[module/xwindow]
type = internal/xwindow
label = %title:0:30:...%

I3 - Information about workspaces and active one

[module/i3]
type = internal/i3

enable-scroll = false
wrapping-scroll = false
format = <label-state> <label-mode>
index-sort = true
label-mode-foreground = ${colors.bg}
label-mode-background = ${colors.fg}
label-mode-padding = 1

# focused = Active workspace on focused monitor
label-focused = %icon% %index%
label-focused-foreground = ${colors.fg}
label-focused-background = ${colors.bg}
label-focused-underline = ${colors.aqua}
label-focused-padding = 1

# unfocused = Inactive workspace on any monitor
label-unfocused = %icon% %index%
label-unfocused-foreground = ${colors.fg}
label-unfocused-background = ${colors.bg}
label-unfocused-underline = ${colors.bg}
label-unfocused-padding = 1

# visible = Active workspace on unfocused monitor
label-visible = %icon% %index%
label-visible-background = ${colors.bg}
label-visible-underline = ${colors.aqua}
label-visible-padding = 1

# urgent = Workspace with urgency hint set
label-urgent = %icon% %index%
label-urgent-background = ${colors.red}
label-urgent-padding = 1

Backlight level

[module/xbacklight]
type = internal/xbacklight

format = <ramp>
ramp-0 = 
ramp-1 = 
ramp-2 = 
ramp-3 = 
ramp-4 = 
ramp-5 = 
ramp-6 = 
ramp-7 = 
ramp-8 = 
ramp-9 = 
ramp-10 = 
ramp-11 = 

CPU Usage

[module/cpu]
type = internal/cpu
interval = 2

format-prefix-foreground = ${colors.fg}
format-underline = ${colors.bg}

label = %{A1:$TERMINAL -e htop &:} %percentage:2%%%{A}

Date

[module/date]
type = internal/date
interval = 1

# Open google calendar on left right
date = %{A1:$TERMINAL --title khal -e ikhal &:} %d-%m%{A}
date-alt = "%{A1:$TERMINAL --title khal -e ikhal &:} %d-%m-%Y%{A}"

time =  %H:%M
time-alt =  %H:%M:%S

label = %date% %time%

Music

[module/music]
type = custom/script

format-underline = ${colors.bg}
format = <label>
exec = ~/.config/polybar/scripts/music-status.sh
interval = 0.5

Music Status

playerctlstatus=$(playerctl --player=jellyfin-tui status 2> /dev/null)
title=$(playerctl --player=jellyfin-tui metadata xesam:title 2>/dev/null)
artist=$(playerctl --player=jellyfin-tui metadata xesam:artist 2>/dev/null)

display_song=""
if [[ -n "$title" && -n "$artist" ]]; then
    [[ ${#title} -gt 20 ]] && title="${title:0:20}…"
    [[ ${#artist} -gt 15 ]] && artist="${artist:0:15}…"
    display_song="$title ($artist)"
fi

if [[ $playerctlstatus ==  "" ]]; then
    echo "%{A1:~/.config/polybar/scripts/music-open.sh:}%{A}"
elif [[ $playerctlstatus =~ "Playing" ]]; then
    echo "$display_song %{A1:playerctl --player=jellyfin-tui previous:}󰒮️%{A} %{A1:playerctl --player=jellyfin-tui pause:}️%{A} %{A1:playerctl --player=jellyfin-tui next:}󰒭️%{A}"
else
    echo "$display_song %{A1:playerctl --player=jellyfin-tui previous:}󰒮️%{A} %{A1:playerctl --player=jellyfin-tui play:}️%{A} %{A1:playerctl --player=jellyfin-tui next:}󰒭️%{A}"
fi

Open Calendar

$TERMINAL --class jellyfin-tui -e tmux new-session -A -s jellyfin jellyfin-tui >/dev/null 2>%1 &

Sound Volume

[module/pipewire]
type = custom/script
tail = true
format-underline = ${colors.cyan}
label-foreground = ${colors.foreground}

# Icons mixed from Font Awesome 5 and Material Icons
# You can copy-paste your options for each possible action, which is more
# trouble-free but repetitive, or apply only the relevant ones (for example
# --sink-blacklist is only needed for next-sink).
exec = ~/.config/polybar/scripts/pipewire.sh --icons-volume " , " --icon-muted " " --sink-nickname "alsa_output.pci-0000_00_1f.3-platform-sof_sdw.HiFi__Speaker__sink:Speakers" listen
click-right = exec pwvucontrol &
click-left = ~/.config/polybar/scripts/pipewire.sh togmute
click-middle = ~/.config/polybar/scripts/pipewire.sh next-sink
scroll-up = ~/.config/polybar/scripts/pipewire.sh --volume-max 130 up
scroll-down = ~/.config/polybar/scripts/pipewire.sh --volume-max 130 down

PipeWire - Status and Control

#!/bin/bash

# Defaults for configurable values, expected to be set by command-line arguments
AUTOSYNC="no"
COLOR_MUTED="%{F#6b6b6b}"
ICON_MUTED=
ICON_SINK=
NOTIFICATIONS="no"
OSD="no"
SINK_NICKNAMES_PROP=
VOLUME_STEP=2
VOLUME_MAX=130
# shellcheck disable=SC2016
FORMAT='$VOL_ICON ${VOL_LEVEL}%  $ICON_SINK $SINK_NICKNAME'
declare -A SINK_NICKNAMES
declare -a ICONS_VOLUME
declare -a SINK_BLACKLIST

# Environment & global constants for the script
END_COLOR="%{F-}"  # For Polybar colors
LANGUAGE=en_US  # Some calls depend on English outputs of pactl

# Get the name of the default sink
# This function is modified to better handle PipeWire output
function getCurrSinkName() {
  if ! pactl info &> /dev/null; then return 1; fi
  curSinkName=$(pactl info | sed -n 's/Default Sink: *//p')
}

# Saves the currently default sink into a variable named `curSink`. It will
# return an error code when pipewire isn't running.
function getCurSink() {
    getCurrSinkName
    curSink=$(pactl list sinks short | grep -F "$curSinkName" | awk '{print $1}')
}

# Saves the sink passed by parameter's volume into a variable named `VOL_LEVEL`.
function getCurVol() {
    VOL_LEVEL=$(pactl list sinks | grep -A 15 'Sink #'"$1"'' | grep 'Volume:' | grep -E -v 'Base Volume:' | awk -F : '{print $3; exit}' | grep -o -P '.{0,3}%' | sed 's/.$//' | tr -d ' ')
}

# Saves the name to be displayed for the sink passed by parameter into a
# variable called `SINK_NICKNAME`.
# If a mapping for the sink name exists, that is used. Otherwise, the string
# "Sink #<index>" is used.
function getNickname() {
    # First check if we have a user-provided nickname
    if [[ -n "${SINK_NICKNAMES[$curSinkName]}" ]]; then
        SINK_NICKNAME="${SINK_NICKNAMES[$curSinkName]}"
    else
        # Otherwise use the sink description
        SINK_NICKNAME=$(pactl list sinks | grep -A 10 'Sink #'"$1"'' | grep 'Description:' | sed 's/^.*Description: //')
    fi
}

# Saves the status of the sink passed by parameter into a variable named
# `isMuted`.
function getIsMuted() {
    isMuted=$(pactl list sinks | grep -A 15 'Sink #'"$1"'' | awk '/Mute/ {print $2; exit}')
}

# Saves all the sink inputs of the sink passed by parameter into a string
# named `sinkInputs`.
function getSinkInputs() {
    sinkInputs=$(pactl list sink-inputs | grep -B 4 "sink: $1 " | awk '/index:/{print $2}')
}

function volUp() {
    # Obtaining the current volume from pacmd into $VOL_LEVEL.
    if ! getCurSink; then
        echo "PipeWire not running"
        return 1
    fi
    getCurVol "$curSink"
    local maxLimit=$((VOLUME_MAX - VOLUME_STEP))

    # Checking the volume upper bounds so that if VOLUME_MAX was 100% and the
    # increase percentage was 3%, a 99% volume would top at 100% instead
    # of 102%. If the volume is above the maximum limit, nothing is done.
    if [ "$VOL_LEVEL" -le "$VOLUME_MAX" ] && [ "$VOL_LEVEL" -ge "$maxLimit" ]; then
        pactl set-sink-volume "$curSink" "$VOLUME_MAX%"
    elif [ "$VOL_LEVEL" -lt "$maxLimit" ]; then
        pactl set-sink-volume "$curSink" "+$VOLUME_STEP%"
    fi

    if [ $OSD = "yes" ]; then showOSD "$curSink"; fi
    if [ $AUTOSYNC = "yes" ]; then volSync; fi
}

function volDown() {
    # Pactl already handles the volume lower bounds so that negative values
    # are ignored.
    if ! getCurSink; then
        echo "PipeWire not running"
        return 1
    fi
    pactl set-sink-volume "$curSink" "-$VOLUME_STEP%"

    if [ $OSD = "yes" ]; then showOSD "$curSink"; fi
    if [ $AUTOSYNC = "yes" ]; then volSync; fi
}

function volSync() {
    if ! getCurSink; then
        echo "PipeWire not running"
        return 1
    fi
    getSinkInputs "$curSink"
    getCurVol "$curSink"

    # Every output found in the active sink has their volume set to the
    # current one. This will only be called if $AUTOSYNC is `yes`.
    for each in $sinkInputs; do
        pactl set-sink-input-volume "$each" "$VOL_LEVEL%"
    done
}

function volMute() {
    # Switch to mute/unmute the volume with pactl.
    if ! getCurSink; then
        echo "PipeWire not running"
        return 1
    fi
    if [ "$1" = "toggle" ]; then
        getIsMuted "$curSink"
        if [ "$isMuted" = "yes" ]; then
            pactl set-sink-mute "$curSink" "no"
        else
            pactl set-sink-mute "$curSink" "yes"
        fi
    elif [ "$1" = "mute" ]; then
        pactl set-sink-mute "$curSink" "yes"
    elif [ "$1" = "unmute" ]; then
        pactl set-sink-mute "$curSink" "no"
    fi

    if [ $OSD = "yes" ]; then showOSD "$curSink"; fi
}

function nextSink() {
    # The final sinks list, removing the blacklisted ones from the list of
    # currently available sinks.
    if ! getCurSink; then
        echo "PipeWire not running"
        return 1
    fi

    # Obtaining a tuple of sink indexes after removing the blacklisted devices
    # with their name.
    sinks=()
    local i=0
    while read -r line; do
        index=$(echo "$line" | cut -f1)
        name=$(echo "$line" | cut -f2)

        # If it's in the blacklist, continue the main loop. Otherwise, add
        # it to the list.
        for sink in "${SINK_BLACKLIST[@]}"; do
            if [ "$sink" = "$name" ]; then
                continue 2
            fi
        done

        sinks[$i]="$index"
        i=$((i + 1))
    done < <(pactl list short sinks)

    # If the resulting list is empty, nothing is done
    if [ ${#sinks[@]} -eq 0 ]; then return; fi

    # If the current sink is greater or equal than last one, pick the first
    # sink in the list. Otherwise just pick the next sink avaliable.
    local newSink
    if [ "$curSink" -ge "${sinks[-1]}" ]; then
        newSink=${sinks[0]}
    else
        for sink in "${sinks[@]}"; do
            if [ "$curSink" -lt "$sink" ]; then
                newSink=$sink
                break
            fi
        done
    fi

    # The new sink is set
    echo $newSink
    pactl set-default-sink "$newSink"

    # Move all audio threads to new sink
    local inputs
    inputs="$(pactl list short sink-inputs | cut -f 1)"
    for i in $inputs; do
        pactl move-sink-input "$i" "$newSink"
    done

    if [ $NOTIFICATIONS = "yes" ]; then
        getNickname "$newSink"

        if command -v dunstify &>/dev/null; then
            notify="dunstify --replace 201839192"
        else
            notify="notify-send"
        fi
        $notify "PipeWire" "Changed output to $SINK_NICKNAME" --icon=audio-headphones-symbolic &
    fi
}

# This function assumes that PipeWire is already running. It only supports
# KDE OSDs for now. It will show a system message with the status of the
# sink passed by parameter, or the currently active one by default.
function showOSD() {
    if [ -z "$1" ]; then
        curSink="$1"
    else
        getCurSink
    fi
    getCurVol "$curSink"
    getIsMuted "$curSink"
    qdbus org.kde.kded /modules/kosd showVolume "$VOL_LEVEL" "$isMuted"
}

function listen() {
    local firstRun=0

    # Listen for changes and immediately create new output for the bar.
    # This is faster than having the script on an interval.
    LANG=$LANGUAGE pactl subscribe 2>/dev/null | {
        while true; do
            {
                # If this is the first time just continue and print the current
                # state. Otherwise wait for events. This is to prevent the
                # module being empty until an event occurs.
                if [ $firstRun -eq 0 ]; then
                    firstRun=1
                else
                    read -r event || break
                    # Avoid double events
                    if ! echo "$event" | grep -e "on card" -e "on sink" -e "on server"; then
                        continue
                    fi
                fi
            } &>/dev/null
            output
        done
    }
}

function output() {
    if ! getCurSink; then
        echo "PipeWire not running"
        return 1
    fi
    getCurVol "$curSink"
    getIsMuted "$curSink"
    getNickname "$curSink"

    # Debug output - uncomment if needed
    # echo "Debug: curSink=$curSink curSinkName=$curSinkName SINK_NICKNAME=$SINK_NICKNAME SINK_NICKNAMES=${SINK_NICKNAMES[$curSinkName]}" >&2

    # Fixed volume icons over max volume
    local iconsLen=${#ICONS_VOLUME[@]}
    if [ "$iconsLen" -ne 0 ]; then
        local volSplit=$((VOLUME_MAX / iconsLen))
        for i in $(seq 1 "$iconsLen"); do
            if [ $((i * volSplit)) -ge "$VOL_LEVEL" ]; then
                VOL_ICON="${ICONS_VOLUME[$((i-1))]}"
                break
            fi
        done
    else
        VOL_ICON=""
    fi

    # Showing the formatted message
    if [ "$isMuted" = "yes" ]; then
        # shellcheck disable=SC2034
        VOL_ICON=$ICON_MUTED
        echo "${COLOR_MUTED}$(eval echo "$FORMAT")${END_COLOR}"
    else
        eval echo "$FORMAT"
    fi
}

function usage() {
    echo "\
Usage: $0 [OPTION...] ACTION

Options: [defaults]
  --autosync | --no-autosync            whether to maintain same volume for all
                                        programs [$AUTOSYNC]
  --color-muted <rrggbb>                color in which to format when muted
                                        [${COLOR_MUTED:4:-1}]
  --notifications | --no-notifications  whether to show notifications when
                                        changing sinks [$NOTIFICATIONS]
  --osd | --no-osd                      whether to display KDE's OSD message
                                        [$OSD]
  --icon-muted <icon>                   icon to use when muted [none]
  --icon-sink <icon>                    icon to use for sink [none]
  --format <string>                     use a format string to control the output
                                        Available variables: \$VOL_ICON,
                                        \$VOL_LEVEL, \$ICON_SINK, and
                                        \$SINK_NICKNAME
                                        [$FORMAT]
  --icons-volume <icon>[,<icon>...]     icons for volume, from lower to higher
                                        [none]
  --volume-max <int>                    maximum volume to which to allow
                                        increasing [$VOLUME_MAX]
  --volume-step <int>                   step size when inc/decrementing volume
                                        [$VOLUME_STEP]
  --sink-blacklist <name>[,<name>...]   sinks to ignore when switching [none]
  --sink-nicknames-from <prop>          pacmd property to use for sink names,
                                        unless overriden by --sink-nickname.
                                        Its possible values are listed under
                                        the 'properties' key in the output of
                                        \`pacmd list-sinks\` [none]
  --sink-nickname <name>:<nick>         nickname to assign to given sink name,
                                        taking priority over
                                        --sink-nicknames-from. May be given
                                        multiple times, and 'name' is exactly as
                                        listed in the output of
                                        \`pactl list sinks short | cut -f2\`
                                        [none]

Actions:
  help              display this message and exit
  output            print the PipeWire status once
  listen            listen for changes in PipeWire to automatically update
                    this script's output
  up, down          increase or decrease the default sink's volume
  mute, unmute      mute or unmute the default sink's audio
  togmute           switch between muted and unmuted
  next-sink         switch to the next available sink
  sync              synchronize all the output streams volume to be the same as
                    the current sink's volume

Author:
    Mario Ortiz Manero
More info on GitHub:
    https://github.com/marioortizmanero/polybar-pulseaudio-control
Modified for PipeWire compatibility"
}

while [[ "$1" = --* ]]; do
    unset arg
    unset val
    if [[ "$1" = *=* ]]; then
        arg="${1//=*/}"
        val="${1//*=/}"
        shift
    else
        arg="$1"
        # Support space-separated values, but also value-less flags
        if [[ "$2" != --* ]]; then
            val="$2"
            shift
        fi
        shift
    fi

    case "$arg" in
        --autosync)
            AUTOSYNC=yes
            ;;
        --no-autosync)
            AUTOSYNC=no
            ;;
        --color-muted|--colour-muted)
            COLOR_MUTED="%{F#$val}"
            ;;
        --notifications)
            NOTIFICATIONS=yes
            ;;
        --no-notifications)
            NOTIFICATIONS=no
            ;;
        --osd)
            OSD=yes
            ;;
        --no-osd)
            OSD=no
            ;;
        --icon-muted)
            ICON_MUTED="$val"
            ;;
        --icon-sink)
            # shellcheck disable=SC2034
            ICON_SINK="$val"
            ;;
        --icons-volume)
            IFS=, read -r -a ICONS_VOLUME <<< "$val"
            ;;
        --volume-max)
            VOLUME_MAX="$val"
            ;;
        --volume-step)
            VOLUME_STEP="$val"
            ;;
        --sink-blacklist)
            IFS=, read -r -a SINK_BLACKLIST <<< "$val"
            ;;
        --sink-nicknames-from)
            SINK_NICKNAMES_PROP="$val"
            ;;
        --sink-nickname)
            SINK_NICKNAMES["${val//:*/}"]="${val//*:}"
            ;;
        --format)
	    FORMAT="$val"
            ;;
        *)
            echo "Unrecognised option: $arg" >&2
            exit 1
            ;;
    esac
done

case "$1" in
    up)
        volUp
        ;;
    down)
        volDown
        ;;
    togmute)
        volMute toggle
        ;;
    mute)
        volMute mute
        ;;
    unmute)
        volMute unmute
        ;;
    sync)
        volSync
        ;;
    listen)
        listen
        ;;
    next-sink)
        nextSink
        ;;
    output)
        output
        ;;
    help)
        usage
        ;;
    *)
        echo "Unrecognised action: $1" >&2
        exit 1
        ;;
esac

Battery

[module/battery]
type = internal/battery

battery = BAT0
adapter = AC
full-at = 95

format-charging = %{A1:xfce4-power-manager-settings &:}<ramp-capacity>  <label-charging>%{A}
format-charging-underline = ${colors.blue}

format-discharging = %{A1:xfce4-power-manager-settings &:}<ramp-capacity>  <label-discharging>%{A}
format-discharging-underline = ${colors.red}

label-full = %{A1:xfce4-power-manager-settings &:} %{A}
format-full-underline = ${colors.bg}

ramp-capacity-0 = 
ramp-capacity-1 = 
ramp-capacity-2 = 
ramp-capacity-3 = 
ramp-capacity-4 = 

Temperature

[module/temperature]
type = internal/temperature
interval = 2
thermal-zone = 0
base-temperature = 50
warn-temperature = 80
hwmon-path = /sys/class/thermal/thermal_zone10/temp
units = false
format = %{A1:$TERMINAL --title="Sensors" -e watch sensors &:}<ramp> <label>%{A}
format-warn = <ramp> <label-warn>
label = %temperature-c%°C
label-warn = %temperature-c%°C
label-warn-foreground = ${colors.fg}
format-warn-underline = ${colors.red}
ramp-0 = 
ramp-1 = 
ramp-2 = 
ramp-3 = 
ramp-4 = 
ramp-foreground = ${colors.fg}

Unread Mails

Module

[module/unread_mail]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/mail-open.sh >/dev/null 2>%1 &
click-right = ~/.config/polybar/scripts/mail-refresh.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/mail-status.sh
interval = 2

Unread Mail Scripts

mail_nb=`du -a ~/.local/share/mails/*/Inbox/new/* 2>/dev/null | wc -l`

if [ "$mail_nb" -eq "0" ]; then
  echo "";
else
  echo "%{F#859900} $mail_nb%{F-}";
fi

Refresh Mail Scripts

dunstify --replace=98465 "Mails " "Syncing...";
checkmail -q && \
    mail_nb=`du -a ~/.local/share/mails/*/Inbox/new/* 2>/dev/null | wc -l` && \
    if [ "$mail_nb" -eq "0" ]; then
        dunstify --replace=98465 "Mails " "No new mail";
    fi

Open Mails

$TERMINAL -e tmux new-session -A -s neomutt neomutt

Calendar

Module

[module/calendar]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/calendar-open.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/calendar-status.sh
interval = 5

Calendar Status Scripts

next_events=$(khal list "$(date +"%H:%M")" 23:59 --format "{start-time} - {title}" -df 'SKIPME' 2>/dev/null | grep -v 'SKIPME' | grep -v 'No events')

cal_icon=""
cal_nb=""
cal_desc=""

if [ -n "$next_events" ]; then
    events_number="$(echo "$next_events" | wc -l)"

    if [ "$events_number" -gt "1" ]; then
        cal_nb=" ($events_number)"
    fi

    next_timed_events=$(echo "$next_events" | sed -e '/^[^0-9]/d')
    if [ -z "$next_timed_events" ]; then
        # Only full day events
        cal_desc=" $(echo "$next_events" | sed -e '/^[0-9]/d;s/^ - //' | head -n 1 | cut -c 1-15)"
    else
        cal_desc=" $(echo "$next_timed_events" | head -n 1 | cut -c 1-20)"
    fi
fi

echo "${cal_icon}${cal_nb}${cal_desc}"

Open Calendar

$TERMINAL --title=khal -e ikhal

Redshift

Module

[module/redshift]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/redshift-toggle.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/redshift-status.sh
interval = 2

Redshift - Status

if pgrep -x "redshift" >/dev/null; then
    echo "";
else
    echo "󰖨";
fi

Toggle Redshift

if pgrep -x "redshift" >/dev/null; then
    killall redshift && \
        dunstify --replace=36492 "Redshift " "Turned off";
else
    nohup redshift > /dev/null 2>&1 &
    dunstify --replace=36492 "Redshift " "Starting...";
fi

Dunst

Module

[module/dunst]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/dunst-toggle.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/dunst-status.sh
interval = 2

Dunst Status script

tmpfile="/tmp/dunststatus";

if [ -f $tmpfile ]; then
  if grep -q "on" $tmpfile; then
    echo "";
  elif grep -q "off" $tmpfile; then
    echo "";
  fi
else
  echo "";
fi

Dunst Toggle

tmpfile="/tmp/dunststatus";

if [ -f $tmpfile ] && grep -q "off" $tmpfile ; then
    killall -SIGUSR2 dunst && \
        echo "on" > $tmpfile;
    dunstify --replace=16549 "Notifications " "Activated";
else
    dunstify --replace=16549 "Notifications " "Deactivated";
    sleep 1 && \
        killall -SIGUSR1 dunst && \
        echo "off" > $tmpfile;
fi

Lock Screen

Module

[module/lockscreen]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/lockscreen-toggle.sh >/dev/null 2>%1 &
click-right = ~/.config/polybar/scripts/lockscreen-activate.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/lockscreen-status.sh

interval = 2

Lock screen Status script

if pgrep -x "xautolock" >/dev/null
then
    echo "";
else
    echo "";
fi

Toggle Automatic Lock Screen

if pgrep -x "xautolock" >/dev/null ; then
    pkill xautolock && \
        dunstify --replace=13602 'Lock Screen ' 'Desactivated'; xset s off -dpms
else
    xautolock -locker "~/.local/bin/lockscreen" -detectsleep -time 30 -notify 60 -notifier "dunstify --replace=31846 -u critical -t 10000 -- 'Locking Screen' '60 seconds'" &
    xset s on +dpms
    dunstify --replace=13602 'Lock Screen ' 'Activated'
fi

Activate Lock Screen

~/.local/bin/lockscreen &
xset s activate

Network

Modules

[module/wired-network]
type = internal/network
interface = enp57s0u2u4u4

label-connected = %{A3:bash ~/.config/polybar/scripts/connection-manager.sh >/dev/null 2>%1 &:}%{A1:bash ~/.config/polybar/scripts/connection-toggle.sh enp57s0u2u4u4 >/dev/null 2>%1 &:} %local_ip%%{A}%{A}
label-connected-foreground = ${colors.fg}

label-disconnected = %{A3:bash ~/.config/polybar/scripts/connection-manager.sh >/dev/null 2>%1 &:}%{A1:bash ~/.config/polybar/scripts/connection-toggle.sh enp57s0u2u4u4 >/dev/null 2>%1 &:}%{A}%{A}
label-disconnected-foreground = #777
[module/wireless-network]
type = internal/network
interface = wlp2s0

format-connected = <label-connected>
format-disconnected = <label-disconnected>

label-connected = %{A3:bash ~/.config/polybar/scripts/connection-manager.sh >/dev/null 2>%1 &:}%{A1:bash ~/.config/polybar/scripts/connection-toggle.sh wlp2s0 >/dev/null 2>%1 &:}直 %essid%%{A}%{A}
label-connected-foreground = ${colors.fg}

label-disconnected = %{A3:bash ~/.config/polybar/scripts/connection-manager.sh >/dev/null 2>%1 &:}%{A1:bash ~/.config/polybar/scripts/connection-toggle.sh wlp2s0 >/dev/null 2>%1 &:}直%{A}%{A}
label-disconnected-foreground = #777

Run Network Manager

$TERMINAL -e sudo nmtui

Toggle Wifi or Ethernet

# Check if an argument is passed
if [ -z "$1" ]
then
    exit 1
fi

isdevicedown=$(nmcli device status | grep ^$1 | grep disconnected)

if [ -z "$isdevicedown" ]
then
  dunstify --replace=84847 "$1" "Disconnecting..." && \
        nmcli device disconnect $1 && \
        dunstify --replace=84847 "$1" "Disconnected"
else
  dunstify --replace=84847 "$1" "Connection..." && \
        nmcli device connect $1 && \
        dunstify --replace=84847 "$1" "Connected"
fi

Bluetooth

Module

[module/bluetooth]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/bluetooth-toggle.sh >/dev/null 2>%1 &
click-right = ~/.config/polybar/scripts/bluetooth-run.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/bluetooth-status.sh

interval = 2

bluetooth-run.sh - Bluetooth Run Manager

blueman-manager && pkill blueman-applet

bluetooth-status.sh - Bluetooth Connection Status

controllerid="9C:B6:D0:96:6E:C0"

isconnected=$(bluetoothctl show $controllerid | grep Powered | grep yes)

if [ -z "$isconnected" ]
then
    echo ""
else
    echo "%{F#859900}%{F-}"
fi

bluetooth-toggle.sh - Toggle Bluetooth Connection

controllerid="9C:B6:D0:96:6E:C0"

isconnected=$(bluetoothctl show $controllerid | grep Powered | grep yes)

if [ -z "$isconnected" ]
then
    bluetoothctl power on && \
        dunstify --replace=88498 "Bluetooth" "Power ON"
else
    bluetoothctl power off && \
        dunstify --replace=88498 "Bluetooth" "Power OFF"
fi

NordVPN

Module

[module/nordvpn]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/nordvpn-toggle >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/nordvpn-status.sh
interval = 2

Nordvpn Status script

tmpfile="/tmp/vpnstatus";

if [ -f $tmpfile ] && grep -q "on" $tmpfile; then
  echo "%{F#859900}󰲀%{F-}";
else
  echo "󰲀";
fi

Nordvpn Toggle

The script is accessible here.

Wireguard

Module

[module/wireguard]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/wireguard-toggle.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/wireguard-status.sh

interval = 2

Wireguard Connection Status

config="homelab"

connection=$(sudo wg show "$config" 2>/dev/null | head -n 1 | awk '{print $NF }')

if [ "$connection" = "$config" ]; then
    echo "%{F#859900}󰒄%{F-}"
else
    echo "󰒄"
fi

Toggle Wireguard Connection

config="homelab"

connection=$(sudo wg show "$config" 2>/dev/null | head -n 1 | awk '{print $NF }')

if [ "$connection" = "$config" ]; then
    sudo wg-quick down "$config" && \
        dunstify --replace=83244 "Wireguard" "Disconnected from $config"
else
    sudo wg-quick up "$config" && \
        dunstify --replace=83244 "Wireguard" "Connected to $config"
fi

Highlight cursor

Module

[module/cursor]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/cursor-toggle.sh >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/cursor-status.sh

interval = 2

Cursor - Status

if pgrep -x "highlight-point" >/dev/null; then
    echo "%{F#859900}%{F-}";
else
    echo "";
fi

Toggle Cursor

if pgrep -x "highlight-point" >/dev/null; then
    killall highlight-pointer && \
        dunstify --replace=22111 --hint=string:x-dunst-stack-tag:kidF4g53 "Cursor" "Turned off";
else
    nohup highlight-pointer -r 10 > /dev/null 2>&1 &
    dunstify --replace=22111 --hint=string:x-dunst-stack-tag:kidF4g53 "Cursor" "Highlight...";
fi

Mounted Drives

Modules

[module/drive_tmp]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/mount-dir tmp_14_days >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/drive-status.sh tmp_14_days T

interval = 5
[module/drive_groupshare]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/mount-dir groupshare >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/drive-status.sh groupshare G

interval = 5
[module/drive_homelab]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/mount-dir homelab >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/drive-status.sh homelab H

interval = 5
[module/drive_unix_home]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/mount-dir unix_home >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/drive-status.sh unix_home U

interval = 5
[module/drive_monochromator]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/mount-dir monochromators >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/drive-status.sh monochromators M

interval = 5
[module/drive_data_id21]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.local/bin/mount-dir data_id21 >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/drive-status.sh data_id21 D

interval = 5

Drive - Status

if mountpoint -q ~/mnt/$1; then
    echo "%{F#859900}$2 󰡰%{F-}";
else
    echo "$2 󰲁";
fi

Tunnel Status

Module

[module/tunnel_esrf]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/systemd-service-toggle.sh esrf-tunnel E >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/systemd-service-status.sh esrf-tunnel E

interval = 2
[module/tunnel_homelab]
type = custom/script

format-underline = ${colors.bg}
click-left = ~/.config/polybar/scripts/systemd-service-toggle.sh homelab-tunnel H >/dev/null 2>%1 &
format = <label>
exec = ~/.config/polybar/scripts/systemd-service-status.sh homelab-tunnel H

interval = 2

Tunnel - Status

SERVICE_NAME="$1"

if [ "$(systemctl --user is-active "$SERVICE_NAME")" != "active" ]
then
    echo "$2 󰢭";
else
    echo "%{F#859900}$2 󰢭%{F-}";
fi

Tunnel - Toggle

SERVICE_NAME="$1"

if [ "$(systemctl --user is-active $SERVICE_NAME)" != "active" ]
then
    systemctl --user start $SERVICE_NAME
else
    systemctl --user stop $SERVICE_NAME
fi

Timer

Module

[module/timer]
type = custom/script

format = <label>
exec = ~/.config/polybar/scripts/timer.sh tail 'TIMER' 5
tail = true

click-left = ~/.config/polybar/scripts/timer.sh new 25 'Pomo session' 'Paused' 'notify-send "Session finished"' ; ~/.config/polybar/scripts/timer.sh update %pid%
click-middle = ~/.config/polybar/scripts/timer.sh cancel ; ~/.config/polybar/scripts/timer.sh update %pid%
click-right = ~/.config/polybar/scripts/timer.sh togglepause ; ~/.config/polybar/scripts/timer.sh update %pid%
scroll-up = ~/.config/polybar/scripts/timer.sh increase 60 || ~/.config/polybar/scripts/timer.sh new 1 'TIMER' 'PAUSED' 'notify-send -u critical "Timer expired."' ; ~/.config/polybar/scripts/timer.sh update %pid%
scroll-down = ~/.config/polybar/scripts/timer.sh increase -60 ; ~/.config/polybar/scripts/timer.sh update %pid%

interval = 2

Timer

### AUTHOR:         Johann Birnick (github: jbirnick)
### PROJECT REPO:   https://github.com/jbirnick/polybar-timer

## FUNCTIONS

now () { date --utc +%s; }

killTimer () { rm -rf /tmp/polybar-timer ; }
timerSet () { [ -e /tmp/polybar-timer/ ] ; }
timerPaused () { [ -f /tmp/polybar-timer/paused ] ; }

timerExpiry () { cat /tmp/polybar-timer/expiry ; }
timerLabelRunning () { cat /tmp/polybar-timer/label_running ; }
timerLabelPaused () { cat /tmp/polybar-timer/label_paused ; }
timerAction () { cat /tmp/polybar-timer/action ; }

secondsLeftWhenPaused () { cat /tmp/polybar-timer/paused ; }
minutesLeftWhenPaused () {  echo $(( ( $(secondsLeftWhenPaused)  + 59 ) / 60 )) ; }
secondsLeft () { echo $(( $(timerExpiry) - $(now) )) ; }
minutesLeft () { echo $(( ( $(secondsLeft)  + 59 ) / 60 )) ; }

printExpiryTime () { dunstify -u low -r -12345 "Timer expires at $( date -d "$(secondsLeft) sec" +%H:%M)" ;}
printPaused () { dunstify -u low -r -12345 "Timer paused" ; }
removePrinting () { dunstify -C -12345 ; }

updateTail () {
  # check whether timer is expired
  if timerSet
  then
    if { timerPaused && [ $(minutesLeftWhenPaused) -le 0 ] ; } || { ! timerPaused && [ $(minutesLeft) -le 0 ] ; }
    then
      eval $(timerAction)
      killTimer
      removePrinting
    fi
  fi

  # update output
  if timerSet
  then
    if timerPaused
    then
      echo "$(timerLabelPaused) $(minutesLeftWhenPaused)"
    else
      echo "$(timerLabelRunning) $(minutesLeft)"
    fi
  else
    echo "${STANDBY_LABEL}"
  fi
}

## MAIN CODE

case $1 in
  tail)
    STANDBY_LABEL=$2

    trap updateTail USR1

    while true
     do
     updateTail
     sleep ${3} &
     wait
    done
    ;;
  update)
    kill -USR1 $(pgrep --oldest --parent ${2})
    ;;
  new)
    killTimer
    mkdir /tmp/polybar-timer
    echo "$(( $(now) + 60*${2} ))" > /tmp/polybar-timer/expiry
    echo "${3}" > /tmp/polybar-timer/label_running
    echo "${4}" > /tmp/polybar-timer/label_paused
    echo "${5}" > /tmp/polybar-timer/action
    printExpiryTime
    ;;
  increase)
    if timerSet
    then
      if timerPaused
      then
        echo "$(( $(secondsLeftWhenPaused) + ${2} ))" > /tmp/polybar-timer/paused
      else
        echo "$(( $(timerExpiry) + ${2} ))" > /tmp/polybar-timer/expiry
        printExpiryTime
      fi
    else
      exit 1
    fi
    ;;
  cancel)
    killTimer
    removePrinting
    ;;
  togglepause)
    if timerSet
    then
      if timerPaused
      then
        echo "$(( $(now) + $(secondsLeftWhenPaused) ))" > /tmp/polybar-timer/expiry
        rm -f /tmp/polybar-timer/paused
        printExpiryTime
      else
        secondsLeft > /tmp/polybar-timer/paused
        rm -f /tmp/polybar-timer/expiry
        printPaused
      fi
    else
      exit 1
    fi
    ;;
  *)
    echo "Please read the manual at https://github.com/jbirnick/polybar-timer ."
    ;;
esac

Screenshot

[module/screenshot]
type = custom/text
content = ""
click-left = ~/.local/bin/screenshot >/dev/null 2>%1 &