--- a/i3blocks.conf +++ b/i3blocks.conf @@ -28,6 +28,11 @@ separator_block_width=15 markup=none +# Brightness indicator +#[brightness] +#label=BRI +#interval=5 + # Volume indicator # # The first parameter sets the step (and units to display) @@ -97,15 +102,6 @@ #[load_average] #interval=10 -# Battery indicator -# -# The battery instance defaults to 0. -[battery] -label=BAT -#label=⚡ -#instance=1 -interval=30 - # Date Time # [time] @@ -127,14 +123,14 @@ #[openvpn] #interval=20 -# Temperature +# WireGuard support # -# Support multiple chips, though lm-sensors. -# The script may be called with -w and -c switches to specify thresholds, -# see the script for details. -#[temperature] -#label=TEMP -#interval=10 +# Support VPN, with colors. +#[wireguard] +#label=VPN +#interval=5 +#instance=wg0 +#markup=pango # Key indicators # --- a/scripts/bandwidth +++ b/scripts/bandwidth @@ -2,6 +2,7 @@ # Copyright (C) 2012 Stefan Breunig # Copyright (C) 2014 kaueraal # Copyright (C) 2015 Thiago Perrotta +# Copyright (C) 2020 Jesús E. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,15 +17,42 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +# Get custom IN and OUT labels if provided by command line arguments +while [[ $# -gt 1 ]]; do + key="$1" + case "$key" in + -i|--inlabel) + INLABEL="$2" + shift;; + -o|--outlabel) + OUTLABEL="$2" + shift;; + esac + shift +done + +[[ -z "$INLABEL" ]] && INLABEL="IN " +[[ -z "$OUTLABEL" ]] && OUTLABEL="OUT " + # Use the provided interface, otherwise the device used for the default route. -if [[ -n $BLOCK_INSTANCE ]]; then - INTERFACE=$BLOCK_INSTANCE -else - INTERFACE=$(ip route | awk '/^default/ { print $5 ; exit }') +if [[ -z $INTERFACE ]] && [[ -n $BLOCK_INSTANCE ]]; then + INTERFACE=$BLOCK_INSTANCE +elif [[ -z $INTERFACE ]]; then + # Verify tun, vpn connection + if [[ $(ip route | awk '/^default/ { print $5 ; exit }') = "tun0" ]]; then + INTERFACE=$(ip route | awk -v i=5 -v j=3 'FNR == i {print $j}') + else + INTERFACE=$(ip route | awk '/^default/ { print $5 ; exit }') + fi fi +# Exit if there is no default route +[[ -z "$INTERFACE" ]] && exit + # Issue #36 compliant. -if ! [ -e "/sys/class/net/${INTERFACE}/operstate" ] || ! [ "`cat /sys/class/net/${INTERFACE}/operstate`" = "up" ] +if ! [ -e "/sys/class/net/${INTERFACE}/operstate" ] || \ + { ! [ "$TREAT_UNKNOWN_AS_UP" = "1" ] && + ! [ "$(cat "/sys/class/net/${INTERFACE}/operstate")" = "up" ]; } then echo "$INTERFACE down" echo "$INTERFACE down" @@ -33,11 +61,11 @@ then fi # path to store the old results in -path="/dev/shm/$(basename $0)-${INTERFACE}" +path="/dev/shm/$(basename "$0")-${INTERFACE}" # grabbing data for each adapter. -read rx < "/sys/class/net/${INTERFACE}/statistics/rx_bytes" -read tx < "/sys/class/net/${INTERFACE}/statistics/tx_bytes" +read -r rx < "/sys/class/net/${INTERFACE}/statistics/rx_bytes" +read -r tx < "/sys/class/net/${INTERFACE}/statistics/tx_bytes" # get time time=$(date +%s) @@ -45,46 +73,46 @@ time=$(date +%s) # write current data if file does not exist. Do not exit, this will cause # problems if this file is sourced instead of executed as another process. if ! [[ -f "${path}" ]]; then - echo "${time} ${rx} ${tx}" > "${path}" - chmod 0666 "${path}" + echo "${time} ${rx} ${tx}" > "${path}" + chmod 0666 "${path}" fi # read previous state and update data storage -read old < "${path}" +read -r old < "${path}" echo "${time} ${rx} ${tx}" > "${path}" # parse old data and calc time passed old=(${old//;/ }) -time_diff=$(( $time - ${old[0]} )) +time_diff=$(( time - old[0] )) # sanity check: has a positive amount of time passed [[ "${time_diff}" -gt 0 ]] || exit # calc bytes transferred, and their rate in byte/s -rx_diff=$(( $rx - ${old[1]} )) -tx_diff=$(( $tx - ${old[2]} )) -rx_rate=$(( $rx_diff / $time_diff )) -tx_rate=$(( $tx_diff / $time_diff )) +rx_diff=$(( rx - old[1] )) +tx_diff=$(( tx - old[2] )) +rx_rate=$(( rx_diff / time_diff )) +tx_rate=$(( tx_diff / time_diff )) # shift by 10 bytes to get KiB/s. If the value is larger than # 1024^2 = 1048576, then display MiB/s instead # incoming -echo -n "IN " -rx_kib=$(( $rx_rate >> 10 )) -if [[ "$rx_rate" -gt 1048576 ]]; then - printf '%sM' "`echo "scale=1; $rx_kib / 1024" | bc`" +echo -n "$INLABEL" +rx_kib=$(( rx_rate >> 10 )) +if hash bc 2>/dev/null && [[ "$rx_rate" -gt 1048576 ]]; then + printf '%sM' "$(echo "scale=1; $rx_kib / 1024" | bc)" else - echo -n "${rx_kib}K" + echo -n "${rx_kib}K" fi echo -n " " # outgoing -echo -n "OUT " -tx_kib=$(( $tx_rate >> 10 )) -if [[ "$tx_rate" -gt 1048576 ]]; then - printf '%sM' "`echo "scale=1; $tx_kib / 1024" | bc`" +echo -n "$OUTLABEL" +tx_kib=$(( tx_rate >> 10 )) +if hash bc 2>/dev/null && [[ "$tx_rate" -gt 1048576 ]]; then + printf '%sM\n' "$(echo "scale=1; $tx_kib / 1024" | bc)" else - echo -n "${tx_kib}K" + echo -n "${tx_kib}K" fi --- a/scripts/disk +++ b/scripts/disk @@ -17,7 +17,7 @@ DIR="${BLOCK_INSTANCE:-$HOME}" ALERT_LOW="${1:-10}" # color will turn red under this value (default: 10%) -df -h -P -l "$DIR" | awk -v alert_low=$ALERT_LOW ' +df -h -P -l "$DIR" | awk -v alert_low="$ALERT_LOW" ' /\/.*/ { # full text print $4 --- a/scripts/iface +++ b/scripts/iface @@ -1,6 +1,7 @@ #!/bin/bash # Copyright (C) 2014 Julien Bonjean # Copyright (C) 2014 Alexander Keller +# Copyright (C) 2020 Jesús E. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,11 +19,11 @@ #------------------------------------------------------------------------ # Use the provided interface, otherwise the device used for the default route. -if [[ -n $BLOCK_INSTANCE ]]; then - IF=$BLOCK_INSTANCE -else - IF=$(ip route | awk '/^default/ { print $5 ; exit }') -fi +IF="${IFACE:-$BLOCK_INSTANCE}" +IF="${IF:-$(ip route | awk '/^default/ { print $5 ; exit }')}" + +# Exit if there is no default route +[[ -z "$IF" ]] && exit #------------------------------------------------------------------------ @@ -32,30 +33,33 @@ fi #------------------------------------------------------------------------ -if [[ "$(cat /sys/class/net/$IF/operstate)" = 'down' ]]; then - echo down # full text - echo down # short text - echo \#FF0000 # color - exit -fi +LABEL="${LABEL:-}" -case $1 in - -4) - AF=inet ;; - -6) - AF=inet6 ;; - *) - AF=inet6? ;; -esac +for flag in "$1" "$2"; do + case "$flag" in + -L) + if [[ "$IF" = "" ]]; then + LABEL="iface " + else + LABEL="$IF: " + fi ;; + esac +done + +if [[ "$IF" = "" ]] || [[ "$(cat "/sys/class/net/$IF/operstate")" = 'down' ]]; +then + echo "${LABEL}down" # text + echo \#FF0000 # color + exit +fi -# if no interface is found, use the first device with a global scope -IPADDR=$(ip addr show $IF | perl -n -e "/$AF ([^\/]+).* scope global/ && print \$1 and exit") +# Check local ip address +IPADDR=$(ip route get 4.2.2.1 | grep -oE "src [.0-9]+" | awk '{print $NF;exit}') case $BLOCK_BUTTON in - 3) echo -n "$IPADDR" | xclip -q -se c ;; + 3) echo -n "$IPADDR" | xclip -q -se c ;; esac #------------------------------------------------------------------------ -echo "$IPADDR" # full text -echo "$IPADDR" # short text +echo "$LABEL$IPADDR" --- a/scripts/load_average +++ b/scripts/load_average @@ -24,7 +24,7 @@ echo "$load" echo "$load" # color if load is too high -awk -v cpus=$cpus -v cpuload=$load ' +awk -v cpus="$cpus" -v cpuload="$load" ' BEGIN { if (cpus <= cpuload) { print "#FF0000"; --- a/scripts/mediaplayer +++ b/scripts/mediaplayer @@ -1,28 +1,29 @@ #!/usr/bin/perl +# # Copyright (C) 2014 Tony Crisci - +# Copyright (C) 2015 Thiago Perrotta +# Copyright (c) 2021 Jesús E. +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. - +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. - +# # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Requires playerctl binary to be in your path (except cmus) -# See: https://github.com/acrisci/playerctl - -# Set instance=NAME in the i3blocks configuration to specify a music player -# (playerctl will attempt to connect to org.mpris.MediaPlayer2.[NAME] on your -# DBus session). +# Set instance=NAME in the i3blocks configuration to specify a music player. +use Time::HiRes qw(usleep); use Env qw(BLOCK_INSTANCE); +use constant DELAY => 50; # Delay in ms to let network-based reflect new data. + my @metadata = (); my $player_arg = ""; @@ -30,16 +31,41 @@ if ($BLOCK_INSTANCE) { $player_arg = "--player='$BLOCK_INSTANCE'"; } -if ($ENV{'BLOCK_BUTTON'} == 1) { - system("playerctl $player_arg previous"); -} elsif ($ENV{'BLOCK_BUTTON'} == 2) { - system("playerctl $player_arg play-pause"); -} elsif ($ENV{'BLOCK_BUTTON'} == 3) { - system("playerctl $player_arg next"); +sub buttons { + my $method = shift; + + if($method eq 'mpd') { + if ($ENV{'BLOCK_BUTTON'} == 1) { + system("mpc prev"); + } elsif ($ENV{'BLOCK_BUTTON'} == 2) { + system("mpc toggle"); + } elsif ($ENV{'BLOCK_BUTTON'} == 3) { + system("mpc next"); + } elsif ($ENV{'BLOCK_BUTTON'} == 4) { + system("mpc volume +10"); + } elsif ($ENV{'BLOCK_BUTTON'} == 5) { + system("mpc volume -10"); + } + } elsif ($method eq 'cmus') { + if ($ENV{'BLOCK_BUTTON'} == 1) { + system("cmus-remote --prev"); + } elsif ($ENV{'BLOCK_BUTTON'} == 2) { + system("cmus-remote --pause"); + } elsif ($ENV{'BLOCK_BUTTON'} == 3) { + system("cmus-remote --next"); + } + } elsif ($method eq 'rhythmbox') { + if ($ENV{'BLOCK_BUTTON'} == 1) { + system("rhythmbox-client --previous"); + } elsif ($ENV{'BLOCK_BUTTON'} == 2) { + system("rhythmbox-client --play-pause"); + } elsif ($ENV{'BLOCK_BUTTON'} == 3) { + system("rhythmbox-client --next"); + } + } } -if ($player_arg eq '' or $player_arg =~ /cmus$/) { - # try cmus first +sub cmus { my @cmus = split /^/, qx(cmus-remote -Q); if ($? == 0) { foreach my $line (@cmus) { @@ -54,23 +80,41 @@ if ($player_arg eq '' or $player_arg =~ /cmus$/) { } if (@metadata) { + buttons('cmus'); + # metadata found so we are done print(join ' - ', @metadata); exit 0; } } +} - # if cmus was given, we are done - exit 0 unless $player_arg eq ''; +sub mpd { + my $data = qx(mpc current); + if (not $data eq '') { + buttons("mpd"); + print($data); + exit 0; + } } -my $artist = qx(playerctl $player_arg metadata artist); -# exit status will be nonzero when playerctl cannot find your player -exit(0) if $?; -push(@metadata, $artist) if $artist; +sub rhythmbox { + buttons('rhythmbox'); -my $title = qx(playerctl $player_arg metadata title); -exit(0) if $?; -push(@metadata, $title) if $title; + my $data = qx(rhythmbox-client --print-playing --no-start); + print($data); +} -print(join(" - ", @metadata)) if @metadata; +if ($player_arg eq '' or $player_arg =~ /mpd/) { + mpd; +} +elsif ($player_arg =~ /cmus/) { + cmus; +} +elsif ($player_arg =~ /rhythmbox/) { + rhythmbox; +} +else { + print('unknown'); +} +print("\n"); --- a/scripts/memory +++ b/scripts/memory @@ -16,7 +16,7 @@ TYPE="${BLOCK_INSTANCE:-mem}" -awk -v type=$TYPE ' +awk -v type="$TYPE" ' /^MemTotal:/ { mem_total=$2 } --- a/scripts/volume +++ b/scripts/volume @@ -1,6 +1,7 @@ #!/bin/bash # Copyright (C) 2014 Julien Bonjean # Copyright (C) 2014 Alexander Keller +# Copyright (C) 2021 Jesús E. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,53 +19,57 @@ #------------------------------------------------------------------------ # The second parameter overrides the mixer selection -# For PulseAudio users, use "pulse" # For Jack/Jack2 users, use "jackplug" # For ALSA users, you may use "default" for your primary card # or you may use hw:# where # is the number of the card desired -MIXER="default" -[ -n "$(lsmod | grep pulse)" ] && MIXER="pulse" -[ -n "$(lsmod | grep jack)" ] && MIXER="jackplug" -MIXER="${2:-$MIXER}" +if [[ -z "$MIXER" ]] ; then + MIXER="default" + lsmod | grep -q jack && MIXER="jackplug" + MIXER="${2:-$MIXER}" +fi # The instance option sets the control to report and configure # This defaults to the first control of your selected mixer # For a list of the available, use `amixer -D $Your_Mixer scontrols` -SCONTROL="${BLOCK_INSTANCE:-$(amixer -D $MIXER scontrols | - sed -n "s/Simple mixer control '\([A-Za-z ]*\)',0/\1/p" | - head -n1 - )}" +if [[ -z "$SCONTROL" ]] ; then + SCONTROL="${BLOCK_INSTANCE:-$(amixer -D "$MIXER" scontrols | + sed -n "s/Simple mixer control '\([^']*\)',0/\1/p" | + head -n1 + )}" +fi # The first parameter sets the step to change the volume by (and units to display) # This may be in in % or dB (eg. 5% or 3dB) -STEP="${1:-5%}" +if [[ -z "$STEP" ]] ; then + STEP="${1:-5%}" +fi #------------------------------------------------------------------------ capability() { # Return "Capture" if the device is a capture device - amixer -D $MIXER get $SCONTROL | - sed -n "s/ Capabilities:.*cvolume.*/Capture/p" + amixer -D "$MIXER" get "$SCONTROL" | sed -n "s/ Capabilities:.*cvolume.*/Capture/p" } volume() { - amixer -D $MIXER get $SCONTROL $(capability) + amixer -D "$MIXER" get "$SCONTROL" "$(capability)" } format() { - perl_filter='if (/.*\[(\d+%)\] (\[(-?\d+.\d+dB)\] )?\[(on|off)\]/)' - perl_filter+='{CORE::say $4 eq "off" ? "MUTE" : "' - # If dB was selected, print that instead - perl_filter+=$([[ $STEP = *dB ]] && echo '$3' || echo '$1') - perl_filter+='"; exit}' - perl -ne "$perl_filter" + perl_filter='if (/.*\[(\d+%)\] (\[(-?\d+.\d+dB)\] )?\[(on|off)\]/)' + perl_filter+='{CORE::say $4 eq "off" ? "MUTE" : "' + # If dB was selected, print that instead + perl_filter+=$([[ $STEP = *dB ]] && echo '$3' || echo '$1') + perl_filter+='"; exit}' + output=$(perl -ne "$perl_filter") + echo "$LABEL$output" } #------------------------------------------------------------------------ case $BLOCK_BUTTON in - 3) amixer -q -D $MIXER sset $SCONTROL $(capability) toggle ;; # right click, mute/unmute - 4) amixer -q -D $MIXER sset $SCONTROL $(capability) ${STEP}+ unmute ;; # scroll up, increase - 5) amixer -q -D $MIXER sset $SCONTROL $(capability) ${STEP}- unmute ;; # scroll down, decrease + 3) "amixer -q -D $MIXER sset $SCONTROL $(capability) toggle" ;; # right click, mute/unmute + 4) "amixer -q -D $MIXER sset $SCONTROL $(capability) ${STEP}+ unmute" ;; # scroll up, increase + 5) "amixer -q -D $MIXER sset $SCONTROL $(capability) ${STEP}- unmute" ;; # scroll down, decrease esac -volume | format +volume "$@" | format "$@" --- a/scripts/wifi +++ b/scripts/wifi @@ -23,16 +23,16 @@ INTERFACE="${BLOCK_INSTANCE:-wlan0}" # As per #36 -- It is transparent: e.g. if the machine has no battery or wireless # connection (think desktop), the corresponding block should not be displayed. [[ ! -d /sys/class/net/${INTERFACE}/wireless ]] || - [[ "$(cat /sys/class/net/$INTERFACE/operstate)" = 'down' ]] && exit + [[ "$(cat "/sys/class/net/$INTERFACE/operstate")" = 'down' ]] && exit #------------------------------------------------------------------------ -QUALITY=$(grep $INTERFACE /proc/net/wireless | awk '{ print int($3 * 100 / 70) }') +QUALITY=$(grep "$INTERFACE" /proc/net/wireless | awk '{ print int($3 * 100 / 70) }') #------------------------------------------------------------------------ -echo $QUALITY% # full text -echo $QUALITY% # short text +echo "$QUALITY%" # full text +echo "$QUALITY%" # short text # color if [[ $QUALITY -ge 80 ]]; then --- a/i3blocks.1 +++ b/i3blocks.1 @@ -184,22 +184,6 @@ If the command line returns 0 or 33, the block is updated\. Otherwise, it is considered a failure and the first line (if any) is still displayed\. Note that stderr is ignored\. A return code of 33 will set the \fBurgent\fR flag to true\. . .P -For example, this script prints the battery percentage and sets the urgent flag if it is below 10%: -. -.IP "" 4 -. -.nf - -BAT=`acpi \-b | grep \-E \-o \'[0\-9][0\-9]?%\'` - -echo "BAT: $BAT" -test ${BAT%?} \-le 10 && exit 33 || exit 0 -. -.fi -. -.IP "" 0 -. -.P When forking a block command, \fBi3blocks\fR will set the environment with some \fBBLOCK_*\fR variables\. The following variables are always provided, with eventually an empty string as the value\. . .TP @@ -240,7 +224,7 @@ .IP "" 0 . .P -Note that \fBi3blocks\fR provides a set of optional scripts for convenience, such as network status, battery check, cpu load, volume, etc\. +Note that \fBi3blocks\fR provides a set of optional scripts for convenience, such as network status, cpu load, volume, etc\. . .SH "EXAMPLES" As an example, here is a close configuration to i3status(1) default settings: @@ -268,8 +252,6 @@ [ethernet] min_width=E: 255\.255\.255\.255 (1000 Mbit/s) -[battery] - [cpu] [datetime] @@ -308,7 +290,6 @@ [free] [wifi] [ethernet] -[battery] [cpu] [datetime] . --- a/i3blocks.1.ronn +++ b/i3blocks.1.ronn @@ -139,14 +139,6 @@ considered a failure and the first line (if any) is still displayed. Note that stderr is ignored. A return code of 33 will set the `urgent` flag to true. -For example, this script prints the battery percentage and sets the urgent flag -if it is below 10%: - - BAT=`acpi -b | grep -E -o '[0-9][0-9]?%'` - - echo "BAT: $BAT" - test ${BAT%?} -le 10 && exit 33 || exit 0 - When forking a block command, **i3blocks** will set the environment with some `BLOCK_*` variables. The following variables are always provided, with eventually an empty string as the value. @@ -176,7 +168,7 @@ align=left Note that **i3blocks** provides a set of optional scripts for convenience, such -as network status, battery check, cpu load, volume, etc. +as network status, cpu load, volume, etc. ## EXAMPLES @@ -200,8 +192,6 @@ [ethernet] min_width=E: 255.255.255.255 (1000 Mbit/s) - [battery] - [cpu] [datetime] @@ -224,7 +214,6 @@ [free] [wifi] [ethernet] - [battery] [cpu] [datetime]