This commit is contained in:
Liam Waldron 2023-07-20 16:59:11 -04:00
commit 9ec09f9238
10 changed files with 1127 additions and 0 deletions

96
config Normal file
View File

@ -0,0 +1,96 @@
# i3blocks configuration file
#
# The i3blocks man page describes the usage of the binary,
# and its website describes the configuration:
#
# https://vivien.github.io/i3blocks
SCRIPT_DIR=/home/arco/.config/i3blocks/scripts
# Global properties
separator=true
separator_block_width=30
[mediaplayer]
command=$SCRIPT_DIR/mediaplayer
interval=1
#[documentation]
#full_text=Documentation
#website=https://vivien.github.io/i3blocks
#command=xdg-open "$website"
#color=#f12711
#[greetings]
#color=#f5af19
#command=echo "Hello, $USER!"
#interval=once
[volume]
command=$SCRIPT_DIR/volume
LABEL=♪
#LABEL=VOL
interval=once
signal=10
STEP=5%
MIXER=pulse
#SCONTROL=[determined automatically]
#NATURAL_MAPPING=0
[dunst]
command=$SCRIPT_DIR/dunst
interval=once
format=json
markup=pango
#min_width=50
align=center
[disk]
command=$SCRIPT_DIR/disk
DIR=/
LABEL=🖴
interval=30
[batterybar]
command=$SCRIPT_DIR/batterybar
label=⏻
interval=5
markup=pango
min_width=bat: ■■■■■
# Discharging colors low to high
C1=#FF0027
C2=#FF3B05
C3=#FFB923
C4=#FFD000
C5=#E4FF00
C6=#ADFF00
C7=#6DFF00
C8=#10BA00
CHARGING_COLOR=#00AFE3
FULL_COLOR=#FFFFFF
AC_COLOR=#535353
[time]
command=date '+%m/%d/%Y %H:%M'
interval=15
[shutdown_menu]
full_text= ⏻ Power Menu
# If you are using FontAwesome, we recommend the power-off icon:
# http://fontawesome.io/icon/power-off/
command=$SCRIPT_DIR/shutdown_menu
#FG_COLOR=#bbbbbb
#BG_COLOR=#111111
#HLFG_COLOR=#111111
#HLBG_COLOR=#bbbbbb
#BORDER_COLOR=#222222
ROFI_TEXT=⏻
ROFI_OPTIONS=-width 11 -location 0 -hide-scrollbar -bw 2
#ZENITY_TITLE=Menu
#ZENITY_TEXT=Action:
#ZENITY_OPTIONS=--column= --hide-header
#ENABLE_CONFIRMATIONS=true (must be true or false)
#LAUNCHER=rofi #(must be rofi or zenity)
LOCKSCRIPT=betterlockscreen -u "/home/arco/Wallpapers/platform.jpg" -l
background=#d79921
color=#282828

155
scripts/arch-update Executable file
View File

@ -0,0 +1,155 @@
#!/usr/bin/env python3
#
# Copyright (C) 2017 Marcel Patzwahl
# Licensed under the terms of the GNU GPL v3 only.
#
# i3blocks blocklet script to see the available updates of pacman and the AUR
import subprocess
from subprocess import check_output
import argparse
import os
import re
def create_argparse():
def _default(name, default='', arg_type=str):
val = default
if name in os.environ:
val = os.environ[name]
return arg_type(val)
strbool = lambda s: s.lower() in ['t', 'true', '1']
strlist = lambda s: s.split()
parser = argparse.ArgumentParser(description='Check for pacman updates')
parser.add_argument(
'-b',
'--base_color',
default = _default('BASE_COLOR', 'green'),
help='base color of the output(default=green)'
)
parser.add_argument(
'-u',
'--updates_available_color',
default = _default('UPDATE_COLOR', 'yellow'),
help='color of the output, when updates are available(default=yellow)'
)
parser.add_argument(
'-a',
'--aur',
action = 'store_const',
const = True,
default = _default('AUR', 'False', strbool),
help='Include AUR packages. Attn: Yaourt must be installed'
)
parser.add_argument(
'-y',
'--aur_yay',
action = 'store_const',
const = True,
default = _default('AUR_YAY', 'False', strbool),
help='Include AUR packages. Attn: Yay must be installed'
)
parser.add_argument(
'-q',
'--quiet',
action = 'store_const',
const = True,
default = _default('QUIET', 'False', strbool),
help = 'Do not produce output when system is up to date'
)
parser.add_argument(
'-w',
'--watch',
nargs='*',
default = _default('WATCH', arg_type=strlist),
help='Explicitly watch for specified packages. '
'Listed elements are treated as regular expressions for matching.'
)
return parser.parse_args()
def get_updates():
output = ''
try:
output = check_output(['checkupdates']).decode('utf-8')
except subprocess.CalledProcessError as exc:
# checkupdates exits with 2 and no output if no updates are available.
# we ignore this case and go on
if not (exc.returncode == 2 and not exc.output):
raise exc
if not output:
return []
updates = [line.split(' ')[0]
for line in output.split('\n')
if line]
return updates
def get_aur_yaourt_updates():
output = ''
try:
output = check_output(['yaourt', '-Qua']).decode('utf-8')
except subprocess.CalledProcessError as exc:
# yaourt exits with 1 and no output if no updates are available.
# we ignore this case and go on
if not (exc.returncode == 1 and not exc.output):
raise exc
if not output:
return []
aur_updates = [line.split(' ')[0]
for line in output.split('\n')
if line.startswith('aur/')]
return aur_updates
def get_aur_yay_updates():
output = check_output(['yay', '-Qua']).decode('utf-8')
if not output:
return []
aur_updates = [line.split(' ')[0] for line in output.split('\n') if line]
return aur_updates
def matching_updates(updates, watch_list):
matches = set()
for u in updates:
for w in watch_list:
if re.match(w, u):
matches.add(u)
return matches
label = os.environ.get("LABEL","")
message = "{0}<span color='{1}'>{2}</span>"
args = create_argparse()
updates = get_updates()
if args.aur:
updates += get_aur_yaourt_updates()
elif args.aur_yay:
updates += get_aur_yay_updates()
update_count = len(updates)
if update_count > 0:
if update_count == 1:
info = str(update_count) + ' update available'
short_info = str(update_count) + ' update'
else:
info = str(update_count) + ' updates available'
short_info = str(update_count) + ' updates'
matches = matching_updates(updates, args.watch)
if matches:
info += ' [{0}]'.format(', '.join(matches))
short_info += '*'
print(message.format(label, args.updates_available_color, info))
print(message.format(label, args.updates_available_color, short_info))
elif not args.quiet:
print(message.format(label, args.base_color, 'system up to date'))

137
scripts/batterybar Executable file
View File

@ -0,0 +1,137 @@
#!/usr/bin/env bash
# batterybar; displays battery percentage as a bar on i3blocks
#
# Copyright 2015 Keftaa <adnan.37h@gmail.com>
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
readarray -t output <<< $(acpi battery)
battery_count=${#output[@]}
for line in "${output[@]}";
do
percentages+=($(echo "$line" | grep -o -m1 '[0-9]\{1,3\}%' | tr -d '%'))
statuses+=($(echo "$line" | egrep -o -m1 'Discharging|Charging|AC|Full|Unknown'))
remaining=$(echo "$line" | egrep -o -m1 '[0-9][0-9]:[0-9][0-9]')
if [[ -n $remaining ]]; then
remainings+=(" ($remaining)")
else
remainings+=("")
fi
done
squares="■"
#There are 8 colors that reflect the current battery percentage when
#discharging
dis_colors=("${C1:-#FF0027}" "${C2:-#FF3B05}" "${C3:-#FFB923}"
"${C4:-#FFD000}" "${C5:-#E4FF00}" "${C6:-#ADFF00}"
"${C7:-#6DFF00}" "${C8:-#10BA00}")
charging_color="${CHARGING_COLOR:-#00AFE3}"
full_color="${FULL_COLOR:-#FFFFFF}"
ac_color="${AC_COLOR:-#535353}"
while getopts 1:2:3:4:5:6:7:8:c:f:a:h opt; do
case "$opt" in
1) dis_colors[0]="$OPTARG";;
2) dis_colors[1]="$OPTARG";;
3) dis_colors[2]="$OPTARG";;
4) dis_colors[3]="$OPTARG";;
5) dis_colors[4]="$OPTARG";;
6) dis_colors[5]="$OPTARG";;
7) dis_colors[6]="$OPTARG";;
8) dis_colors[7]="$OPTARG";;
c) charging_color="$OPTARG";;
f) full_color="$OPTARG";;
a) ac_color="$OPTARG";;
h) printf "Usage: batterybar [OPTION] color
When discharging, there are 8 [1-8] levels colors.
You can specify custom colors, for example:
batterybar -1 red -2 \"#F6F6F6\" -8 green
You can also specify the colors for the charging, AC and
charged states:
batterybar -c green -f white -a \"#EEEEEE\"\n";
exit 0;
esac
done
end=$(($battery_count - 1))
for i in $(seq 0 $end);
do
if (( percentages[$i] > 0 && percentages[$i] < 20 )); then
squares="■"
elif (( percentages[$i] >= 20 && percentages[$i] < 40 )); then
squares="■■"
elif (( percentages[$i] >= 40 && percentages[$i] < 60 )); then
squares="■■■"
elif (( percentages[$i] >= 60 && percentages[$i] < 80 )); then
squares="■■■■"
elif (( percentages[$i] >=80 )); then
squares="■■■■■"
fi
if [[ "${statuses[$i]}" = "Unknown" ]]; then
squares="<sup>?</sup>$squares"
fi
case "${statuses[$i]}" in
"Charging")
color="$charging_color"
;;
"Full")
color="$full_color"
;;
"AC")
color="$ac_color"
;;
"Discharging"|"Unknown")
if (( percentages[$i] >= 0 && percentages[$i] < 10 )); then
color="${dis_colors[0]}"
elif (( percentages[$i] >= 10 && percentages[$i] < 20 )); then
color="${dis_colors[1]}"
elif (( percentages[$i] >= 20 && percentages[$i] < 30 )); then
color="${dis_colors[2]}"
elif (( percentages[$i] >= 30 && percentages[$i] < 40 )); then
color="${dis_colors[3]}"
elif (( percentages[$i] >= 40 && percentages[$i] < 60 )); then
color="${dis_colors[4]}"
elif (( percentages[$i] >= 60 && percentages[$i] < 70 )); then
color="${dis_colors[5]}"
elif (( percentages[$i] >= 70 && percentages[$i] < 80 )); then
color="${dis_colors[6]}"
elif (( percentages[$i] >= 80 )); then
color="${dis_colors[7]}"
fi
;;
esac
# Print Battery number if there is more than one
if (( $end > 0 )) ; then
message="$message $(($i + 1)):"
fi
if [[ "$BLOCK_BUTTON" -eq 1 ]]; then
message="$message ${statuses[$i]} <span foreground=\"$color\">${percentages[$i]}%${remainings[i]}</span>"
fi
message="$message <span foreground=\"$color\">$squares</span>"
done
echo $message

48
scripts/disk Executable file
View File

@ -0,0 +1,48 @@
#!/usr/bin/env sh
# Copyright (C) 2014 Julien Bonjean <julien@bonjean.info>
# 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 <http://www.gnu.org/licenses/>.
DIR="${DIR:-$BLOCK_INSTANCE}"
DIR="${DIR:-$HOME}"
ALERT_LOW="${ALERT_LOW:-$1}"
ALERT_LOW="${ALERT_LOW:-10}" # color will turn red under this value (default: 10%)
LOCAL_FLAG="-l"
if [ "$1" = "-n" ] || [ "$2" = "-n" ]; then
LOCAL_FLAG=""
fi
df -h -P $LOCAL_FLAG "$DIR" | awk -v label="$LABEL" -v alert_low=$ALERT_LOW '
/\/.*/ {
# full text
print label $4
# short text
print label $4
use=$5
# no need to continue parsing
exit 0
}
END {
gsub(/%$/,"",use)
if (100 - use < alert_low) {
# color
print "#FF0000"
}
}
'

40
scripts/dunst Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
"""
A do-not-disturb button for muting Dunst notifications in i3 using i3blocks
Mute is handled using the `dunstctl` command.
"""
__author__ = "Jessey White-Cinis <j@cin.is>"
__copyright__ = "Copyright (c) 2019 Jessey White-Cinis"
__license__ = "MIT"
__version__ = "1.1.0"
import os
import subprocess as sp
import json
def mute_toggle():
'''Toggle dunst notifications'''
sp.run(["dunstctl", "set-paused", "toggle"], check=True)
def clicked():
'''Returns True if the button was clicked'''
button = os.environ.get("BLOCK_BUTTON", None)
return bool(button)
def muted():
'''Returns True if Dunst is muted'''
output = sp.check_output(('dunstctl', 'is-paused'))
return u'true' == output.strip().decode("UTF-8")
if clicked():
# toggle button click to turn mute on and off
mute_toggle()
if muted():
RTN = {"full_text":"<span font='Font Awesome 5 Free Solid' color='#BE616E'>\uf1f6</span>"}
else:
RTN = {"full_text":"<span font='Font Awesome 5 Free Solid' color='#A4B98E'>\uf0f3</span>"}
print(json.dumps(RTN))

159
scripts/mediaplayer Executable file
View File

@ -0,0 +1,159 @@
#!/usr/bin/env perl
# Copyright (C) 2014 Tony Crisci <tony@dubstepdish.com>
# Copyright (C) 2015 Thiago Perrotta <perrotta dot thiago at poli dot ufrj dot br>
# 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 <http://www.gnu.org/licenses/>.
# For all media players except mpd/cmus/rhythmbox, MPRIS support should be
# enabled and the playerctl binary should be in your path.
# 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). If instance is empty, playerctl will connect to the first
# supported media player it finds.
use Time::HiRes qw(usleep);
use Env qw(BLOCK_INSTANCE);
use constant DELAY => 50; # Delay in ms to let network-based players (spotify) reflect new data.
use constant SPOTIFY_STR => 'spotify';
my @metadata = ();
my $player_arg = "";
if ($BLOCK_INSTANCE) {
$player_arg = "--player='$BLOCK_INSTANCE'";
}
sub buttons {
my $method = shift;
if($method eq 'mpd') {
if ($ENV{'BLOCK_BUTTON'} == 1) {
system("mpc prev &>/dev/null");
} elsif ($ENV{'BLOCK_BUTTON'} == 2) {
system("mpc toggle &>/dev/null");
} elsif ($ENV{'BLOCK_BUTTON'} == 3) {
system("mpc next &>/dev/null");
} elsif ($ENV{'BLOCK_BUTTON'} == 4) {
system("mpc volume +10 &>/dev/null");
} elsif ($ENV{'BLOCK_BUTTON'} == 5) {
system("mpc volume -10 &>/dev/null");
}
} 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 'playerctl') {
if ($ENV{'BLOCK_BUTTON'} == 1) {
system("playerctl $player_arg previous");
usleep(DELAY * 1000) if $BLOCK_INSTANCE eq SPOTIFY_STR;
} elsif ($ENV{'BLOCK_BUTTON'} == 2) {
system("playerctl $player_arg play-pause");
} elsif ($ENV{'BLOCK_BUTTON'} == 3) {
system("playerctl $player_arg next");
usleep(DELAY * 1000) if $BLOCK_INSTANCE eq SPOTIFY_STR;
} elsif ($ENV{'BLOCK_BUTTON'} == 4) {
system("playerctl $player_arg volume 0.01+");
} elsif ($ENV{'BLOCK_BUTTON'} == 5) {
system("playerctl $player_arg volume 0.01-");
}
} 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");
}
}
}
sub cmus {
my @cmus = split /^/, qx(cmus-remote -Q);
if ($? == 0) {
foreach my $line (@cmus) {
my @data = split /\s/, $line;
if (shift @data eq 'tag') {
my $key = shift @data;
my $value = join ' ', @data;
@metadata[0] = $value if $key eq 'artist';
@metadata[1] = $value if $key eq 'title';
}
}
if (@metadata) {
buttons('cmus');
# metadata found so we are done
print(join ' - ', @metadata);
print("\n");
exit 0;
}
}
}
sub mpd {
my $data = qx(mpc current);
if (not $data eq '') {
buttons("mpd");
print($data);
exit 0;
}
}
sub playerctl {
buttons('playerctl');
my $artist = qx(playerctl $player_arg metadata artist 2>/dev/null);
chomp $artist;
# exit status will be nonzero when playerctl cannot find your player
exit(0) if $? || $artist eq '(null)';
push(@metadata, $artist) if $artist;
my $title = qx(playerctl $player_arg metadata title);
exit(0) if $? || $title eq '(null)';
push(@metadata, $title) if $title;
print(join(" - ", @metadata)) if @metadata;
}
sub rhythmbox {
buttons('rhythmbox');
my $data = qx(rhythmbox-client --print-playing --no-start);
print($data);
}
if ($player_arg =~ /mpd/) {
mpd;
}
elsif ($player_arg =~ /cmus/) {
cmus;
}
elsif ($player_arg =~ /rhythmbox/) {
rhythmbox;
}
else {
playerctl;
}
print("\n");

43
scripts/playerctl Executable file
View File

@ -0,0 +1,43 @@
#!/bin/bash
# Based on https://aur.archlinux.org/packages/playerctl/
INSTANCE="${BLOCK_INSTANCE}"
if [[ "${INSTANCE}" != "" ]]; then
ARGUMENTS="--player ${INSTANCE}"
ps -e | grep "${INSTANCE}" &> /dev/null
fi
if [ $? == 1 ]; then
exit 0
fi
ICON_PLAY="➤"
ICON_PAUSE="Ⅱ"
ICON_STOP="≠"
CUR_ICON=""
if [[ "${BLOCK_BUTTON}" -eq 1 ]]; then
$(playerctl ${ARGUMENTS} previous)
elif [[ "${BLOCK_BUTTON}" -eq 2 ]]; then
$(playerctl ${ARGUMENTS} play-pause)
elif [[ "${BLOCK_BUTTON}" -eq 3 ]]; then
$(playerctl ${ARGUMENTS} next)
fi
PLAYER_STATUS=$(playerctl ${ARGUMENTS} status)
INFO_TITLE=$(playerctl ${ARGUMENTS} metadata title)
INFO_ALBUM=$(playerctl ${ARGUMENTS} metadata album)
INFO_ARTIST=$(playerctl ${ARGUMENTS} metadata artist)
if [[ "${PLAYER_STATUS}" = "Paused" ]]; then
CUR_ICON="${ICON_PAUSE}"
elif [[ "${PLAYER_STATUS}" = "Playing" ]]; then
CUR_ICON="${ICON_PLAY}"
else
CUR_ICON="${ICON_STOP}"
fi
if [[ "${INFO_TITLE}" != "" ]] && [[ "${INFO_ARTIST}" != "" ]]; then
echo "${INFO_ARTIST} - ${INFO_TITLE} ${CUR_ICON}"
echo "${INFO_ARTIST} - ${INFO_TITLE} ${CUR_ICON}"
fi

186
scripts/shutdown_menu Executable file
View File

@ -0,0 +1,186 @@
#!/usr/bin/env bash
#
# Use rofi/zenity to change system runstate thanks to systemd.
#
# Note: this currently relies on associative array support in the shell.
#
# Inspired from i3pystatus wiki:
# https://github.com/enkore/i3pystatus/wiki/Shutdown-Menu
#
# Copyright 2015 Benjamin Chrétien <chretien at lirmm dot fr>
#
# 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 <http://www.gnu.org/licenses/>.
#######################################################################
# BEGIN CONFIG #
#######################################################################
# Use a custom lock script
#LOCKSCRIPT="i3lock-extra -m pixelize"
# Colors: FG (foreground), BG (background), HL (highlighted)
FG_COLOR="${FG_COLOR:-#bbbbbb}"
BG_COLOR="${BG_COLOR:-#111111}"
HLFG_COLOR="${HLFG_COLOR:-#111111}"
HLBG_COLOR="${HLBG_COLOR:-#bbbbbb}"
BORDER_COLOR="${BORDER_COLOR:-#222222}"
# Options not related to colors
ROFI_TEXT="${ROFI_TEXT:-Menu:}"
ROFI_OPTIONS=(${ROFI_OPTIONS:--theme-str 'window {width: 11%; border: 2;} listview {scrollbar: false;}' -location 3})
# Zenity options
ZENITY_TITLE="${ZENITY_TITLE:-Menu}"
ZENITY_TEXT="${ZENITY_TEXT:-Action:}"
ZENITY_OPTIONS=(${ZENITY_OPTIONS:---column= --hide-header})
#######################################################################
# END CONFIG #
#######################################################################
# Whether to ask for user's confirmation
enable_confirmation=${ENABLE_CONFIRMATIONS:-false}
# Preferred launcher if both are available
preferred_launcher="${LAUNCHER:-rofi}"
usage="$(basename "$0") [-h] [-c] [-p name] -- display a menu for shutdown, reboot, lock etc.
where:
-h show this help text
-c ask for user confirmation
-p preferred launcher (rofi or zenity)
This script depends on:
- systemd,
- i3,
- rofi or zenity."
# Check whether the user-defined launcher is valid
launcher_list=(rofi zenity)
function check_launcher() {
if [[ ! "${launcher_list[@]}" =~ (^|[[:space:]])"$1"($|[[:space:]]) ]]; then
echo "Supported launchers: ${launcher_list[*]}"
exit 1
else
# Get array with unique elements and preferred launcher first
# Note: uniq expects a sorted list, so we cannot use it
i=1
launcher_list=($(for l in "$1" "${launcher_list[@]}"; do printf "%i %s\n" "$i" "$l"; let i+=1; done \
| sort -uk2 | sort -nk1 | cut -d' ' -f2- | tr '\n' ' '))
fi
}
# Parse CLI arguments
while getopts "hcp:" option; do
case "${option}" in
h) echo "${usage}"
exit 0
;;
c) enable_confirmation=true
;;
p) preferred_launcher="${OPTARG}"
check_launcher "${preferred_launcher}"
;;
*) exit 1
;;
esac
done
check_launcher "${preferred_launcher}"
# Check whether a command exists
function command_exists() {
command -v "$1" &> /dev/null 2>&1
}
# systemctl required
if ! command_exists systemctl ; then
exit 1
fi
# menu defined as an associative array
typeset -A menu
# Menu with keys/commands
menu=(
[Shutdown]="systemctl poweroff"
[Reboot]="systemctl reboot"
[Hibernate]="systemctl hibernate"
[Suspend]="systemctl suspend"
[Halt]="systemctl halt"
[Lock]="${LOCKSCRIPT:-i3lock --color=${BG_COLOR#"#"}}"
[Logout]="i3-msg exit"
[Cancel]=""
)
menu_nrows=${#menu[@]}
# Menu entries that may trigger a confirmation message
menu_confirm="Shutdown Reboot Hibernate Suspend Halt Logout"
launcher_exe=""
launcher_options=""
rofi_colors=""
function prepare_launcher() {
if [[ "$1" == "rofi" ]]; then
rofi_colors=(-bc "${BORDER_COLOR}" -bg "${BG_COLOR}" -fg "${FG_COLOR}" \
-hlfg "${HLFG_COLOR}" -hlbg "${HLBG_COLOR}")
launcher_exe="rofi"
launcher_options=(-dmenu -i -lines "${menu_nrows}" -p "${ROFI_TEXT}" \
"${rofi_colors[@]}" "${ROFI_OPTIONS[@]}")
elif [[ "$1" == "zenity" ]]; then
launcher_exe="zenity"
launcher_options=(--list --title="${ZENITY_TITLE}" --text="${ZENITY_TEXT}" \
"${ZENITY_OPTIONS[@]}")
fi
}
for l in "${launcher_list[@]}"; do
if command_exists "${l}" ; then
prepare_launcher "${l}"
break
fi
done
# No launcher available
if [[ -z "${launcher_exe}" ]]; then
exit 1
fi
launcher=(${launcher_exe} "${launcher_options[@]}")
selection="$(printf '%s\n' "${!menu[@]}" | sort | "${launcher[@]}")"
function ask_confirmation() {
if [ "${launcher_exe}" == "rofi" ]; then
confirmed=$(echo -e "Yes\nNo" | rofi -dmenu -i -lines 2 -p "${selection}?" \
"${rofi_colors[@]}" "${ROFI_OPTIONS[@]}")
[ "${confirmed}" == "Yes" ] && confirmed=0
elif [ "${launcher_exe}" == "zenity" ]; then
zenity --question --text "Are you sure you want to ${selection,,}?"
confirmed=$?
fi
if [ "${confirmed}" == 0 ]; then
i3-msg -q "exec ${menu[${selection}]}"
fi
}
if [[ $? -eq 0 && ! -z ${selection} ]]; then
if [[ "${enable_confirmation}" = true && \
${menu_confirm} =~ (^|[[:space:]])"${selection}"($|[[:space:]]) ]]; then
ask_confirmation
else
i3-msg -q "exec ${menu[${selection}]}"
fi
fi

91
scripts/volume Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/env bash
# Copyright (C) 2014 Julien Bonjean <julien@bonjean.info>
# Copyright (C) 2014 Alexander Keller <github@nycroth.com>
# 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 <http://www.gnu.org/licenses/>.
#------------------------------------------------------------------------
# The second parameter overrides the mixer selection
# For PulseAudio users, eventually 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
if [[ -z "$MIXER" ]] ; then
MIXER="default"
if command -v pulseaudio >/dev/null 2>&1 && pulseaudio --check ; then
# pulseaudio is running, but not all installations use "pulse"
if amixer -D pulse info >/dev/null 2>&1 ; then
MIXER="pulse"
fi
fi
[ -n "$(lsmod | grep 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`
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)
if [[ -z "$STEP" ]] ; then
STEP="${1:-5%}"
fi
# AMIXER(1):
# "Use the mapped volume for evaluating the percentage representation like alsamixer, to be
# more natural for human ear."
NATURAL_MAPPING=${NATURAL_MAPPING:-0}
if [[ "$NATURAL_MAPPING" != "0" ]] ; then
AMIXER_PARAMS="-M"
fi
#------------------------------------------------------------------------
capability() { # Return "Capture" if the device is a capture device
amixer $AMIXER_PARAMS -D $MIXER get $SCONTROL |
sed -n "s/ Capabilities:.*cvolume.*/Capture/p"
}
volume() {
amixer $AMIXER_PARAMS -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}'
output=$(perl -ne "$perl_filter")
echo "$LABEL$output"
}
#------------------------------------------------------------------------
case $BLOCK_BUTTON in
3) amixer $AMIXER_PARAMS -q -D $MIXER sset $SCONTROL $(capability) toggle ;; # right click, mute/unmute
4) amixer $AMIXER_PARAMS -q -D $MIXER sset $SCONTROL $(capability) ${STEP}+ unmute ;; # scroll up, increase
5) amixer $AMIXER_PARAMS -q -D $MIXER sset $SCONTROL $(capability) ${STEP}- unmute ;; # scroll down, decrease
esac
volume | format

172
scripts/volume-pipewire Executable file
View File

@ -0,0 +1,172 @@
#!/bin/bash
# Displays the default device, volume, and mute status for i3blocks
set -a
AUDIO_HIGH_SYMBOL=${AUDIO_HIGH_SYMBOL:-' '}
AUDIO_MED_THRESH=${AUDIO_MED_THRESH:-50}
AUDIO_MED_SYMBOL=${AUDIO_MED_SYMBOL:-' '}
AUDIO_LOW_THRESH=${AUDIO_LOW_THRESH:-0}
AUDIO_LOW_SYMBOL=${AUDIO_LOW_SYMBOL:-' '}
AUDIO_MUTED_SYMBOL=${AUDIO_MUTED_SYMBOL:-' '}
AUDIO_DELTA=${AUDIO_DELTA:-5}
DEFAULT_COLOR=${DEFAULT_COLOR:-"#ffffff"}
MUTED_COLOR=${MUTED_COLOR:-"#a0a0a0"}
LONG_FORMAT=${LONG_FORMAT:-'${SYMB} ${VOL}% [${INDEX}:${NAME}]'}
SHORT_FORMAT=${SHORT_FORMAT:-'${SYMB} ${VOL}% [${INDEX}]'}
USE_ALSA_NAME=${USE_ALSA_NAME:-0}
USE_DESCRIPTION=${USE_DESCRIPTION:-0}
SUBSCRIBE=${SUBSCRIBE:-0}
MIXER=${MIXER:-""}
SCONTROL=${SCONTROL:-""}
while getopts F:Sf:adH:M:L:X:T:t:C:c:i:m:s:h opt; do
case "$opt" in
S) SUBSCRIBE=1 ;;
F) LONG_FORMAT="$OPTARG" ;;
f) SHORT_FORMAT="$OPTARG" ;;
a) USE_ALSA_NAME=1 ;;
d) USE_DESCRIPTION=1 ;;
H) AUDIO_HIGH_SYMBOL="$OPTARG" ;;
M) AUDIO_MED_SYMBOL="$OPTARG" ;;
L) AUDIO_LOW_SYMBOL="$OPTARG" ;;
X) AUDIO_MUTED_SYMBOL="$OPTARG" ;;
T) AUDIO_MED_THRESH="$OPTARG" ;;
t) AUDIO_LOW_THRESH="$OPTARG" ;;
C) DEFAULT_COLOR="$OPTARG" ;;
c) MUTED_COLOR="$OPTARG" ;;
i) AUDIO_INTERVAL="$OPTARG" ;;
m) MIXER="$OPTARG" ;;
s) SCONTROL="$OPTARG" ;;
h) printf \
"Usage: volume-pulseaudio [-S] [-F format] [-f format] [-p] [-a|-d] [-H symb] [-M symb]
[-L symb] [-X symb] [-T thresh] [-t thresh] [-C color] [-c color] [-i inter]
[-m mixer] [-s scontrol] [-h]
Options:
-F, -f\tOutput format (-F long format, -f short format) to use, with exposed variables:
\${SYMB}, \${VOL}, \${INDEX}, \${NAME}
-S\tSubscribe to volume events (requires persistent block, always uses long format)
-a\tUse ALSA name if possible
-d\tUse device description instead of name if possible
-H\tSymbol to use when audio level is high. Default: '$AUDIO_HIGH_SYMBOL'
-M\tSymbol to use when audio level is medium. Default: '$AUDIO_MED_SYMBOL'
-L\tSymbol to use when audio level is low. Default: '$AUDIO_LOW_SYMBOL'
-X\tSymbol to use when audio is muted. Default: '$AUDIO_MUTED_SYMBOL'
-T\tThreshold for medium audio level. Default: $AUDIO_MED_THRESH
-t\tThreshold for low audio level. Default: $AUDIO_LOW_THRESH
-C\tColor for non-muted audio. Default: $DEFAULT_COLOR
-c\tColor for muted audio. Default: $MUTED_COLOR
-i\tInterval size of volume increase/decrease. Default: $AUDIO_DELTA
-m\tUse the given mixer.
-s\tUse the given scontrol.
-h\tShow this help text
" && exit 0;;
esac
done
if [[ -z "$MIXER" ]] ; then
MIXER="default"
if amixer -D pulse info >/dev/null 2>&1 ; then
MIXER="pulse"
fi
fi
if [[ -z "$SCONTROL" ]] ; then
SCONTROL=$(amixer -D "$MIXER" scontrols | sed -n "s/Simple mixer control '\([^']*\)',0/\1/p" | head -n1)
fi
CAPABILITY=$(amixer -D $MIXER get $SCONTROL | sed -n "s/ Capabilities:.*cvolume.*/Capture/p")
function move_sinks_to_new_default {
DEFAULT_SINK=$1
pactl list sink-inputs | grep 'Sink Input #' | grep -o '[0-9]\+' | while read SINK
do
pactl move-sink-input $SINK $DEFAULT_SINK
done
}
function set_default_playback_device_next {
inc=${1:-1}
num_devices=$(pactl list sinks | grep -c Name:)
sink_arr=($(pactl list sinks | grep Name: | sed -r 's/\s+Name: (.+)/\1/'))
default_sink=$(pactl get-default-sink)
default_sink_index=$(for i in "${!sink_arr[@]}"; do if [[ "$default_sink" = "${sink_arr[$i]}" ]]; then echo "$i"; fi done)
default_sink_index=$(( ($default_sink_index + $num_devices + $inc) % $num_devices ))
default_sink=${sink_arr[$default_sink_index]}
pactl set-default-sink $default_sink
move_sinks_to_new_default $default_sink
}
case "$BLOCK_BUTTON" in
1) set_default_playback_device_next ;;
2) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY toggle ;;
3) set_default_playback_device_next -1 ;;
4) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY $AUDIO_DELTA%+ ;;
5) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY $AUDIO_DELTA%- ;;
esac
function print_format {
echo "$1" | envsubst '${SYMB}${VOL}${INDEX}${NAME}'
}
function print_block {
ACTIVE=$(pactl list sinks | grep "State\: RUNNING" -B4 -A55 | grep "Name:\|Volume: \(front-left\|mono\)\|Mute:\|api.alsa.pcm.card = \|node.nick = ")
for Name in NAME MUTED VOL INDEX NICK; do
read $Name
done < <(echo "$ACTIVE")
INDEX=$(echo "$INDEX" | grep -o '".*"' | sed 's/"//g')
VOL=$(echo "$VOL" | grep -o "[0-9]*%" | head -1 )
VOL="${VOL%?}"
NAME=$(echo "$NICK" | grep -o '".*"' | sed 's/"//g')
if [[ $USE_ALSA_NAME == 1 ]] ; then
ALSA_NAME=$(pactl list sinks |\
awk '/^\s*\*/{f=1}/^\s*index:/{f=0}f' |\
grep "alsa.name\|alsa.mixer_name" |\
head -n1 |\
sed 's/.*= "\(.*\)".*/\1/')
NAME=${ALSA_NAME:-$NAME}
elif [[ $USE_DESCRIPTION == 1 ]] ; then
DESCRIPTION=$(pactl list sinks | grep "State\: RUNNING" -B4 -A55 | grep 'Description: ' | sed 's/^.*: //')
NAME=${DESCRIPTION:-$NAME}
fi
if [[ $MUTED =~ "no" ]] ; then
SYMB=$AUDIO_HIGH_SYMBOL
[[ $VOL -le $AUDIO_MED_THRESH ]] && SYMB=$AUDIO_MED_SYMBOL
[[ $VOL -le $AUDIO_LOW_THRESH ]] && SYMB=$AUDIO_LOW_SYMBOL
COLOR=$DEFAULT_COLOR
else
SYMB=$AUDIO_MUTED_SYMBOL
COLOR=$MUTED_COLOR
fi
if [[ $ACTIVE = "" ]] ; then
echo "Sound inactive"
COLOR='#222225'
fi
if [[ $SUBSCRIBE == 1 ]] ; then
print_format "$LONG_FORMAT"
else
print_format "$LONG_FORMAT"
print_format "$SHORT_FORMAT"
echo "$COLOR"
fi
}
print_block
if [[ $SUBSCRIBE == 1 ]] ; then
while read -r EVENT; do
print_block
done < <(pactl subscribe | stdbuf -oL grep change)
fi