From 39788a2641418bf80f48c1803caf72c0eafe123e Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 8 Dec 2019 00:35:41 -0500 Subject: [PATCH 001/110] Initial Commit --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 From e80233dd04c114a5b00bdd647b6b133367db0cf9 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 11 Sep 2020 11:00:39 -0400 Subject: [PATCH 002/110] Intial commit of all current scripts --- .gitignore | 3 + apply-gruvbox.sh | 755 ++++++++++++++++++++++++++++++++++++++ audio/mute.sh | 3 + audio/noise-cancel.sh | 11 + gammastep.pl | 40 ++ i3/detached.sh | 3 + i3/home.sh | 3 + i3/i3move.sh | 28 ++ i3/work.sh | 3 + rofi/drun.sh | 10 + rofi/rofi-openvpn.sh | 29 ++ rofi/rofi-power-menu.sh | 42 +++ rofi/rofi-send-to-kodi.sh | 5 + rofi/rofi-ssh-menu.sh | 28 ++ rofi/sway-alt-tab.sh | 18 + send-to-kodi.sh | 104 ++++++ sway/displays.pl | 308 ++++++++++++++++ sway/gammastep.pl | 42 +++ sway/popup-term.pl | 75 ++++ sway/swayidle.sh | 32 ++ sway/swayidlecountdown.sh | 5 + waybar/waybar-cpu.sh | 7 + waybar/waybar-disk.sh | 3 + waybar/waybar-exec.sh | 6 + waybar/waybar-mem.sh | 3 + waybar/waybar-nmtui.sh | 9 + waybar/waybar-pa.sh | 0 27 files changed, 1575 insertions(+) create mode 100644 .gitignore create mode 100644 apply-gruvbox.sh create mode 100644 audio/mute.sh create mode 100755 audio/noise-cancel.sh create mode 100755 gammastep.pl create mode 100755 i3/detached.sh create mode 100755 i3/home.sh create mode 100755 i3/i3move.sh create mode 100755 i3/work.sh create mode 100755 rofi/drun.sh create mode 100755 rofi/rofi-openvpn.sh create mode 100755 rofi/rofi-power-menu.sh create mode 100755 rofi/rofi-send-to-kodi.sh create mode 100755 rofi/rofi-ssh-menu.sh create mode 100755 rofi/sway-alt-tab.sh create mode 100755 send-to-kodi.sh create mode 100755 sway/displays.pl create mode 100755 sway/gammastep.pl create mode 100755 sway/popup-term.pl create mode 100755 sway/swayidle.sh create mode 100755 sway/swayidlecountdown.sh create mode 100755 waybar/waybar-cpu.sh create mode 100755 waybar/waybar-disk.sh create mode 100644 waybar/waybar-exec.sh create mode 100755 waybar/waybar-mem.sh create mode 100755 waybar/waybar-nmtui.sh create mode 100644 waybar/waybar-pa.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31e27cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +sshs +# Just backups of Papillon scripts that don't have their own repo yet +data diff --git a/apply-gruvbox.sh b/apply-gruvbox.sh new file mode 100644 index 0000000..6eda344 --- /dev/null +++ b/apply-gruvbox.sh @@ -0,0 +1,755 @@ +#!/usr/bin/env bash + +# Single theme copy of apply-colors.sh from: https://raw.githubusercontent.com/Mayccoll/Gogh + +# ====================CONFIG THIS =============================== # +export COLOR_01="#282828" # HOST +export COLOR_02="#cc241d" # SYNTAX_STRING +export COLOR_03="#98971a" # SYNTAX_STRING +export COLOR_04="#d79921" # COMMAND +export COLOR_05="#458588" # COMMAND_COLOR2 +export COLOR_06="#b16286" # PATH +export COLOR_07="#68986a" # SYNTAX_VAR +export COLOR_08="#a89984" # PROMP + +export COLOR_09="#928374" # +export COLOR_10="#fb4934" # +export COLOR_11="#b8bb26" # COMMAND_ERROR +export COLOR_12="#fabd2f" # EXEC +export COLOR_13="#83a598" # +export COLOR_14="#d3869b" # FOLDER +export COLOR_15="#8ec07c" # +export COLOR_16="#ebdbb2" # + +export BACKGROUND_COLOR="#1d2021" # Background Color +export FOREGROUND_COLOR="#ebdbb2" # Text +export CURSOR_COLOR="$FOREGROUND_COLOR" # Cursor +export PROFILE_NAME="Gruvbox" + +# | =========================================== +# | Early pre-requisites check +# | =========================================== +UUIDGEN="${UUIDGEN:-$(command -v uuidgen | xargs echo)}" +DCONF="${DCONF:-$(command -v dconf | xargs echo)}" +GCONF="${GCONF:-$(command -v gconftool-2 | xargs echo)}" +GS="${GS:-$(command -v gsettings | xargs echo)}" +# Note: xargs echo is to make the command sucessful even if it was not +# otherwise the script will exit if the command does not exist (elementary os) + +# | =========================================== +# | Make sure all exported variables get unset no matter what +# | Defining this in this script because it gets called even if +# | gogh.sh was not called. Exported variables in gogh.sh gets +# | handled there in case there was en error before this script was called +# | ============================================ +GLOBAL_VAR_CLEANUP() { + unset PROFILE_NAME + unset PROFILE_SLUG + unset scratchdir + unset TILIX_RES + unset TERMINAL + unset LOOP + unset OPTLENGTH + + for c in $(seq -s " " -w 16); do + unset DEMO_COLOR_${c} + unset COLOR_${c} + done + + unset BACKGROUND_COLOR + unset FOREGROUND_COLOR + unset CURSOR_COLOR + unset HIGHLIGHT_FG_COLOR + unset HIGHLIGHT_BG_COLOR + unset USE_SYS_TRANSPARENCY + unset PROFILE_NAME +} + +# Note: Since all scripts gets invoked in a subshell the traps from the parent shell +# will not get inherited. Hence traps defined in gogh.sh and print-themes.sh will still trigger +trap 'GLOBAL_VAR_CLEANUP; trap - EXIT' EXIT HUP INT QUIT PIPE TERM + +# | =========================================== +# | Second test for TERMINAL in case user ran +# | theme script directly instead of gogh.sh +# | ============================================ +if [[ -z "${TERMINAL:-}" ]]; then + + # | =========================================== + # | Check for the terminal name (depening on os) + # | =========================================== + OS="$(uname)" + if [[ "$OS" = "Darwin" ]]; then + TERMINAL=$TERM_PROGRAM + elif [[ "${OS#CYGWIN}" != "${OS}" ]]; then + TERMINAL="mintty" + else + # | =========================================== + # | Depending on how the script was invoked, we need + # | to loop until pid is no longer a subshell + # | =========================================== + pid="$$" + TERMINAL="$(ps -h -o comm -p $pid)" + while [[ "${TERMINAL:(-2)}" == "sh" ]]; do + pid="$(ps -h -o ppid -p $pid)" + TERMINAL="$(ps -h -o comm -p $pid)" + done + fi +fi + + +case "${TERMINAL}" in + pantheon-terminal|io.elementary.t* ) + if [[ -z "${GS}" ]]; then + printf '\n%s\n' "Error gsettings not found" + printf '%s\n' "sudo apt install dconf?" + printf '%s\n\n' "or export GS=/path/to/gsettings" + exit 1 + fi + ;; + + mintty ) + CFGFILE="${HOME}/.minttyrc" + if [[ ! -f "${CFGFILE}" ]]; then + printf '\n%s\n' "Warning: Couldn't find an existing configuration file, so one will be created for you." + printf '%s\n\n' "Warning: Are you really running Cygwin's mintty?" + touch "${CFGFILE}" + fi + ;; + + guake|tilix|mate-terminal|gnome-terminal* ) + case "${TERMINAL}" in + guake|gnome-terminal* ) + if [[ -z "${DCONF}" ]] && [[ -z "${GCONF}" ]]; then + printf '\n%s\n' "Error gconftool not found!" + printf '%s\n' "sudo apt install gconftool?" + printf '%s\n\n' "or export GCONF=/path/to/gconftool-2/" + exit 1 + fi + ;; + esac + if [[ -z "${DCONF}" ]]; then + printf '\n%s\n' "Error dconf not found" + printf '%s\n' "sudo apt install dconf?" + printf '%s\n\n' "or export DCONF=/path/to/dconf" + exit 1 + fi + ;; + +esac + +# | =========================================== +# | Convert RGB to gnome colors +# | =========================================== +gnome_color () { + + AA=${1:1:2} + BB=${1:3:2} + CC=${1:5:2} + + echo "#${AA}${AA}${BB}${BB}${CC}${CC}" +} + +hexToDec () { + echo "$((16#${1}))" +} + +hexRGBtoDecRGB () { + R="$(hexToDec "${1:1:2}")" + G="$(hexToDec "${1:3:2}")" + B="$(hexToDec "${1:5:2}")" + + echo "${R}" "${G}" "${B}" +} + +convertRGBtoMac () { + local color="${1}" + set -- + set -- $(hexRGBtoDecRGB "${color}") + R=${1}; shift; G=${1}; shift; B=${1}; shift + + R=$(echo "${R} / 255" | bc -l) + G=$(echo "${G} / 255" | bc -l) + B=$(echo "${B} / 255" | bc -l) + + echo "${R}" "${G}" "${B}" +} + +createMinttyEntry () { + local name="${1}" + local color="${2}" + set -- + set -- $(hexRGBtoDecRGB "${color}") + R=${1}; shift; G=${1}; shift; B=${1}; shift + + echo "${name}=${R},${G},${B}" +} + +updateMinttyConfig () { + local config="${1}" + local color="${2}" + local name="${3}" + + sed -i -r -e "s/^${name}=.+/$(createMinttyEntry "${name}" "${color}")/g" "${config}" +} + +convertNameAndRGBtoITerm() { + local name="${1}" + local color="${2}" + set -- + set -- $(convertRGBtoMac "${color}") + R=${1}; shift; G=${1}; shift; B=${1}; shift + + echo "${name}Blue Component${B}Green Component${G}Red Component${R}" +} + +dset() { + local key="${1}"; shift + local val="${1}" + + "${DCONF}" write "${PROFILE_KEY}/${key}" "${val}" +} + +# Because dconf still doesn't have "append" +dlist_append() { + local key="${1}"; shift + local val="${1}"; shift + local entries + + entries="$( + { + "${DCONF}" read "${key}" | tr -d "[]" | tr , "\n" | grep -F -v "${val}" + echo "'${val}'" + } | head -c-1 | tr "\n" , + )" + + "${DCONF}" write "${key}" "[${entries}]" +} + +gcset() { + local type="${1}"; shift + local key="${1}"; shift + local val="${1}" + + "${GCONF}" --set --type "${type}" "${PROFILE_KEY}/${key}" -- "${val}" +} + +# Because gconftool doesn't have "append" +glist_append() { + local type="${1}"; shift + local key="${1}"; shift + local val="${1}"; shift + local entries + + entries="$( + { + "${GCONF}" --get "${key}" | tr -d "[]" | tr , "\n" | grep -F -v "${val}" + echo "${val}" + } | head -c-1 | tr "\n" , + )" + + "${GCONF}" --set --type list --list-type "${type}" "${key}" "[${entries}]" +} + +gset() { + local key="${1}"; shift + local val="${1}" + + "${GS}" set "${PROFILE_KEY}" "${key}" "${val}" +} + +set_theme() { + dset visible-name "'${PROFILE_NAME}'" + dset background-color "'${BACKGROUND_COLOR}'" + dset foreground-color "'${FOREGROUND_COLOR}'" + + if [[ -n "${HIGHLIGHT_BG_COLOR:-}" ]]; then + dset highlight-colors-set "true" + dset highlight-background-color "'${HIGHLIGHT_BG_COLOR}'" + if [[ -n "${HIGHLIGHT_FG_COLOR:-}" ]]; then + dset highlight-foreground-color "'${HIGHLIGHT_FG_COLOR}'" + fi + fi + + if [[ -n "${BOLD_COLOR:-}" ]]; then + dset bold-color "'${BOLD_COLOR}'" + dset bold-color-same-as-fg "false" + else + dset bold-color "'${FOREGROUND_COLOR}'" + dset bold-color-same-as-fg "true" + fi + dset use-theme-colors "false" + dset use-theme-background "false" + dset use-theme-transparency "${USE_SYS_TRANSPARENCY:-false}" +} + +legacy_set_theme() { + gcset string visible_name "${PROFILE_NAME}" + gcset string background_color "${BACKGROUND_COLOR}" + gcset string foreground_color "${FOREGROUND_COLOR}" + + if [[ -n "${BOLD_COLOR:-}" ]]; then + gcset string bold_color "${BOLD_COLOR}" + gcset bool bold_color_same_as_fg "false" + else + gcset string bold_color "${FOREGROUND_COLOR}" + gcset bool bold_color_same_as_fg "true" + fi + gcset bool use_theme_colors "false" + gcset bool use_theme_background "false" +} + +# | =========================================== +# | If terminal supports truecolor then we can show theme colors without applying the theme +# | =========================================== +if [[ "${COLORTERM:-}" == "truecolor" ]] || [[ "${COLORTERM:-}" == "24bit" ]]; then + # gogh_colors have been moved here to avoid multiple definitions + function gogh_colors () { + # Build up the color string to avoid visual rendering + local color_str + # Note: {01..16} does not work on OSX + for c in $(seq -s " " -w 16); do + local color="COLOR_$c" + set -- $(hexRGBtoDecRGB "${!color}") + color_str+="\033[38;2;${1};${2};${3}m█████$(tput sgr0)" + [[ ${GOGH_DRY_RUN:-0} -eq 1 ]] && export "DEMO_COLOR_$c=\033[38;2;${1};${2};${3}m" + [[ "$c" == "08" ]] && color_str+="\n" # new line + done + printf '\n%b\n\n\n' "${color_str}" + unset color_str + } +else + function gogh_colors () { + # Build up the color string to avoid visual rendering + local color_str + for c in {0..15}; do + color_str+="$(tput setaf $c)█████$(tput sgr0)" + [[ $c == 7 ]] && color_str+="\n" # new line + done + printf '\n%b\n\n' "${color_str}" + unset color_str + } +fi + +# | =========================================== +# | Print theme colors +# | =========================================== +gogh_colors +if [[ ${GOGH_DRY_RUN:-0} -eq 1 ]]; then + color + # End here if dry run was initiated + exit 0 +fi + + +apply_elementary() { + # | =========================================== + # | Applying values on elementary/pantheon terminal + # | =========================================== + gset background "${BACKGROUND_COLOR}" + gset foreground "${FOREGROUND_COLOR}" + gset cursor-color "${CURSOR_COLOR}" + gset palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" +} + +apply_cygwin() { + # | =========================================== + # | Applying values on mintty (cygwin) + # | =========================================== + + echo "Patching mintty configuration file (${CFGFILE}) with new colors..." + + updateMinttyConfig "$CFGFILE" "$COLOR_01" "Black" + updateMinttyConfig "$CFGFILE" "$COLOR_02" "Red" + updateMinttyConfig "$CFGFILE" "$COLOR_03" "Green" + updateMinttyConfig "$CFGFILE" "$COLOR_04" "Yellow" + updateMinttyConfig "$CFGFILE" "$COLOR_05" "Blue" + updateMinttyConfig "$CFGFILE" "$COLOR_06" "Magenta" + updateMinttyConfig "$CFGFILE" "$COLOR_07" "Cyan" + updateMinttyConfig "$CFGFILE" "$COLOR_08" "White" + + updateMinttyConfig "$CFGFILE" "$COLOR_09" "BoldBlack" + updateMinttyConfig "$CFGFILE" "$COLOR_10" "BoldRed" + updateMinttyConfig "$CFGFILE" "$COLOR_11" "BoldGreen" + updateMinttyConfig "$CFGFILE" "$COLOR_12" "BoldYellow" + updateMinttyConfig "$CFGFILE" "$COLOR_13" "BoldBlue" + updateMinttyConfig "$CFGFILE" "$COLOR_14" "BoldMagenta" + updateMinttyConfig "$CFGFILE" "$COLOR_15" "BoldCyan" + updateMinttyConfig "$CFGFILE" "$COLOR_16" "BoldWhite" + + updateMinttyConfig "$CFGFILE" "$BACKGROUND_COLOR" "Backgroundcolor" + updateMinttyConfig "$CFGFILE" "$FOREGROUND_COLOR" "Foregroundcolor" + updateMinttyConfig "$CFGFILE" "$CURSOR_COLOR" "Cursorcolor" + + echo "Done - please reopen your Cygwin terminal to see the changes" +} + +apply_darwin() { + # | =========================================== + # | Applying values on iTerm2 + # | =========================================== + + BACKGROUND_COLOR=$(convertNameAndRGBtoITerm "Background Color" "$BACKGROUND_COLOR") + FOREGROUND_COLOR=$(convertNameAndRGBtoITerm "Foreground Color" "$FOREGROUND_COLOR") + COLOR_01=$(convertNameAndRGBtoITerm "Ansi 0 Color" "$COLOR_01") + COLOR_02=$(convertNameAndRGBtoITerm "Ansi 1 Color" "$COLOR_02") + COLOR_03=$(convertNameAndRGBtoITerm "Ansi 2 Color" "$COLOR_03") + COLOR_04=$(convertNameAndRGBtoITerm "Ansi 3 Color" "$COLOR_04") + COLOR_05=$(convertNameAndRGBtoITerm "Ansi 4 Color" "$COLOR_05") + COLOR_06=$(convertNameAndRGBtoITerm "Ansi 5 Color" "$COLOR_06") + COLOR_07=$(convertNameAndRGBtoITerm "Ansi 6 Color" "$COLOR_07") + COLOR_08=$(convertNameAndRGBtoITerm "Ansi 7 Color" "$COLOR_08") + COLOR_09=$(convertNameAndRGBtoITerm "Ansi 8 Color" "$COLOR_09") + COLOR_10=$(convertNameAndRGBtoITerm "Ansi 9 Color" "$COLOR_10") + COLOR_11=$(convertNameAndRGBtoITerm "Ansi 10 Color" "$COLOR_11") + COLOR_12=$(convertNameAndRGBtoITerm "Ansi 11 Color" "$COLOR_12") + COLOR_13=$(convertNameAndRGBtoITerm "Ansi 12 Color" "$COLOR_13") + COLOR_14=$(convertNameAndRGBtoITerm "Ansi 13 Color" "$COLOR_14") + COLOR_15=$(convertNameAndRGBtoITerm "Ansi 14 Color" "$COLOR_15") + COLOR_16=$(convertNameAndRGBtoITerm "Ansi 15 Color" "$COLOR_16") + + # Assemble color scheme file contents + ITERMCOLORS=''${BACKGROUND_COLOR}${FOREGROUND_COLOR}${COLOR_01}${COLOR_02}${COLOR_03}${COLOR_04}${COLOR_05}${COLOR_06}${COLOR_07}${COLOR_08}${COLOR_09}${COLOR_10}${COLOR_11}${COLOR_12}${COLOR_13}${COLOR_14}${COLOR_15}'' + + # Dump iTerm color scheme to file and import it by opening it + echo "${ITERMCOLORS}" > "${PROFILE_NAME}.itermcolors" + open "${PROFILE_NAME}.itermcolors" + rm "${PROFILE_NAME}.itermcolors" +} + +apply_gtk() { + # | =========================================== + # | Applying values to gnome/mate/tilix + # | =========================================== + + local legacy="${1:-}" + + # This is to avoid doing the profile loop definition twice + if [[ -z "${legacy}" ]]; then + CONFTOOL="${DCONF} read" + VISIBLE_NAME="visible-name" + else + CONFTOOL="${GCONF} --get" + VISIBLE_NAME="visible_name" + fi + + # Check first wether profile already exists + profile_hashes=($(${CONFTOOL} "${PROFILE_LIST_KEY}" | tr "[]'," " ")) + for profile in "${profile_hashes[@]}"; do + if [[ "$(${CONFTOOL} "${BASE_DIR}${profile}/${VISIBLE_NAME}" | tr -d "'")" == "${PROFILE_NAME}" ]]; then + printf '%s\n' "Profile already exists" "Skipping..." + exit 0 + fi + done + + # Fallback if there is no default profile + set -- $(${CONFTOOL} ${PROFILE_LIST_KEY} | tr "[]'," " ") + : ${DEFAULT_SLUG:="$1"} + + : ${PROFILE_NAME:="Default"} + : ${PROFILE_SLUG:="Default"} + + DEFAULT_KEY="${BASE_DIR}${DEFAULT_SLUG:-}" + PROFILE_KEY="${BASE_DIR}${PROFILE_SLUG:-}" + + if [[ -z "${legacy}" ]]; then + if [[ -z "$(${DCONF} list ${BASE_DIR%:})" ]]; then + # Provide a user friendly error text if no saved profile exists, otherwise it will display "Error gconftool not found!" + # it could happen on a newly installed system. (happened on CentOS 7) + printf '%s\n' \ + "Error, no saved profiles found!" \ + "Possible fix, new a profile (Terminal > Edit > Preferences > Profiles > New, then Close) and try again." \ + "You can safely delete the created profile after the installation." + exit 1 + fi + + BACKGROUND_COLOR=$(gnome_color "$BACKGROUND_COLOR") + FOREGROUND_COLOR=$(gnome_color "$FOREGROUND_COLOR") + HIGHLIGHT_BG_COLOR=$(gnome_color "$HIGHLIGHT_BG_COLOR") + HIGHLIGHT_FG_COLOR=$(gnome_color "$HIGHLIGHT_FG_COLOR") + COLOR_01=$(gnome_color "$COLOR_01") + COLOR_02=$(gnome_color "$COLOR_02") + COLOR_03=$(gnome_color "$COLOR_03") + COLOR_04=$(gnome_color "$COLOR_04") + COLOR_05=$(gnome_color "$COLOR_05") + COLOR_06=$(gnome_color "$COLOR_06") + COLOR_07=$(gnome_color "$COLOR_07") + COLOR_08=$(gnome_color "$COLOR_08") + COLOR_09=$(gnome_color "$COLOR_09") + COLOR_10=$(gnome_color "$COLOR_10") + COLOR_11=$(gnome_color "$COLOR_11") + COLOR_12=$(gnome_color "$COLOR_12") + COLOR_13=$(gnome_color "$COLOR_13") + COLOR_14=$(gnome_color "$COLOR_14") + COLOR_15=$(gnome_color "$COLOR_15") + COLOR_16=$(gnome_color "$COLOR_16") + + # copy existing settings from default profile + $DCONF dump "${DEFAULT_KEY}/" | $DCONF load "${PROFILE_KEY}/" + + # add new copy to global list of profiles + dlist_append "${PROFILE_LIST_KEY}" "${PROFILE_SLUG#:}" + + set_theme + dset palette "${LEFT_WRAPPER:-}'${COLOR_01}${PALETTE_DELIM}${COLOR_02}${PALETTE_DELIM}${COLOR_03}${PALETTE_DELIM}${COLOR_04}${PALETTE_DELIM}${COLOR_05}${PALETTE_DELIM}${COLOR_06}${PALETTE_DELIM}${COLOR_07}${PALETTE_DELIM}${COLOR_08}${PALETTE_DELIM}${COLOR_09}${PALETTE_DELIM}${COLOR_10}${PALETTE_DELIM}${COLOR_11}${PALETTE_DELIM}${COLOR_12}${PALETTE_DELIM}${COLOR_13}${PALETTE_DELIM}${COLOR_14}${PALETTE_DELIM}${COLOR_15}${PALETTE_DELIM}${COLOR_16}'${RIGHT_WRAPPER:-}" + ${LEGACY_BOLD:-} && dset allow-bold "true" # mate + else + # Append the Base16 profile to the profile list + glist_append string "${PROFILE_LIST_KEY}" "${PROFILE_SLUG}" + + legacy_set_theme + gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" + ${LEGACY_BOLD:-} && gcset bool allow-bold "true" + fi +} + +apply_guake() { + # | =========================================== + # | Applying values to guake + # | =========================================== + + local legacy="${1:-}" + PROFILE_KEY="/apps/guake/style/font" + + if [[ -z "${legacy}" ]]; then + dset palette "'${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}:${FOREGROUND_COLOR}:${BACKGROUND_COLOR}'" + dset palette-name "'${PROFILE_NAME}'" + dset allow-bold 'true' + else + gcset string color "${FOREGROUND_COLOR}" + gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" + gcset string palette-name "${PROFILE_NAME}" + PROFILE_KEY="/apps/guake/style/background" + gcset string color "${BACKGROUND_COLOR}" + + fi +} + +appy_tilixschemes() { + # | =========================================== + # | Applying values to tilix colorschemes + # | =========================================== + + if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then + [[ -d "${HOME}/.config/tilix/schemes" ]] || mkdir -p "${HOME}/.config/tilix/schemes" + + TILIXCOLORS='{\n\t"name": "'${PROFILE_NAME}'",\n\t"comment": "Generated by Gogh",\n\t"foreground-color": "'${FOREGROUND_COLOR}'",\n\t"background-color":"'${BACKGROUND_COLOR}'",\n\t"cursor-background-color": "'${CURSOR_COLOR}'",\n\t"palette": [\n\t\t"'${COLOR_01}'",\n\t\t"'${COLOR_02}'",\n\t\t"'${COLOR_03}'",\n\t\t"'${COLOR_04}'",\n\t\t"'${COLOR_05}'",\n\t\t"'${COLOR_06}'",\n\t\t"'${COLOR_07}'",\n\t\t"'${COLOR_08}'",\n\t\t"'${COLOR_09}'",\n\t\t"'${COLOR_10}'",\n\t\t"'${COLOR_11}'",\n\t\t"'${COLOR_12}'",\n\t\t"'${COLOR_13}'",\n\t\t"'${COLOR_14}'",\n\t\t"'${COLOR_15}'",\n\t\t"'${COLOR_16}'"\n\t],\n\t"use-badge-color": false,\n\t"use-bold-color": false,\n\t"use-cursor-color": false,\n\t"use-highlight-color": false,\n\t"use-theme-colors": false\n}' + echo -e "${TILIXCOLORS}" > "${scratchdir}/${PROFILE_NAME}.json" + + # Note: Tilix does not store color scheme name in dconf + # so we have to update color palette for the current profile in order to switch to the new theme + # but only set the palette on the last loop to avoid a flashing terminal + if ((LOOP == OPTLENGTH)); then + cp -f ${scratchdir}/* "$HOME/.config/tilix/schemes/" + rm -rf "${scratchdir}" + read -r -p "All done - apply new theme? [y/N] " -n 1 TILIX_RES + if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then + PROFILE_KEY="${BASE_DIR}${DEFAULT_SLUG}" + PROFILE_NAME="$(${DCONF} read ${PROFILE_KEY}/visible-name | tr -d \')" + set_theme + dset palette "['${COLOR_01}', '${COLOR_02}', '${COLOR_03}', '${COLOR_04}', '${COLOR_05}', '${COLOR_06}', '${COLOR_07}', '${COLOR_08}', '${COLOR_09}', '${COLOR_10}', '${COLOR_11}', '${COLOR_12}', '${COLOR_13}', '${COLOR_14}', '${COLOR_15}', '${COLOR_16}']" + fi + fi + + unset PROFILE_NAME + unset PROFILE_SLUG + unset TILIXCOLORS + exit 0 + fi +} + +apply_xfce4-terminal() { + # XFCE4 terminal has no profiles, instead it uses color presets + SCHEMEDIR="${HOME}/.local/share/xfce4/terminal/colorschemes" + CONFFILE="${HOME}/.config/xfce4/terminal/terminalrc" + + if [[ ! (-w "${CONFFILE}") ]]; then + if [[ -r "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ]]; then + cp "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ${CONFFILE} + else + echo "ERROR: config file not present or not writable!" + exit 1 + fi + fi + + [[ -d "${SCHEMEDIR}" ]] || mkdir -p "${SCHEMEDIR}" + + F_NAME=${PROFILE_NAME// /-} + F_NAME=$(echo ${F_NAME} | tr -d ":()") + F_NAME=$(echo "${F_NAME}" | awk '{print tolower($0)}') + + FF_NAME="${SCHEMEDIR}/${F_NAME}.theme" + + touch "${FF_NAME}" + + L_COLORCURSOR="ColorCursor=${CURSOR_COLOR}" + L_COLORPALETTE="ColorPalette=${COLOR_01};${COLOR_02};${COLOR_03};${COLOR_04};${COLOR_05};${COLOR_06};${COLOR_07};${COLOR_08};${COLOR_09};${COLOR_10};${COLOR_11};${COLOR_12};${COLOR_13};${COLOR_14};${COLOR_15};${COLOR_16}" + + printf '%s\n' \ + "; Generated by Gogh" \ + "; https://mayccoll.github.io/Gogh" \ + "[Scheme]" \ + "Name=${PROFILE_NAME}" \ + "ColorForeground=${FOREGROUND_COLOR}" \ + "ColorBackground=${BACKGROUND_COLOR}" \ + "${L_COLORCURSOR}" \ + "${L_COLORPALETTE}" \ + "ColorCursorUseDefault=FALSE" > ${FF_NAME} + + # apply last theme in queue + # xfce4-terminal monitors its rc file and doesn't reference + # any of the themes in there. The color settings need to + # be written there directly. + if ((LOOP == OPTLENGTH)); then + read -r -p "All done - apply new theme? [y/N] " -n 1 XFCE4_APPLY_CURR_THEME + if [[ ${XFCE4_APPLY_CURR_THEME::1} =~ ^(y|Y)$ ]]; then + if grep -q "^ColorPalette=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorPalette=.*/${L_COLORPALETTE}/" "${CONFFILE}" + else + echo "${L_COLORPALETTE}" >> "${CONFFILE}" + fi + + if grep -q "^ColorCursor=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorCursor=.*/${L_COLORCURSOR}/" "${CONFFILE}" + else + echo "${L_COLORCURSOR}" >> "${CONFFILE}" + fi + + if grep -q "^ColorForeground=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorForeground=.*/ColorForeground=${FOREGROUND_COLOR}/" "${CONFFILE}" + else + echo "ColorForeground=${FOREGROUND_COLOR}" >> "${CONFFILE}" + fi + + if grep -q "^ColorBackground=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorBackground=.*/ColorBackground=${BACKGROUND_COLOR}/" "${CONFFILE}" + else + echo "ColorBackground=${BACKGROUND_COLOR}" >> "${CONFFILE}" + fi + + if grep -q "^ColorCursorUseDefault=FALSE" "${CONFFILE}"; then + true + else + echo "ColorCursorUseDefault=FALSE" >> "${CONFFILE}" + fi + fi + fi + + unset SCHEMEDIR + unset CONFFILE + unset PROFILE_NAME + unset F_NAME + unset FF_NAME + unset L_COLORCURSOR + unset L_COLORPALETTE + exit 0 +} + +[[ -n "${UUIDGEN}" ]] && PROFILE_SLUG="$(uuidgen)" + +case "${TERMINAL}" in + pantheon-terminal|io.elementary.t* ) + if [[ "${TERMINAL}" == "pantheon-terminal" ]]; then + PROFILE_KEY="org.pantheon.terminal.settings" + else + PROFILE_KEY="io.elementary.terminal.settings" + fi + apply_elementary + ;; + + iTerm.app ) + apply_darwin + ;; + + mintty ) + apply_cygwin + ;; + + guake ) + if [[ -n "$(${DCONF} list /apps/guake/style/)" ]]; then + apply_guake + else + apply_guake legacy + fi + ;; + + gnome-terminal* ) + if [[ -n "$(${DCONF} list /org/gnome/terminal/)" ]]; then + BASE_DIR="/org/gnome/terminal/legacy/profiles:/:" + PROFILE_LIST_KEY="${BASE_DIR%:}list" + PROFILE_SLUG="${PROFILE_SLUG}" + + # Note -- ${BASE_DIR%s} is a workaround to avoid doing additional conditional testing for existing profiles + # if terminal is set to gnome-terminal + : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR%:}default | tr -d \')"} + + LEFT_WRAPPER="[" + RIGHT_WRAPPER="]" + PALETTE_DELIM="', '" + + apply_gtk + else + BASE_DIR="/apps/gnome-terminal/profiles/" + PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile_list" + LEGACY_BOLD=true + + : ${DEFAULT_SLUG:="$(${GCONF} read ${BASE_DIR}default_profile)"} + + apply_gtk legacy + fi + ;; + + mate-terminal ) + BASE_DIR="/org/mate/terminal/profiles/" + PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile-list" + LEGACY_BOLD=true + + : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR/profiles/global}default-profile | tr -d \')"} + + PALETTE_DELIM=":" + + apply_gtk + ;; + + tilix ) + BASE_DIR="/com/gexperts/Tilix/profiles/" + PROFILE_LIST_KEY="${BASE_DIR}list" + + : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR}default | tr -d \')"} + + LEFT_WRAPPER="[" + RIGHT_WRAPPER="]" + PALETTE_DELIM="', '" + + appy_tilixschemes + apply_gtk + ;; + + xfce4-terminal ) + apply_xfce4-terminal + ;; + + * ) + printf '%s\n' \ + "Unsupported terminal!" \ + "" \ + "Supported terminals:" \ + " mintty and deriviates" \ + " guake" \ + " iTerm2" \ + " elementary terminal (pantheon/elementary)" \ + " mate-terminal" \ + " gnome-terminal" \ + " tilix" \ + " xfce4-terminal" \ + "" \ + "If you believe you have recieved this message in error," \ + "try manually setting \`TERMINAL', hint: ps -h -o comm -p \$PPID" + exit 1 + ;; + +esac + +unset PROFILE_NAME +unset PROFILE_SLUG +unset DEFAULT_SLUG diff --git a/audio/mute.sh b/audio/mute.sh new file mode 100644 index 0000000..fa323c0 --- /dev/null +++ b/audio/mute.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +amixer -q -D pulse sset Master toggle diff --git a/audio/noise-cancel.sh b/audio/noise-cancel.sh new file mode 100755 index 0000000..a9fd86c --- /dev/null +++ b/audio/noise-cancel.sh @@ -0,0 +1,11 @@ +# Microphone Realtime background noise reduction script +# author Luigi Maselli - https://grigio.org licence: AS-IS +# credits: http://askubuntu.com/questions/18958/realtime-noise-removal-with-pulseaudio +# run as: sudo && pulseaudio -k + +sudo cp /etc/pulse/default.pa /etc/pulse/default.pa.bak +sudo cat <> /etc/pulse/default.pa +load-module module-echo-cancel source_name=noechosource sink_name=noechosink +set-default-source noechosource +set-default-sink noechosink +EOT \ No newline at end of file diff --git a/gammastep.pl b/gammastep.pl new file mode 100755 index 0000000..9e2f0c0 --- /dev/null +++ b/gammastep.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use LWP::UserAgent; +use JSON::XS; + +my $ua = LWP::UserAgent->new(); +my $json = JSON::XS->new(); +my $location = "https://papillon.john.me.tz/data/location.json"; + +my $lat_lon = fetch_lat_lon($ua, $json, $location); + +my $pid = fork; +unless ($pid) { + open STDIN, '/dev/null'; + open STDOUT, '>>/dev/null'; + open STDERR, '>>/dev/null'; + + `gammastep -l $lat_lon`; +} + +sub fetch_lat_lon { + my ($ua, $json, $location) = @_; + + my $raw = $ua->get($location)->content(); + if (defined $raw) { + my $decoded = $json->decode($raw); + if (defined $decoded->{lat} && defined $decoded->{lon}) { + return "$decoded->{lat}:$decoded->{lon}"; + } + print $decoded->{lat}; + + } + sleep 5; + return fetch_lat_lon($ua, $json, $location); +} + +exit; diff --git a/i3/detached.sh b/i3/detached.sh new file mode 100755 index 0000000..6b569ac --- /dev/null +++ b/i3/detached.sh @@ -0,0 +1,3 @@ +#!/bin/sh +xrandr --output DP-2-1 --off --output DP-2-2 --off --output DP-2-3 --off --output eDP-1 --primary --mode 1920x1080 --pos 0x0 --rotate normal --output HDMI-2 --off --output HDMI-1 --off --output DP-2 --off --output DP-1 --off +echo "detached" > ~/.config/screenlayout/i3.current diff --git a/i3/home.sh b/i3/home.sh new file mode 100755 index 0000000..64a3659 --- /dev/null +++ b/i3/home.sh @@ -0,0 +1,3 @@ +#!/bin/sh +xrandr --output DP-2-1 --mode 1366x768 --pos 0x0 --rotate left --output DP-2-2 --mode 1920x1200 --pos 768x0 --rotate normal --output DP-2-3 --off --output eDP-1 --primary --mode 1920x1080 --pos 768x1200 --rotate normal --output HDMI-2 --off --output HDMI-1 --off --output DP-2 --off --output DP-1 --off +echo "home" > ~/.config/screenlayout/i3.current diff --git a/i3/i3move.sh b/i3/i3move.sh new file mode 100755 index 0000000..43e6873 --- /dev/null +++ b/i3/i3move.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +LAYOUT=`cat ~/.config/screenlayout/i3.current` +MIDDLE="eDP-1" + +if [[ $LAYOUT == 'home' ]]; then + RIGHT="DP-2-2" + LEFT="DP-2-1" +elif [[ $LAYOUT == 'work' ]]; then + RIGHT="DP-2-2" + LEFT="DP-2-1" +elif [[ $LAYOUT == '3' ]]; then + MIDDLE="DP-2-2" + LEFT="DP-2-1" + RIGHT="eDP-1" +else + echo "No external displays connected" +fi + +if [[ $1 == 'right' ]]; then + i3 move workspace to output $RIGHT +elif [[ $1 == 'middle' ]]; then + i3 move workspace to output $MIDDLE +elif [[ $1 == 'left' ]]; then + i3 move workspace to output $LEFT +else + echo "Invalid direction. Requires either 'up', 'left', or 'middle'" +fi diff --git a/i3/work.sh b/i3/work.sh new file mode 100755 index 0000000..cdf7bbb --- /dev/null +++ b/i3/work.sh @@ -0,0 +1,3 @@ +#!/bin/sh +xrandr --output DP-2-1 --mode 1920x1080 --pos 0x0 --rotate left --output DP-2-2 --mode 1920x1080 --pos 1080x0 --rotate normal --output DP-2-3 --off --output eDP-1 --primary --mode 1920x1080 --pos 1080x1080 --rotate normal --output HDMI-2 --off --output HDMI-1 --off --output DP-2 --off --output DP-1 --off +echo "work" > ~/.config/screenlayout/i3.current diff --git a/rofi/drun.sh b/rofi/drun.sh new file mode 100755 index 0000000..afd9659 --- /dev/null +++ b/rofi/drun.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +ROFI=$(pgrep -c rofi | cut -b 1) +echo $ROFI + +if [[ "$ROFI" -eq "0" ]]; then + rofi -config /home/jpm/.config/rofi/config -show drun +else + killall rofi 2&>1 /dev/null +fi diff --git a/rofi/rofi-openvpn.sh b/rofi/rofi-openvpn.sh new file mode 100755 index 0000000..b741701 --- /dev/null +++ b/rofi/rofi-openvpn.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Passwordless sudo required + +res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) + +if [ $res = "Connection" ]; then + /usr/bin/uxterm -e 'sudo /usr/bin/nmtui' +elif [ $res = "John.Me.tz" ]; then + sudo /usr/bin/systemctl stop openvpn-client@* + sudo /usr/bin/systemctl start openvpn-client@john.me.tz +elif [ $res = "MailCleaner" ]; then + sudo /usr/bin/systemctl stop openvpn-client@* + sudo /usr/bin/systemctl start openvpn-client@mailcleaner +elif [ $res = "Disconnect" ]; then + sudo /usr/bin/systemctl stop openvpn-client@* +elif [ $res = "Restart" ]; then + sudo /usr/bin/systemctl restart openvpn-client@* +fi + +exit + +# Waybar sometimes doesn't update with the VPN IP, for whatever reason. Restart it. +# exits above because I change outputs more often than I change VPNs +if [ "$(pgrep -c waybar)" -gt 0 ]; then + sleep 2s + pkill waybar + waybar +fi diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh new file mode 100755 index 0000000..12fdcdd --- /dev/null +++ b/rofi/rofi-power-menu.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Passwordless sudo required for systemctl [reboot|poweroff|hibernate] + +# Determine if Sway or i3 +if [ -z ${SWAYSOCK+x} ]; then + WM="i3" +else + WM="sway" +fi + +if [[ $WM == 'i3' ]]; then + res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) +else + res=$(echo "🔒 Lock|↩ Logout|↻ Reload Sway|↻ Reload Waybar|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) +fi + +if [ "$res" == "🔒 Lock" ]; then + ${WM}lock -c 323232 +elif [ "$res" == "↩ Logout" ]; then + # Prevent auto-login + rm /home/jpm/.config/last_login_gui + ${WM} exit +elif [ "$res" == "↻ Reload i3" ]; then + i3 reload +elif [ "$res" == "↹ Restart i3" ]; then + i3 restart +elif [ "$res" == "↻ Reload Sway" ]; then + sway reload +elif [ "$res" == "↻ Reload Waybar" ]; then + # Need to integrate with sway/displays.pl for alternative outputs + /home/jpm/scripts/sway/displays.pl -w +elif [ "$res" == "🡙 Reboot" ]; then + rm $SSH_AUTH_SOCK + sudo systemctl reboot -i +elif [ "$res" == "⏻ Shutdown" ]; then + rm $SSH_AUTH_SOCK + sudo systemctl poweroff -i +elif [ "$res" == "↯ Hibernate" ]; then + sudo systemctl hibernate -i +fi +exit 0 diff --git a/rofi/rofi-send-to-kodi.sh b/rofi/rofi-send-to-kodi.sh new file mode 100755 index 0000000..735b552 --- /dev/null +++ b/rofi/rofi-send-to-kodi.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +INPUT="$(rofi -dmenu -i -p 'Kodi:' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100)" + +/home/jpm/scripts/send-to-kodi.sh $INPUT 2>&1 /dev/null diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh new file mode 100755 index 0000000..c46ce99 --- /dev/null +++ b/rofi/rofi-ssh-menu.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|kipary.mailcleaner.net|media.lan.john.me.tz|pipcam.lan.john.me.tz|therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -yoffset 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) + +if [ $res = "john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs w' +elif [ $res = "root@john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs r' +elif [ $res = "shb.ng" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs s' +elif [ $res = "kipary.mailcleaner.net" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs d' +elif [ $res = "camera.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs c' +elif [ $res = "hud.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs h' +elif [ $res = "media.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs m' +elif [ $res = "programmer.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs p' +elif [ $res = "t470s.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs l' +elif [ $res = "therm.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs t' +elif [ $res = "vm.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs v' +fi +exit 0 diff --git a/rofi/sway-alt-tab.sh b/rofi/sway-alt-tab.sh new file mode 100755 index 0000000..032500e --- /dev/null +++ b/rofi/sway-alt-tab.sh @@ -0,0 +1,18 @@ +#!/bin/bash +swaymsg -t get_tree | + +jq -r '.nodes[].nodes[] | if .nodes then [recurse(.nodes[])] else [] end + .floating_nodes | .[] | select(.nodes==[]) | ((.id | tostring) + "\t" + .name)' | + +sed -e 's/ - [^-]*//' | + +sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | + +rofi -dmenu -config ~/.config/rofi/sidebar.rasi | { + +read -r + +id=`echo $REPLY | rev | cut -d' ' -f1 | rev` + +swaymsg "[con_id=$id]" focus + +} diff --git a/send-to-kodi.sh b/send-to-kodi.sh new file mode 100755 index 0000000..2e396ca --- /dev/null +++ b/send-to-kodi.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +# Required settings +host=10.8.0.66 +port=8080 + +# Optional login for Kodi +#user= +#pass= + +# Settings for netcat (local file) +local_hostname=$(hostname) +local_port=12345 + +show_help() +{ + cat</dev/null; then + zenity --error --ellipsize --text "$*" + else + echo "$*" 1>&2 + fi + + exit 1 +} + +send_json() +{ + curl \ + ${user:+--user "$user:$pass"} \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"Player.Open","params":{"item":{"file":"'"$1"'"}},"id":1}' \ + http://$host:$port/jsonrpc \ + || error "Failed to send link - is Kodi running?" +} + +ytplugin='plugin://plugin.video.youtube/?action=play_video&videoid=' + +[[ $host && $port ]] || error "Please set host and port in configuration" +[[ "$1" = --help ]] && show_help + +# Dialog box? +input=$1 +until [[ $input ]]; do + input="$(zenity --entry --title "Send to Kodi" --text "Paste a video link here")" || exit +done + +if [[ $input =~ ^file:// ]]; then + # Remove file:// and carrige return (\r) at the end + input="$(sed 's%^file://%%;s/\r$//' <<< "$input")" +fi + +# Get URL for... + +# Local media +if [[ -e $input ]]; then + type nc &>/dev/null || error "netcat required" + [[ $local_hostname && $local_port ]] || error "Please set local hostname and port in configuration" + + # Start netcat in background and kill it when we exit + nc -lp $local_port < "$input" & + trap "kill $!" EXIT + + url="tcp://$local_hostname:$local_port" + +# youtube.com / youtu.be +elif [[ $input =~ ^https?://(www\.)?youtu(\.be/|be\.com/watch\?v=) ]]; then + url="$ytplugin$(sed 's/.*\(youtu\.be\/\|[&?]v=\)\([a-zA-Z0-9_-]\+\).*/\2/' <<< "$input")" + +# Playable formats +elif [[ $input =~ \.(mp4|mkv|mov|avi|flv|wmv|asf|mp3|flac|mka|m4a|aac|ogg|pls|jpg|png|gif|jpeg|tiff)(\?.*)?$ ]]; then + url="$input" + +# Youtube-dl +else + type youtube-dl &>/dev/null || error "youtube-dl required" + url="$(youtube-dl -gf best "$input")" || error "No videos found, or site not supported by youtube-dl" +fi + +[[ $url ]] && send_json "$url" + +# Wait for netcat to exit +wait +# Don't kill netcat +trap - EXIT diff --git a/sway/displays.pl b/sway/displays.pl new file mode 100755 index 0000000..0b7eeaf --- /dev/null +++ b/sway/displays.pl @@ -0,0 +1,308 @@ +#!/usr/bin/perl + +######################################################################## +# Dependencies +######################################################################## +# +# Depends on JSON::XS and Proc::ProcessTable +# +# Debian: +# apt install libjson-xs-perl libproc-processtable-perl + +######################################################################## +# Directories and Files +######################################################################## + +# Template is a normal config with the following in place of values: +# "output": __OUTPUT__ +# "position": __POSITION__ +# "width": __WIDTH__ (optional) +my $waybar_template = '/home/jpm/.config/waybar/config.template'; + +# Temporary directory to save generated waybar config(s) +my $waybar_temporary = '/tmp'; + +######################################################################## +# Display Serials and Names +######################################################################## + +# Hash to match display Serial with a friendly name. +# You can get the serial from (quoted with *): +# $ swaymsg -t get_outputs +# Output eDP-1 'Unknown 0x057D *0x00000000*' +my %outputs = ( + '0x00000101' => 'Sam', + '3CQ4342S6W' => 'HP-1', + '3CQ3310Q1Q' => 'HP-2', + '0x00000000' => 'LVDS' +); + +######################################################################## +# Display Configurations +######################################################################## + +# First-level key of hash is the name of each configuration +# Second-level keys are the display friendly-names, above +# Third-level are the actual settings for that display +my %configs = ( + 'detached' => { + 'HP-1' => { + 'on' => 0 + }, + 'HP-2' => { + 'on' => 0 + }, + 'Sam' => { + 'on' => 0 + }, + 'LVDS' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 0, + 'y' => 0, + 'rotate' => 0, + 'waybar' => 'bottom' + } + }, + 'stacked' => { + 'Sam' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 960, + 'y' => 0, + 'rotate' => 0, + 'waybar' => 'bottom' + }, + 'HP-1' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 0, + 'y' => 1200, + 'rotate' => 0, + 'waybar' => 'top' + }, + 'HP-2' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 1920, + 'y' => 1200, + 'rotate' => 0, + 'waybar' => 'top' + }, + 'LVDS' => { + 'on' => 0 + } + }, + 'sidebyside' => { + 'HP-1' => { + 'on' => 1, + 'width' => 1080, + 'height' => 1920, + 'x' => 0, + 'y' => 225, + 'rotate' => 270, + 'waybar' => 'top' + }, + 'Sam' => { + 'on' => 1, + 'width' => 1200, + 'height' => 1920, + 'x' => 1080, + 'y' => 0, + 'rotate' => 90, + 'waybar' => 'top' + }, + 'HP-2' => { + 'on' => 1, + 'width' => 1080, + 'height' => 1920, + 'x' => 2280, + 'y' => 225, + 'rotate' => 90, + 'waybar' => 'top' + }, + 'LVDS' => { + 'on' => 0, + } + } +); + +######################################################################## +# Program (do not edit below) +######################################################################## + +use strict; +use warnings; + +# Bail if zero or >1 args +my $last = "/home/jpm/.config/last_display"; +my $waybar_only = 0; +my $config; + +if (scalar(@ARGV)) { + while (@ARGV) { + my $arg = shift; + if ($arg eq "-w") { + $waybar_only = 1; + } else { + if (defined $config) { + die "Too many arguments.\n"; + } + $config = $arg; + } + } +} + +unless (defined $config) { + open(my $fh, '<', $last); + $config = <$fh>; + close($fh); + chomp $config; + print "$config\n"; +} + +# Bail if requested config doesn't exist +unless (defined $configs{$config}) { + die "$config is not a defined configuration: " . join(', ', keys %configs) . "\n"; +} + +# Import and setup JSON object +use JSON::XS; +my $json = JSON::XS->new(); + +# Fetch connected displays +my $displays_raw = `swaymsg -t get_outputs --raw`; +my $displays = $json->decode($displays_raw); + +# For each connected display, collect the desired settings for enabled +# displays and a list of displays to disable +my $on; +my @off; + +for (my $i = 0; $i < scalar(@$displays); $i++) { + + # If a display is found without any settings, print error and turn it off + unless (defined $configs{$config}{$outputs{$displays->[$i]->{serial}}}) { + print STDERR "Output $displays->[$i]->{name} ($displays->[$i]->{serial}) found without defined function. Disabling.\n"; + push @off, $displays->[$i]->{name}; + next; + } + + # If display is enabled, copy all of the desired settings + if ($configs{$config}{$outputs{$displays->[$i]->{serial}}}{on}) { + $on->{$outputs{$displays->[$i]->{serial}}} = $configs{$config}{$outputs{$displays->[$i]->{serial}}}; + $on->{$outputs{$displays->[$i]->{serial}}}{output} = $displays->[$i]->{name}; + # Otherwise simply list it for disabling + } else { + push @off, $displays->[$i]->{name}; + } + +} + +unless ($waybar_only) { + # Number of simultaneous outputs is limited by possible, so disabled displays first + foreach (@off) { + + # Sway returns status as JSON + my $res_raw = `sway output $_ disable`; + my $res = $json->decode($res_raw)->[0]; + + # If failed, print to STDERR + unless ($res->{success}) { + print STDERR "Error ($res->{error}) in command 'sway output $_ disable'\n"; + } + + } +} + +# Kill existing Waybars +require Proc::ProcessTable; +my $t = new Proc::ProcessTable; +foreach my $p ( @{ $t->table } ) { + my $cmndline = $p->{'cmndline'}; + $cmndline =~ s/\s*$//g; + if ($cmndline =~ /^waybar.*/) { + if ($p->{'pid'} == $$) { + next; + } else { + $p->kill(9); + } + } +} + +# Configure each enabled display +foreach my $out (keys %$on) { + + unless ($waybar_only) { + # Build command, starting by enabling and powering on + my $cmd = "sway output $on->{$out}->{output} enable dpms on"; + + # If additional options are provided, add them to command + if (defined $on->{$out}->{rotate}) { + $cmd .= " transform $on->{$out}->{rotate}"; + } + if (defined $on->{$out}->{x} && defined $on->{$out}->{y}) { + $cmd .= " position $on->{$out}->{x} $on->{$out}->{y}"; + } + if (defined $on->{$out}->{width} && defined $on->{$out}->{height}) { + $cmd .= " mode $on->{$out}->{width}x$on->{$out}->{height}"; + } + + # Sway returns status as JSON + my $res_raw = `$cmd`; + my $res = $json->decode($res_raw)->[0]; + + # If failed, print to STDERR + unless ($res->{success}) { + print STDERR "Error ($res->{error}) in command '$cmd'\n"; + } + } + + # If waybar position is set, fork, generate config and execute it + if (defined $on->{$out}->{waybar}) { + my $pid = fork; + unless ($pid) { + open STDIN, '/dev/null'; + open STDOUT, '>>/dev/null'; + open STDERR, '>>/dev/null'; + + # Load in config template + my $waybar; + open (my $fh, '<', $waybar_template); + while (<$fh>) { + $waybar .= $_; + } + close $fh; + chomp $waybar; + + # Replace basic preferences + $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; + $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; + if (defined $on->{$out}->{width}) { + $waybar =~ s/__WIDTH__/$on->{$out}->{width}/; + # If width is not set, comment that line out to use default + } else { + $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; + } + + # Write config to a temporary file + my $tmp = $waybar_temporary . "/" . $on->{$out}->{output} . ".tmp"; + open ($fh, '>', $tmp); + print $fh $waybar; + close $fh; + `nohup waybar --config=$tmp`; + print $tmp . "\n"; + + # Remove config + unlink $tmp; + } + } +} + +open(my $fh, '>', $last); +print $fh $config; +close($fh); diff --git a/sway/gammastep.pl b/sway/gammastep.pl new file mode 100755 index 0000000..3d71179 --- /dev/null +++ b/sway/gammastep.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +# TODO: If gammastep is already running, allow location to update + +use strict; +use warnings; + +use LWP::UserAgent; +use JSON::XS; + +my $ua = LWP::UserAgent->new(); +my $json = JSON::XS->new(); +my $location = "https://papillon.john.me.tz/data/location.json"; + +my $lat_lon = fetch_lat_lon($ua, $json, $location); + +my $pid = fork; +unless ($pid) { + open STDIN, '/dev/null'; + open STDOUT, '>>/dev/null'; + open STDERR, '>>/dev/null'; + + `gammastep -l $lat_lon`; +} + +sub fetch_lat_lon { + my ($ua, $json, $location) = @_; + + my $raw = $ua->get($location)->content(); + if (defined $raw) { + my $decoded = $json->decode($raw); + if (defined $decoded->{lat} && defined $decoded->{lon}) { + return "$decoded->{lat}:$decoded->{lon}"; + } + print $decoded->{lat}; + + } + sleep 5; + return fetch_lat_lon($ua, $json, $location); +} + +exit; diff --git a/sway/popup-term.pl b/sway/popup-term.pl new file mode 100755 index 0000000..50eaae8 --- /dev/null +++ b/sway/popup-term.pl @@ -0,0 +1,75 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +# Workspace to push the terminal to when dismissed +my $hidden = 'grave'; +# Terminal application used for pop-up (swaymsg 'name') +my $term = 'uxterm'; + +use JSON::XS; +my $json = JSON::XS->new(); + +my $raw = join("\n",`swaymsg -t get_tree`); + +my $root = $json->decode($raw); + +# Get focused +my $display = $root->{focus}->[0]; +my ($workspace, $term_id, $term_ws); +foreach my $d (@{$root->{nodes}}) { + # If both the current workspace and terminal have been found, nothing else to look for + if (defined($workspace) && defined($term_id)) { + last; + # If the display from this iteration of the loop is in focus, look for the active workspace + } elsif ($d->{id} eq $display) { + foreach my $w (@{$d->{nodes}}) { + # Again, if both found, skip + if (defined($workspace) && defined($term_id)) { + last; + # Otherwise if the current workspace is active, mark it + } elsif ($w->{id} eq $d->{focus}->[0]) { + $workspace = $w->{name}; + } + # In any case, look for the terminal app + foreach my $n (@{$w->{floating_nodes}}) { + if ($n->{name} eq $term) { + $term_id = $n->{id}; + $term_ws = $w->{name}; + last; + } + } + } + # All other displays only need to be quickly searched for the term_id + } else { + foreach my $w (@{$d->{nodes}}) { + if (defined($term_id)) { + last; + } + foreach my $n (@{$w->{floating_nodes}}) { + if ($n->{name} eq $term) { + $term_id = $n->{id}; + $term_ws = $w->{name}; + last; + } + } + } + } +} +print "Active workspace = $workspace\nTerminal ID = $term_id\nTerminal WS = $term_ws\n"; + +# If there is no terminal found, spawn one +if (!defined($term_id)) { + print "No term running, starting one\n"; + exec $term +# If the current workspace is known and terminal isn't on it, bring and give focus +} elsif ($workspace != $term_ws) { + print "Term not on current workspace, bringing it\n"; + `swaymsg "[con_id=$term_id]" move workspace $workspace`; + `swaymsg "[con_id=$term_id]" focus`; +# Otherwise hide it from whereever it is +} else { + print "Term is on current workspace or lost, moving to $hidden\n"; + `swaymsg "[con_id=$term_id]" move workspace $hidden`; +} diff --git a/sway/swayidle.sh b/sway/swayidle.sh new file mode 100755 index 0000000..1b855e6 --- /dev/null +++ b/sway/swayidle.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +BLFILE="/tmp/blc" + +if [ -z $1 ]; then + echo "Missing argument: swayidlerun, swayidlewarn, swayidlesleep or swayidlewake" +elif [ $1 == "swayidlerun" ]; then + swayidle timeout 270 "/home/jpm/scripts/swayidle.sh swayidlewarn" before-sleep "/home/jpm/scripts/swayidle.sh swayidlesleep" resume "/home/jpm/scripts/swayidle.sh swayidlewake" +elif [ $1 == "swayidlewarn" ]; then + # Store current brightness + echo $(/home/jpm/bin/blc.pl %) > $BLFILE + # Dim display + /home/jpm/bin/blc.pl = 1 + # Warning notifications + /home/jpm/scripts/swayidlecountdown.sh +elif [ $1 == "swayidlesleep" ]; then + # Change nick to AFK + ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t 'screen -S irssi -X stuff "/nick jpmAFK^M"' + # Turn off monitor + swaymsg 'swaymsg "output * dpms off"' + # Lock screen + swaylock -c 323232 +elif [ $1 == "swayidlewake" ]; then + # Kill sleep if running + # Turn on monitor + swaymsg 'swaymsg "output * dpms on"' + # Restore brightness level + kill `pgrep swayidlecountdo` + /home/jpm/bin/blc.pl = $(cat /tmp/blc) +else + echo "Invalid argument: run, sleep or wake" +fi diff --git a/sway/swayidlecountdown.sh b/sway/swayidlecountdown.sh new file mode 100755 index 0000000..0c8574b --- /dev/null +++ b/sway/swayidlecountdown.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +for i in `seq 0 30`; do + notify-send -t 999 "Sleeping" $(expr 30 - $i); sleep 1 +done diff --git a/waybar/waybar-cpu.sh b/waybar/waybar-cpu.sh new file mode 100755 index 0000000..01c19e6 --- /dev/null +++ b/waybar/waybar-cpu.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if [ "$(pgrep -c htop)" -gt 0 ]; then + pkill htop +else + /usr/bin/uxterm -e htop +fi diff --git a/waybar/waybar-disk.sh b/waybar/waybar-disk.sh new file mode 100755 index 0000000..023388e --- /dev/null +++ b/waybar/waybar-disk.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +notify-send -t 3000 Disks "$(lsblk -o NAME,SIZE,FSUSE%,MOUNTPOINT | grep -vP '^loop' | sed 's/MOUNTPOINT/MOUNT/' | sed -e 's/│ └─/+---/' | sed -e 's/ └─/+---/' | sed -e 's/├─/+-/' | sed -e 's/└─/+-/' | awk {'printf "%-20s %-7s %- 6s %-7s\n", $1, $2, $3, $4'})" diff --git a/waybar/waybar-exec.sh b/waybar/waybar-exec.sh new file mode 100644 index 0000000..c4fd28a --- /dev/null +++ b/waybar/waybar-exec.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +CURRENT=`cat /home/jpm/.screenlayout/current` + +if [ $CURRENT eq 'waybar-single' ]; then + select diff --git a/waybar/waybar-mem.sh b/waybar/waybar-mem.sh new file mode 100755 index 0000000..7f5bbc5 --- /dev/null +++ b/waybar/waybar-mem.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +notify-send 'Memory Usage' "`free -h | awk '{printf(\"%6s %6s %6s %6s\n\", $1, $2, $3, $4)}' | sed -r 's/(.*) shared$/ \1/'`" diff --git a/waybar/waybar-nmtui.sh b/waybar/waybar-nmtui.sh new file mode 100755 index 0000000..1e9dc4e --- /dev/null +++ b/waybar/waybar-nmtui.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +if [ "$(pgrep -c nmtui | cut -b 1)" -eq "0" ]; then + echo true + /usr/bin/xterm -e '/usr/bin/nmtui' +else + echo false + pkill nmtui 2&>1 /dev/null +fi diff --git a/waybar/waybar-pa.sh b/waybar/waybar-pa.sh new file mode 100644 index 0000000..e69de29 From 0a65577304a2051cf1bddf73dd8b8557be4c980e Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 11 Sep 2020 11:05:15 -0400 Subject: [PATCH 003/110] Updated docs, removed unneeded or duplicates --- README.md | 148 ++++++++++++++++++++++++++++++++++++++++++ gammastep.pl | 40 ------------ waybar/waybar-exec.sh | 6 -- waybar/waybar-pa.sh | 0 4 files changed, 148 insertions(+), 46 deletions(-) delete mode 100755 gammastep.pl delete mode 100644 waybar/waybar-exec.sh delete mode 100644 waybar/waybar-pa.sh diff --git a/README.md b/README.md index e69de29..e93cf6c 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,148 @@ +# Simple Scripts + +## Waybar + +(Waybar)[https://github.com/Alexays/Waybar] is a very flexible and customizable taskbar for Sway (and other Wlroots-based wayland compositors). Waybar applets have hover and click functionality and have several scripts related to those. See the .config repository for the actual Waybar and Sway configs. + + waybar/waybar-cpu.sh + +Launch htop in floating window (bottom-right). If already running, kill it. + + waybar/waybar-disk.sh + +Notification with disk usage summaries. Renders properly with Dunst, but not Mako. + + waybar/waybar-mem.sh + +Notification with memory usage summaries. + + waybar/waybar-nmtui.sh + +Launch nmtui in floating window (bottom-right). If already running, kill it. + +## Audio + + audio/mute.sh + +Just a simple script to toggle Pulseaudio mute. + + audio/noise-cancel.sh + +Add a noise-cancelled version of existing interfaces to Pulseaudio. + +## i3 + +I haven't used i3 in earnest for quite some time since moving to Sway, so it is very likely that some of these scripts are broken based on other config changes. + + i3/i3move.sh + +When any of the Xrandr scripts below is run, it will print it's name to a config file. This script will read that config file and then knows how the outputs are arranged. Once this is known, it allows hotkeys to know which output to move a workspace to. + + i3/detached.sh + +Xrandr config. Just the laptop display. + + i3/work.sh + +Xrandr config. Vertical on the left, horizontal aligned to top of the vertical, and laptop directly below that. Left-to-right order is Vertical-Horizontal-Laptop. + + i3/home.sh + +Xrandr config. Not a layout I currently use. Home is now the "stacked" view from sway/displays. + +## Rofi + +(Rofi)[https://github.com/davatorium/rofi] is a neat graphical launcher and menu system. I use it for a bunch of stuff to supplement i3 and Sway to fill out same desktop niceties. See configs in 'dotfiles' repository. + + rofi/drun.sh + +Simple launcher. + + rofi/rofi-openvpn.sh + +Quick VPN switcher. + + rofi/rofi-power-menu.sh + +Lock, log out, restart Sway/i3, restart waybar, hibernate, reboot, shutdown. + + rofi/rofi-send-to-kodi.sh + +Forward pasted link to ./send-to-kodi.sh. + + rofi/rofi-ssh-menu.sh + +Open a terminal to any SSH shortcut machine. (TODO: Integrate with 'sshs' to get machine list from there instead of a static list). + + rofi/sway-alt-tab.sh + +Show all currently running applications in Sway to locate window. + +## Sway + +(Sway)[https://github.com/swaywm/sway] is an i3-compatible Wayland compositor and tiling window manager. See configs in 'dotfiles' repository. + + sway/ + +Scripts exclusively for automating or enhancing Sway. + + sway/displays.pl + +Script to automatically configure wayland outputs using swaymsg. Also forks waybars for each display. Allows custom configurations. No argument will run the last used configuration (~/config/last_display). '-w' will run only waybar without changing displays. + + sway/gammastep.pl + +Setup Gammastep based on current location. Requires a URL that returns JSON, including a "lat" and "lon". My URL (restricted to my IPs) returns these as recorded by PhoneTrack on my phone similar to: + +``` +{"lat":"180.12345678","lon":"-180.12345678","timestamp":"1599831660"} +``` + +It forks to keep running if terminal is killed. If location fails to be fetched it will try again every 5 seconds. + + sway/popup-term.pl + +A DIY version of the Tilde terminal. If terminal is not running, it opens on the current display. If it is running but not on current dislpay, it moves to current display. If it is already on current display, it is moved to a hidden display ('grave'). + +Note the relevant settings in dotfiles repository (sway/config) related to the 'grave' workspace, as well as UXTerm. + +``` +for_window [class="UXTerm"] floating enable, resize set height 600px, resize set width 800px, move position 1120px 460px +# Grave '`' key, DIY version of Tilde pop-up terminal +bindsym $mod+Grave exec /home/jpm/scripts/sway/popup-term.pl +# Visit the hidden grave workspace +bindsym $mod+Shift+Grave workspace grave +``` + +Also note that 'grave' has no label in waybar (waybar/config.template) to allow it to be *hidden*. + +``` +"sway/workspaces": { + "format": "{icon}", + "format-icons": { + "0": "0 \uf073", // Example of workspace with a label + "grave": "", + ... +``` + + sway/swayidle.sh + +**Work in progress** These scripts don't currently work the way I like. + +Sway has an Idle detection daemon that can flexibly take different actions after certain periods of inactivity as well as prior to sleep and after wake. + +This script is meant to unify all of the actions into one script by accepting an option. + + sway/swayidlecountdown.sh + +Prior to locking a countdown should be provided. Currently testing how to manage a countdown with Dunst, which doesn't actually support dynamic notifications. + +## Miscellaneous + + send-to-kodi.sh + +(This script)[https://github.com/allejok96/send-to-kodi] sends a URL or local file to a (Kodi)[https://github.com/xbmc] media player. Only modified to have my local media server IP. + + apply-gruvbox.sh + +A single theme version of the one provided (here)[https://raw.githubusercontent.com/Mayccoll/Gogh]. Applies the theme to a variety of terminals. Not really necessary after cloning the 'dotfiles' repository. diff --git a/gammastep.pl b/gammastep.pl deleted file mode 100755 index 9e2f0c0..0000000 --- a/gammastep.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use LWP::UserAgent; -use JSON::XS; - -my $ua = LWP::UserAgent->new(); -my $json = JSON::XS->new(); -my $location = "https://papillon.john.me.tz/data/location.json"; - -my $lat_lon = fetch_lat_lon($ua, $json, $location); - -my $pid = fork; -unless ($pid) { - open STDIN, '/dev/null'; - open STDOUT, '>>/dev/null'; - open STDERR, '>>/dev/null'; - - `gammastep -l $lat_lon`; -} - -sub fetch_lat_lon { - my ($ua, $json, $location) = @_; - - my $raw = $ua->get($location)->content(); - if (defined $raw) { - my $decoded = $json->decode($raw); - if (defined $decoded->{lat} && defined $decoded->{lon}) { - return "$decoded->{lat}:$decoded->{lon}"; - } - print $decoded->{lat}; - - } - sleep 5; - return fetch_lat_lon($ua, $json, $location); -} - -exit; diff --git a/waybar/waybar-exec.sh b/waybar/waybar-exec.sh deleted file mode 100644 index c4fd28a..0000000 --- a/waybar/waybar-exec.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -CURRENT=`cat /home/jpm/.screenlayout/current` - -if [ $CURRENT eq 'waybar-single' ]; then - select diff --git a/waybar/waybar-pa.sh b/waybar/waybar-pa.sh deleted file mode 100644 index e69de29..0000000 From 93a185960f1fe8700aea5559906e5f104b6f2f42 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 13 Sep 2020 02:18:03 -0400 Subject: [PATCH 004/110] Script to automatically update firefox since it's not great at doing this on it's own --- update-firefox.pl | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 update-firefox.pl diff --git a/update-firefox.pl b/update-firefox.pl new file mode 100755 index 0000000..149c280 --- /dev/null +++ b/update-firefox.pl @@ -0,0 +1,154 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use IO::Prompter; +use File::Which qw( which ); + +# Configurable variables +my $lang = 'en-CA'; +my $install = "$ENV{HOME}/.local/bin"; +my $working = "/tmp/firefox.new"; + +# Download link as provided by https://www.mozilla.org/$lang/firefox/developer/ +my $url = 'https://download.mozilla.org/?product=firefox-devedition-latest-ssl&os=linux64&lang='.$lang; + +# Ensure that we can unzip +unless (which("bunzip2")) { + die "Requires bunzip2. Try:\nsudo apt install zutils or your distro's equivalent\n"; +} + +# Only understood argument is to not bother verifying the package +my ($download_key, $verify) = (0,1); +if (defined $ARGV[0]) { + if ($ARGV[0] eq '--no-verify') { + $verify = 0; + } else { + die "Didn't understand argument $ARGV[0]\n"; + } +} + +# If verification is to be done, make sure we have the key +unless ($verify) { + print "Checking for Mozilla GPG key in keyring...\n"; + system("gpg --list-keys release\@mozillla.com 2>&1 > /dev/null"); + if ($?) { + my $YN = prompt (-in => *STDIN, "You don't currently have Mozilla's GPG key in your keyring.\nWould you like to install it? If not, installation will not be verified. [y/N]: ", -single); + if ($YN eq 'y' || $YN eq 'Y') { + $download_key = 1; + } else { + $verify = 0; + } + } +} + +# If a previous download still exists remove it +if ( -e $working ) { + system("rm -rf $working"); + if ($?) { + die "Working directory $working already exists and failed to remove: $!\n"; + } +} + +# Get version currently installed +my $current = `$install/firefox/firefox-bin --version`; +$current =~ s/.*\s([^\s])/$1/; +chomp $current; + +use WWW::Mechanize; +my $mech = WWW::Mechanize->new(); + +# $url is actually going to redirect to the proper current dowload, so just get the redirect. +my $head = $mech->head($url); + +my ($location, $version); +# This redirect will have the version id, so we can use that to determine if a new version actually exists +if ($head->{'_msg'}) { + $version = $location = $head->{'_previous'}->{'_headers'}->{'location'}; + $version =~ s/^.*\-([^\-]*)\.tar\.bz2$/$1/; + if ($version eq $current) { + die "Current ($current) is the same as New ($version)\n"; + } +} else { + print "unable to find new download\n"; +} + +mkdir($working) || die "Couldn't make $working: $!\n"; + +# Download package +print "Fetching package $location...\n"; +$mech->get($location); +$mech->save_content( $working."/firefox-".$version.".tar.bz2", binmode => ':raw', decoded_by_headers => 1 ); + +# If verification is required, get signature as well +if ($verify) { + $location .= '.asc'; + print "Fetching GPG signature $location...\n"; + $mech->get($location); + $mech->save_content( $working."/firefox-".$version.".tar.bz2.asc", binmode => ':raw', decoded_by_headers => 1 ); +} + +# If key still needs to be fetched, get it +if ($download_key) { + $location =~ s/linux-x86_64.*$/KEY/; + print "Fetching GPG key $location...\n"; + $mech->get($location); + $mech->save_content( $working."/mozilla.pgp", binmode => ':raw', decoded_by_headers => 1 ); + # And install it + print "Installing Mozilla GPG key in keyring...\n"; + system("gpg --import $working/mozilla.pgp 2>&1 > /dev/null"); + if ($?) { + die "Warning: failed to import key. Cannot verify integrity.\nDownloaded to $working. You can check and install it to $install manually: $!\n"; + } + unlink("$working/mozilla.pgp"); +} + +# Verify the package +if ($verify) { + print "Verifying download with Mozilla GPG key...\n"; + system("gpg --verify $working/firefox-$version.tar.bz2.asc"); + if ($?) { + die "Warning: failed to verify download. Signing failed.\nDownloaded to $working. You can check and install it to $install manually: $!\n"; + } +} + +# Uncompress +print "Uncompressing download with bunzip2...\n"; +system("bunzip2 $working/firefox-$version.tar.bz2"); +if ($?) { + die "Failed to uncompress: $!\n"; +} + +# Extract +print "Extracting from TAR archive...\n"; +system("tar -xf $working/firefox-$version.tar -C $working"); +if ($?) { + die "Failed to extract: $!\n"; +} + +# Bin the old backup +if (-e "$install/.firefox.old") { + print "Removing previous backup folder...\n"; + system("rm -rf $install/.firefox.old"); + if ($?) { + die "Failed to remove: $!\n"; + } +} + +# Move current to old +print "Backing up currently installed version ($current) to $install/.firefox.old...\n"; +system("mv $install/firefox $install/.firefox.old"); +if ($?) { + die "Failed to move: $!\n"; +} + +# Move new to current +print "Moving new version to $install for final installation...\n"; +system("mv $working/firefox $install/"); +if ($?) { + die "Failed to move: $!\n"; +} + +# Hurray! +print "Installation of version $version complete. You should restart firefox whenever it is convenient.\n"; +exit(); From ea6b7df307d49e3601f127ea62457bb4787b5aef Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 10 Oct 2020 04:44:51 -0400 Subject: [PATCH 005/110] Remove unnecessary debug line --- sway/displays.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/sway/displays.pl b/sway/displays.pl index 0b7eeaf..bc6c149 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -295,7 +295,6 @@ foreach my $out (keys %$on) { print $fh $waybar; close $fh; `nohup waybar --config=$tmp`; - print $tmp . "\n"; # Remove config unlink $tmp; From 5b18c8d7f4f9fd0c5f4122bef7d0a12c5bbf7592 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 10 Oct 2020 05:06:58 -0400 Subject: [PATCH 006/110] Login scripts Stores WM to last_login_gui file to allow for auto-login to the last used GUI Removes old log file, executes GUI with new one --- i3/starti3.sh | 5 +++++ sway/startsway.sh | 5 +++++ 2 files changed, 10 insertions(+) create mode 100755 i3/starti3.sh create mode 100755 sway/startsway.sh diff --git a/i3/starti3.sh b/i3/starti3.sh new file mode 100755 index 0000000..438950d --- /dev/null +++ b/i3/starti3.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +rm /home/jpm/.i3log +echo i3 > /home/jpm/.config/last_login_gui +exec startx 2> /home/jpm/.i3log diff --git a/sway/startsway.sh b/sway/startsway.sh new file mode 100755 index 0000000..e4998f2 --- /dev/null +++ b/sway/startsway.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +rm /home/jpm/.swaylog +echo sway > /home/jpm/.config/last_login_gui +exec sway 2> /home/jpm/.swaylog From 0893074aa11283d8716252094d41bfe4748876e5 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 13 Nov 2020 20:59:45 -0500 Subject: [PATCH 007/110] Change to wireguard IP --- send-to-kodi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/send-to-kodi.sh b/send-to-kodi.sh index 2e396ca..9b41bac 100755 --- a/send-to-kodi.sh +++ b/send-to-kodi.sh @@ -1,7 +1,7 @@ #!/bin/bash # Required settings -host=10.8.0.66 +host=10.10.0.66 port=8080 # Optional login for Kodi From f8bc44a73366976e555f6bf3faec6e4cba496389 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 15 Nov 2020 23:46:04 -0500 Subject: [PATCH 008/110] Updated for WireGuard, prevented reloading waybar on abort --- rofi/rofi-openvpn.sh | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/rofi/rofi-openvpn.sh b/rofi/rofi-openvpn.sh index b741701..7cf8db3 100755 --- a/rofi/rofi-openvpn.sh +++ b/rofi/rofi-openvpn.sh @@ -7,23 +7,25 @@ res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "| if [ $res = "Connection" ]; then /usr/bin/uxterm -e 'sudo /usr/bin/nmtui' elif [ $res = "John.Me.tz" ]; then - sudo /usr/bin/systemctl stop openvpn-client@* - sudo /usr/bin/systemctl start openvpn-client@john.me.tz + sudo /usr/bin/systemctl stop openvpn-client@mailcleaner + sudo /usr/bin/systemctl restart wg-quick@wg0 elif [ $res = "MailCleaner" ]; then - sudo /usr/bin/systemctl stop openvpn-client@* - sudo /usr/bin/systemctl start openvpn-client@mailcleaner + sudo /usr/bin/systemctl stop wg-quick@wg0 + sudo /usr/bin/systemctl restart openvpn-client@mailcleaner elif [ $res = "Disconnect" ]; then - sudo /usr/bin/systemctl stop openvpn-client@* + sudo /usr/bin/systemctl stop openvpn-client@mailcleaner + sudo /usr/bin/systemctl stop wg-quick@wg0 elif [ $res = "Restart" ]; then - sudo /usr/bin/systemctl restart openvpn-client@* + if [ "`ip addr show wg0 2> /dev/null`" != "" ]; then + sudo /usr/bin/systemctl restart wg-quick@wg0 + fi + if [ "`ip addr show tun0 2> /dev/null`" != "" ]; then + sudo /usr/bin/systemctl restart openvpn-client@mailcleaner + fi +else + exit fi -exit - # Waybar sometimes doesn't update with the VPN IP, for whatever reason. Restart it. # exits above because I change outputs more often than I change VPNs -if [ "$(pgrep -c waybar)" -gt 0 ]; then - sleep 2s - pkill waybar - waybar -fi +/home/jpm/scripts/sway/displays.pl -w From 8baad221bdbdc097da153dcf5f8a910a73731b89 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 15 Nov 2020 23:47:18 -0500 Subject: [PATCH 009/110] Better comments, prevent duplicate waybars Generate a single config file. Multiple processes seems to have run into a bug where waybar will restore killed bars. --- sway/displays.pl | 131 ++++++++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 48 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index bc6c149..8d9d3c4 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -1,5 +1,16 @@ #!/usr/bin/perl +######################################################################## +# Usage +######################################################################## +# +# $ displays.pl [layout] [-w] +# +# layout Name of desired layout, as configured starting at line 100 +# If missing, last known layout is used (logged to file $last) +# -w (Re)load waybar only. Skip display configuration. Only kill +# existing waybars and start new ones for desired layout + ######################################################################## # Dependencies ######################################################################## @@ -17,11 +28,14 @@ # "output": __OUTPUT__ # "position": __POSITION__ # "width": __WIDTH__ (optional) -my $waybar_template = '/home/jpm/.config/waybar/config.template'; +my $waybar_template = "$ENV{'HOME'}/.config/waybar/config.template"; # Temporary directory to save generated waybar config(s) my $waybar_temporary = '/tmp'; +# File to log and recover last used layout name +my $last = "$ENV{'HOME'}/.config/last_display"; + ######################################################################## # Display Serials and Names ######################################################################## @@ -138,8 +152,6 @@ my %configs = ( use strict; use warnings; -# Bail if zero or >1 args -my $last = "/home/jpm/.config/last_display"; my $waybar_only = 0; my $config; @@ -157,12 +169,12 @@ if (scalar(@ARGV)) { } } +# Get previous config if one is not provided unless (defined $config) { - open(my $fh, '<', $last); + open(my $fh, '<', $last) || die "Config name not provided and failed to open $last\n"; $config = <$fh>; close($fh); chomp $config; - print "$config\n"; } # Bail if requested config doesn't exist @@ -170,11 +182,14 @@ unless (defined $configs{$config}) { die "$config is not a defined configuration: " . join(', ', keys %configs) . "\n"; } -# Import and setup JSON object -use JSON::XS; -my $json = JSON::XS->new(); +# Write config that is to be used so that it can be recovered as default +open(my $fh, '>', $last) || print STDERR "Config name cannot be written to $last\n"; +print $fh $config; +close($fh); # Fetch connected displays +use JSON::XS; +my $json = JSON::XS->new(); my $displays_raw = `swaymsg -t get_outputs --raw`; my $displays = $json->decode($displays_raw); @@ -182,7 +197,6 @@ my $displays = $json->decode($displays_raw); # displays and a list of displays to disable my $on; my @off; - for (my $i = 0; $i < scalar(@$displays); $i++) { # If a display is found without any settings, print error and turn it off @@ -203,8 +217,9 @@ for (my $i = 0; $i < scalar(@$displays); $i++) { } +# Skip enabling/disabling displays if only running waybar (re)start unless ($waybar_only) { - # Number of simultaneous outputs is limited by possible, so disabled displays first + # Number of simultaneous outputs is limited by gpu, so disabled displays first foreach (@off) { # Sway returns status as JSON @@ -226,14 +241,35 @@ foreach my $p ( @{ $t->table } ) { my $cmndline = $p->{'cmndline'}; $cmndline =~ s/\s*$//g; if ($cmndline =~ /^waybar.*/) { + # Never kill this process if ($p->{'pid'} == $$) { next; + # SIGKILL match + # TODO BUG: when multiple processes are running, some respawn with new PIDs. IDK why? } else { $p->kill(9); } } } +# Load in config template +my $template; +if (open (my $fh, '<', $waybar_template)) { + while (<$fh>) { + $template .= $_; + } + close $fh; + chomp $template; +} else { + print STDERR "Failed to load template $waybar_template\n"; +} + +# If template is already set up as an array, remove the square brackets so that we can concatenate multiple displays +$template =~ s/^[^\[\{]*\[(.*)\]$/$1/s; + +# Setup waybar config file +my $waybar = ''; + # Configure each enabled display foreach my $out (keys %$on) { @@ -262,46 +298,45 @@ foreach my $out (keys %$on) { } } - # If waybar position is set, fork, generate config and execute it - if (defined $on->{$out}->{waybar}) { - my $pid = fork; - unless ($pid) { - open STDIN, '/dev/null'; - open STDOUT, '>>/dev/null'; - open STDERR, '>>/dev/null'; + # Skip waybar setup if template failed to be loaded + if ( (defined $template) && (defined $on->{$out}->{waybar}) && ($on->{$out}->{waybar} =~ m/(top|bottom|left|right)/) ) { - # Load in config template - my $waybar; - open (my $fh, '<', $waybar_template); - while (<$fh>) { - $waybar .= $_; - } - close $fh; - chomp $waybar; - - # Replace basic preferences - $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; - $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; - if (defined $on->{$out}->{width}) { - $waybar =~ s/__WIDTH__/$on->{$out}->{width}/; - # If width is not set, comment that line out to use default - } else { - $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; - } - - # Write config to a temporary file - my $tmp = $waybar_temporary . "/" . $on->{$out}->{output} . ".tmp"; - open ($fh, '>', $tmp); - print $fh $waybar; - close $fh; - `nohup waybar --config=$tmp`; - - # Remove config - unlink $tmp; + # If there's already a display set up, add a comma + unless ($waybar eq '') { + $waybar .= ','; } + + $waybar .= $template; + + # Replace basic preferences + $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; + $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; + if (defined $on->{$out}->{width}) { + $waybar =~ s/__WIDTH__/$on->{$out}->{width}/; + # If width is not set, comment that line out to use default + } else { + $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; + } + } } -open(my $fh, '>', $last); -print $fh $config; -close($fh); +# Restore array formatting +$waybar = '[' . $waybar . ']'; + +# Start Waybar as fork +my $pid = fork; +unless ($pid) { + open STDIN, '/dev/null'; + open STDOUT, '>>/dev/null'; + open STDERR, '>>/dev/null'; + # Write config to a temporary file + my $tmp = $waybar_temporary . "/waybar-" . time() .".config"; + open ($fh, '>', $tmp); + print $fh $waybar; + close $fh; + `nohup waybar --config=$tmp`; + + # Remove config + unlink $tmp; +} From d8bfb5a38ebc2976af4868b4c363621e8aa6e397 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 15 Nov 2020 23:55:20 -0500 Subject: [PATCH 010/110] Thinkpad control scripts SystemD unit file to give ownership or necessary sys files to user toggle_outputs.sh simply swaps between two most common layouts with sway/displays.pl kbd_backlight.pl simply increments the current backlight brightness then %3 to cycle between off, low, high blc.pl is an overly complicated screen backlight control --- thinkpad/blc.pl | 305 +++++++++++++++++++++++ thinkpad/kbd_backlight.pl | 39 +++ thinkpad/toggle_outputs.sh | 9 + thinkpad/user-thinkpad-controls@.service | 8 + 4 files changed, 361 insertions(+) create mode 100755 thinkpad/blc.pl create mode 100755 thinkpad/kbd_backlight.pl create mode 100755 thinkpad/toggle_outputs.sh create mode 100644 thinkpad/user-thinkpad-controls@.service diff --git a/thinkpad/blc.pl b/thinkpad/blc.pl new file mode 100755 index 0000000..d9a4f0e --- /dev/null +++ b/thinkpad/blc.pl @@ -0,0 +1,305 @@ +#!/usr/bin/perl -w + +# Files containing current and max brightness values +my $cur_file = "/sys/class/backlight/intel_backlight/brightness"; +my $max_file = "/sys/class/backlight/intel_backlight/max_brightness"; +my $last_file = "/home/jpm/.config/blc.last"; + +sub to_percent { + my $value = shift; + if ($value eq "Permission Denied") { + return $value; + } else { + $value = int($value/get_max()*100); + return $value . '%'; + } +} + +sub get_offset { + return int(get_max()/100); +} + +sub get_current { + open(my $c,'<',"$cur_file"); + my $current = <$c>; + close $c; + chomp $current; + return $current; +} + +sub get_max { + open(my $m,'<',"$max_file"); + my $max = <$m>; + close $m; + chomp $max; + return $max; +} + +sub get_min { + return int((get_max()/100)+2); +} + +sub writable { + if (! -w $cur_file) { + return 0; + } else { + return 1; + } +} + +sub increment { + if (writable()) { + my $current = get_current(); + my $max = get_max(); + my $target = $current+get_offset(); + if ($target > $max) { + $target = $max; + } + open(my $c,'>',"$cur_file"); + print $c $target; + close $c; + return $target; + } else { + return "Permission Denied"; + } +} + +sub decrement { + if (writable()) { + my $current = get_current(); + my $min = get_min(); + my $target = $current-get_offset(); + if ($target < $min) { + $target = $min; + } + open(my $c,'>',"$cur_file"); + print $c $target; + close $c; + return $target; + } else { + return "Permission Denied"; + } +} + +sub set { + my $value = shift; + if (writable()) { + $current = get_current(); + if ($value > $current) { + for (my $i=$current;$i<=$value;$i++) { + open(my $c,'>',"$cur_file"); + print $c $i; + close $c; + } + } else { + for (my $i=$current;$i>=$value;$i--) { + open(my $c,'>',"$cur_file"); + print $c $i; + close $c; + } + } + return $value; + } else { + return "Permission Denied"; + } +} + +sub help { + print " +Backlight Control + +Usage: blc.pl [--silent|--notify] [OPTION] [VALUE] + +With no option the backlight information is printed as JSON. + +Output printed to STDOUT unless: + +--silent Do not display output (overrides --notify) +--notify Send output to notification daemon. --notify=N will + change the display duration in ms. Default is 200ms + +Output option must preceed the first Action option. + +Actions: + += VALUE Set backlight to specific value. VALUE greater than + 100 will be treated as absolute value. VALUE eqaul to + or less than 100 will be treated as a percentage +++ Increment by 1% ++= VALUE Increment by VALUE percent +-- Decrement by 1% +-= VALUE Decrement by VALUE percent + +Actions corrected to 1% or 100% if over or under. All actions +provide output as a percentage, with the % symbol. + +Final percentage printed as below, skipping other options. + +Print: + +== Print current absolute value +^ Print maximum absolute value +% Print current percentage (does not include % symbol) +--help Help (not impacted by --silent or --notify) +--HELP Advanced help (same as above) + +Any other option will be printed literally"; +} + +sub advanced { + $current = get_current(); + $max = get_max(); + print ". + +Print functions can be strung together but command will exit +with the first non-print option. eg. + + \$ blc.pl == / ^ + 21/100 + \$ blc.pl == ++ + ('==' ignored) + (Backlight incremented) + +Escape options with \\ in quotes to display them literally. eg. + + \$ blc.pl == / ^ '\\=' % \'\\%\' + " . $current . "/" . $max . "=" . int($current/$max*100) . "% + +Only one \'\\' is removed per block. eg. + + \$ blc.pl '\\% \\' + % \\ + +"; +} + +my $current = get_current(); +my (@output, $target, $silent, $notify); + +if (scalar @ARGV) { + for (my $i=0;$i get_max()) { + $target = set(get_max()); + } elsif ($target > 100) { + $target = set($target); + } else { + $target = set(int((get_max()*$target/100)+1)); + } + if ($target eq "Permission Denied") { + @output = $target; + } else { + @output = to_percent($target); + } + last; + } else { + @output = ("No value after $ARGV[$i]"); + last; + } + } elsif ($ARGV[$i] eq '%') { + push @output,int(get_current()/get_max()*100); + } elsif ($ARGV[$i] eq '^') { + push @output,get_max(); + } elsif ($ARGV[$i] eq '==') { + push @output,get_current(); + } elsif ($ARGV[$i] eq '--help') { + help(); + print " (see --HELP).\n\n"; + exit(); + } elsif ($ARGV[$i] eq '--HELP') { + help(); + advanced(); + exit(); + } elsif ($ARGV[$i] eq '--silent') { + $silent = 'TRUE'; + } elsif ($ARGV[$i] =~ /^--notify/) { + $notify = 'TRUE'; + if ($ARGV[$i] =~ /=[0-9]+$/) { + $duration = $ARGV[$i]; + $duration =~ s/.*=([0-9]+)/$1/; + } else { + $duration = 200; + } + } else { + my $add = $ARGV[$i]; + $add =~ s/\\//; + push @output,$add; + } + } +} else { + @output = ('{"Backlight":{"Max":"' . get_max() . '","Current":"' . get_current() . '","Percentage","' . int(get_current()/get_max()*100) . '%"}}'); +} + + +open(my $fh,'>',$last_file); +print $fh get_current(); +close($fh); + +if ($silent) { + exit(); +} elsif ($notify) { + # Don't output anything if the value didn't change + if ($current == get_current()) { + exit(); + } + my $concat; + foreach (@output) { + $concat .= $_; + } + system "notify-send --urgency=normal -i /usr/share/icons/Papirus-Dark-Grey/48x48/status/notification-display-brightness.svg -t $duration \"$concat\""; + exit(); +} else { + print foreach @output; + print "\n"; + exit(); +} diff --git a/thinkpad/kbd_backlight.pl b/thinkpad/kbd_backlight.pl new file mode 100755 index 0000000..e195341 --- /dev/null +++ b/thinkpad/kbd_backlight.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my $maxfile = "/sys/class/leds/tpacpi\:\:kbd_backlight/max_brightness"; +my $current = "/sys/class/leds/tpacpi\:\:kbd_backlight/brightness"; + +my ($max, $now, $new); +if (open(my $m, '<', $maxfile)) { + $max = readline($m); + chomp $max; + close($m); +} else { + print "Failed to read $maxfile\n"; + exit; +} +print STDERR "max = $max\n"; + +if (open(my $c, '<', $current)) { + $now = readline($c); + chomp $now; + close($c); +} else { + print "Failed to read $current\n"; + exit; +} +print STDERR "now = $now\n"; + +if (open(my $fh, '>', $current)) { + $new = (($now+1) % ($max+1)); + chomp $new; + print $fh $new; + close($fh); +} else { + print "Failed to write $current\n"; + exit; +} +print STDERR "new = $new\n"; diff --git a/thinkpad/toggle_outputs.sh b/thinkpad/toggle_outputs.sh new file mode 100755 index 0000000..072718c --- /dev/null +++ b/thinkpad/toggle_outputs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +CURRENT=`cat /home/jpm/.config/last_display` + +if [ "$CURRENT" == "detached" ]; then + /home/jpm/scripts/sway/displays.pl stacked +else + /home/jpm/scripts/sway/displays.pl detached +fi diff --git a/thinkpad/user-thinkpad-controls@.service b/thinkpad/user-thinkpad-controls@.service new file mode 100644 index 0000000..7d10487 --- /dev/null +++ b/thinkpad/user-thinkpad-controls@.service @@ -0,0 +1,8 @@ +[Unit] +Description=Give ownership of backlight to %I + +[Service] +ExecStart=chown %i:%i /sys/class/backlight/intel_backlight/brightness /sys/class/leds/tpacpi::kbd_backlight/brightness + +[Install] +WantedBy=multi-user.target From 4750ac31b31c2af713491eb0afa7bda88d4a7c5f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 16 Nov 2020 00:53:09 -0500 Subject: [PATCH 011/110] Move toggle_outputs to sway directory It is not specific to thinkpad hardware but it is specific to sway; this is more appropriate --- sway/toggle_outputs.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 sway/toggle_outputs.sh diff --git a/sway/toggle_outputs.sh b/sway/toggle_outputs.sh new file mode 100755 index 0000000..072718c --- /dev/null +++ b/sway/toggle_outputs.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +CURRENT=`cat /home/jpm/.config/last_display` + +if [ "$CURRENT" == "detached" ]; then + /home/jpm/scripts/sway/displays.pl stacked +else + /home/jpm/scripts/sway/displays.pl detached +fi From e81c0311ed2e11e2e93f45718d5ea7fb75986a65 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 16 Nov 2020 02:31:52 -0500 Subject: [PATCH 012/110] toggle_output.sh was moved --- thinkpad/toggle_outputs.sh | 9 --------- 1 file changed, 9 deletions(-) delete mode 100755 thinkpad/toggle_outputs.sh diff --git a/thinkpad/toggle_outputs.sh b/thinkpad/toggle_outputs.sh deleted file mode 100755 index 072718c..0000000 --- a/thinkpad/toggle_outputs.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -CURRENT=`cat /home/jpm/.config/last_display` - -if [ "$CURRENT" == "detached" ]; then - /home/jpm/scripts/sway/displays.pl stacked -else - /home/jpm/scripts/sway/displays.pl detached -fi From b161ad6423daf03932889cda230aeee427c356c0 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 16 Nov 2020 07:40:33 +0000 Subject: [PATCH 013/110] Updated documentation Added README data for laptop function button scripts. Fixed formatting for links and used bold instead of code formatting for script names. --- README.md | 125 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index e93cf6c..4ad8ae3 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,13 @@ # Simple Scripts - -## Waybar - -(Waybar)[https://github.com/Alexays/Waybar] is a very flexible and customizable taskbar for Sway (and other Wlroots-based wayland compositors). Waybar applets have hover and click functionality and have several scripts related to those. See the .config repository for the actual Waybar and Sway configs. - - waybar/waybar-cpu.sh - -Launch htop in floating window (bottom-right). If already running, kill it. - - waybar/waybar-disk.sh - -Notification with disk usage summaries. Renders properly with Dunst, but not Mako. - - waybar/waybar-mem.sh - -Notification with memory usage summaries. - - waybar/waybar-nmtui.sh - -Launch nmtui in floating window (bottom-right). If already running, kill it. - ## Audio - audio/mute.sh +**audio/mute.sh** -Just a simple script to toggle Pulseaudio mute. +Just a simple script to toggle Alsa mute. - audio/noise-cancel.sh +--- + +**audio/noise-cancel.sh** Add a noise-cancelled version of existing interfaces to Pulseaudio. @@ -34,77 +15,73 @@ Add a noise-cancelled version of existing interfaces to Pulseaudio. I haven't used i3 in earnest for quite some time since moving to Sway, so it is very likely that some of these scripts are broken based on other config changes. - i3/i3move.sh +**i3/i3move.sh** When any of the Xrandr scripts below is run, it will print it's name to a config file. This script will read that config file and then knows how the outputs are arranged. Once this is known, it allows hotkeys to know which output to move a workspace to. - i3/detached.sh +**i3/detached.sh** Xrandr config. Just the laptop display. - i3/work.sh +**i3/work.sh** Xrandr config. Vertical on the left, horizontal aligned to top of the vertical, and laptop directly below that. Left-to-right order is Vertical-Horizontal-Laptop. - i3/home.sh +**i3/home.sh** Xrandr config. Not a layout I currently use. Home is now the "stacked" view from sway/displays. ## Rofi -(Rofi)[https://github.com/davatorium/rofi] is a neat graphical launcher and menu system. I use it for a bunch of stuff to supplement i3 and Sway to fill out same desktop niceties. See configs in 'dotfiles' repository. +[Rofi](https://github.com/davatorium/rofi) is a neat graphical launcher and menu system. I use it for a bunch of stuff to supplement i3 and Sway to fill out same desktop niceties. See configs in 'dotfiles' repository. - rofi/drun.sh +**rofi/drun.sh** Simple launcher. - rofi/rofi-openvpn.sh +**rofi/rofi-openvpn.sh** Quick VPN switcher. - rofi/rofi-power-menu.sh +**rofi/rofi-power-menu.sh** Lock, log out, restart Sway/i3, restart waybar, hibernate, reboot, shutdown. - rofi/rofi-send-to-kodi.sh +**rofi/rofi-send-to-kodi.sh** Forward pasted link to ./send-to-kodi.sh. - rofi/rofi-ssh-menu.sh +**rofi/rofi-ssh-menu.sh** Open a terminal to any SSH shortcut machine. (TODO: Integrate with 'sshs' to get machine list from there instead of a static list). - rofi/sway-alt-tab.sh +**rofi/sway-alt-tab.sh** Show all currently running applications in Sway to locate window. ## Sway -(Sway)[https://github.com/swaywm/sway] is an i3-compatible Wayland compositor and tiling window manager. See configs in 'dotfiles' repository. +[Sway](https://github.com/swaywm/sway) is an i3-compatible Wayland compositor and tiling window manager. See configs in 'dotfiles' repository. Here are some scripts exclusively for automating or enhancing Sway. - sway/ - -Scripts exclusively for automating or enhancing Sway. - - sway/displays.pl +**sway/displays.pl** Script to automatically configure wayland outputs using swaymsg. Also forks waybars for each display. Allows custom configurations. No argument will run the last used configuration (~/config/last_display). '-w' will run only waybar without changing displays. - sway/gammastep.pl +**sway/gammastep.pl** -Setup Gammastep based on current location. Requires a URL that returns JSON, including a "lat" and "lon". My URL (restricted to my IPs) returns these as recorded by PhoneTrack on my phone similar to: +Setup Gammastep based on current location. I don't have geolocation in my laptop, so this requires a URL that returns JSON, including a "lat" and "lon". My URL (restricted to my IPs) returns these as recorded by PhoneTrack on my phone similar to: ``` {"lat":"180.12345678","lon":"-180.12345678","timestamp":"1599831660"} ``` -It forks to keep running if terminal is killed. If location fails to be fetched it will try again every 5 seconds. +It forks to keep running if terminal is killed to remove the need for nohup. If location fails to be fetched it will try again every 5 seconds. - sway/popup-term.pl +**sway/popup-term.pl** -A DIY version of the Tilde terminal. If terminal is not running, it opens on the current display. If it is running but not on current dislpay, it moves to current display. If it is already on current display, it is moved to a hidden display ('grave'). +A DIY version of the Tilde terminal. If terminal is not running, it opens on the current display. If it is running but not on current display, it moves to current display. If it is already on current display, it is moved to a hidden display ('grave'). -Note the relevant settings in dotfiles repository (sway/config) related to the 'grave' workspace, as well as UXTerm. +Note the relevant settings in dotfiles repository (sway/config) related to the 'grave' workspace, as well as UXTerm which is configured to open floating in the bottom corner. ``` for_window [class="UXTerm"] floating enable, resize set height 600px, resize set width 800px, move position 1120px 460px @@ -125,24 +102,62 @@ Also note that 'grave' has no label in waybar (waybar/config.template) to allow ... ``` - sway/swayidle.sh +**sway/swayidle.sh** -**Work in progress** These scripts don't currently work the way I like. +Work in progress. These scripts don't currently work the way I like. Sway has an Idle detection daemon that can flexibly take different actions after certain periods of inactivity as well as prior to sleep and after wake. This script is meant to unify all of the actions into one script by accepting an option. - sway/swayidlecountdown.sh +**sway/swayidlecountdown.sh** -Prior to locking a countdown should be provided. Currently testing how to manage a countdown with Dunst, which doesn't actually support dynamic notifications. +Prior to locking, a countdown should be provided. Currently testing how to manage a countdown with Dunst, which doesn't actually support dynamic notifications. + +**sway/toggle_outputs** + +Swap between detached and docked modes using `sway/displays.pl`. Bound to function key for external monitor button. + +## Thinkpad + +**thinkpad/blc.pl** + +Overly complicated backlight brightness control script. Provides flexible control of backlight so that changes can be easily scripted or called from keyboard shortcuts. --help provides some usage docs. + +**thinkpad/kbd_backlight.pl** + +Simple script to cycle keyboard backlight. Gets max brightness, current brightness and then changes then increments the current brightness. Uses mod of max+1 so that it will cycle back around to 0 (disabled) if it is already at max. + +**thinkpad/user-thinkpad-control@.service** + +SystemD unit file used to give ownership of necessary sys files to whichever user it is enabled for `systemctl enable user-thinkpad-control@jpm`. Without this, the user won't be able to write these files and thus cannot set brightness values. + +## Waybar + +[Waybar](https://github.com/Alexays/Waybar) is a very flexible and customizable taskbar for Sway (and other Wlroots-based wayland compositors). Waybar applets have hover and click functionality and have several scripts related to those. See the .config repository for the actual Waybar and Sway configs. + + **waybar/waybar-cpu.sh** + +Launch htop in floating window (bottom-right). If already running, kill it. + +**waybar/waybar-disk.sh** + +Notification with disk usage summaries. Renders properly with Dunst, but not Mako. + +**waybar/waybar-mem.sh** + +Notification with memory usage summaries. + +**waybar/waybar-nmtui.sh** + +Launch nmtui in floating window (bottom-right). If already running, kill it. ## Miscellaneous - send-to-kodi.sh +**send-to-kodi.sh** -(This script)[https://github.com/allejok96/send-to-kodi] sends a URL or local file to a (Kodi)[https://github.com/xbmc] media player. Only modified to have my local media server IP. +[This script](https://github.com/allejok96/send-to-kodi) sends a URL or local file to a [Kodi](https://github.com/xbmc) media player. Only modified to have my local media server IP. - apply-gruvbox.sh +**apply-gruvbox.sh** -A single theme version of the one provided (here)[https://raw.githubusercontent.com/Mayccoll/Gogh]. Applies the theme to a variety of terminals. Not really necessary after cloning the 'dotfiles' repository. +A single theme version of the one provided [here](https://raw.githubusercontent.com/Mayccoll/Gogh). Applies the theme to a variety of terminals. Not really necessary after cloning the 'dotfiles' repository. \ No newline at end of file From a4f2b3310c7750d3ae176d2d6b261ec7ea284f52 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 23 Nov 2020 04:35:26 -0500 Subject: [PATCH 014/110] Kernel formatting --- README.md | 118 ++- apply-gruvbox.sh | 1080 +++++++++++----------- audio/noise-cancel.sh | 5 +- i3/detached.sh | 9 +- i3/home.sh | 11 +- i3/i3move.sh | 24 +- i3/work.sh | 11 +- rofi/drun.sh | 4 +- rofi/rofi-openvpn.sh | 30 +- rofi/rofi-power-menu.sh | 36 +- rofi/rofi-send-to-kodi.sh | 3 +- rofi/rofi-ssh-menu.sh | 29 +- rofi/sway-alt-tab.sh | 6 +- send-to-kodi.sh | 58 +- sway/displays.pl | 403 ++++---- sway/gammastep.pl | 33 +- sway/popup-term.pl | 88 +- sway/swayidle.sh | 46 +- sway/swayidlecountdown.sh | 2 +- sway/toggle_outputs.sh | 4 +- thinkpad/blc.pl | 467 +++++----- thinkpad/kbd_backlight.pl | 32 +- thinkpad/user-thinkpad-controls@.service | 4 +- update-firefox.pl | 160 ++-- waybar/waybar-cpu.sh | 4 +- waybar/waybar-disk.sh | 6 +- waybar/waybar-mem.sh | 4 +- waybar/waybar-nmtui.sh | 8 +- 28 files changed, 1451 insertions(+), 1234 deletions(-) diff --git a/README.md b/README.md index 4ad8ae3..4087bf2 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,51 @@ # Simple Scripts + ## Audio **audio/mute.sh** Just a simple script to toggle Alsa mute. ---- - **audio/noise-cancel.sh** Add a noise-cancelled version of existing interfaces to Pulseaudio. ## i3 -I haven't used i3 in earnest for quite some time since moving to Sway, so it is very likely that some of these scripts are broken based on other config changes. +I haven't used i3 in earnest for quite some time since moving to Sway, so it is +very likely that some of these scripts are broken based on other config changes. **i3/i3move.sh** -When any of the Xrandr scripts below is run, it will print it's name to a config file. This script will read that config file and then knows how the outputs are arranged. Once this is known, it allows hotkeys to know which output to move a workspace to. +When any of the Xrandr scripts below is run, it will print it's name to a config +file. This script will read that config file and then knows how the outputs are +arranged. Once this is known, it allows hotkeys to know which output to move a +workspace to. **i3/detached.sh** Xrandr config. Just the laptop display. -**i3/work.sh** +**i3/detached.sh** -Xrandr config. Vertical on the left, horizontal aligned to top of the vertical, and laptop directly below that. Left-to-right order is Vertical-Horizontal-Laptop. +Xrandr config. Just the laptop display. **i3/home.sh** -Xrandr config. Not a layout I currently use. Home is now the "stacked" view from sway/displays. +Xrandr config. Not a layout I currently use. Home is now the "stacked" view from +sway/displays. + +**i3/work.sh** + +Xrandr config. Vertical on the left, horizontal aligned to top of the vertical, +and laptop directly below that. Left-to-right order is +Vertical-Horizontal-Laptop. ## Rofi -[Rofi](https://github.com/davatorium/rofi) is a neat graphical launcher and menu system. I use it for a bunch of stuff to supplement i3 and Sway to fill out same desktop niceties. See configs in 'dotfiles' repository. +[Rofi](https://github.com/davatorium/rofi) is a neat graphical launcher and menu +system. I use it for a bunch of stuff to supplement i3 and Sway to fill out same +desktop niceties. See configs in 'dotfiles' repository. **rofi/drun.sh** @@ -53,7 +65,8 @@ Forward pasted link to ./send-to-kodi.sh. **rofi/rofi-ssh-menu.sh** -Open a terminal to any SSH shortcut machine. (TODO: Integrate with 'sshs' to get machine list from there instead of a static list). +Open a terminal to any SSH shortcut machine. (TODO: Integrate with 'sshs' to get +machine list from there instead of a static list). **rofi/sway-alt-tab.sh** @@ -61,27 +74,40 @@ Show all currently running applications in Sway to locate window. ## Sway -[Sway](https://github.com/swaywm/sway) is an i3-compatible Wayland compositor and tiling window manager. See configs in 'dotfiles' repository. Here are some scripts exclusively for automating or enhancing Sway. +[Sway](https://github.com/swaywm/sway) is an i3-compatible Wayland compositor +and tiling window manager. See configs in 'dotfiles' repository. Here are some +scripts exclusively for automating or enhancing Sway. **sway/displays.pl** -Script to automatically configure wayland outputs using swaymsg. Also forks waybars for each display. Allows custom configurations. No argument will run the last used configuration (~/config/last_display). '-w' will run only waybar without changing displays. +Script to automatically configure wayland outputs using swaymsg. Also forks +waybars for each display. Allows custom configurations. No argument will run the +last used configuration (~/config/last_display). '-w' will run only waybar +without changing displays. **sway/gammastep.pl** -Setup Gammastep based on current location. I don't have geolocation in my laptop, so this requires a URL that returns JSON, including a "lat" and "lon". My URL (restricted to my IPs) returns these as recorded by PhoneTrack on my phone similar to: +Setup Gammastep based on current location. I don't have geolocation in my +laptop, so this requires a URL that returns JSON, including a "lat" and "lon". +My URL (restricted to my IPs) returns these as recorded by PhoneTrack on my +phone similar to: ``` {"lat":"180.12345678","lon":"-180.12345678","timestamp":"1599831660"} ``` -It forks to keep running if terminal is killed to remove the need for nohup. If location fails to be fetched it will try again every 5 seconds. +It forks to keep running if terminal is killed. If location fails to be fetched +it will try again every 5 seconds. **sway/popup-term.pl** -A DIY version of the Tilde terminal. If terminal is not running, it opens on the current display. If it is running but not on current display, it moves to current display. If it is already on current display, it is moved to a hidden display ('grave'). +A DIY version of the Tilde terminal. If terminal is not running, it opens on the +current display. If it is running but not on current dislpay, it moves to +current display. If it is already on current display, it is moved to a hidden +display ('grave'). -Note the relevant settings in dotfiles repository (sway/config) related to the 'grave' workspace, as well as UXTerm which is configured to open floating in the bottom corner. +Note the relevant settings in dotfiles repository (sway/config) related to the +'grave' workspace, as well as UXTerm. ``` for_window [class="UXTerm"] floating enable, resize set height 600px, resize set width 800px, move position 1120px 460px @@ -91,58 +117,69 @@ bindsym $mod+Grave exec /home/jpm/scripts/sway/popup-term.pl bindsym $mod+Shift+Grave workspace grave ``` -Also note that 'grave' has no label in waybar (waybar/config.template) to allow it to be *hidden*. +Also note that 'grave' has no label in waybar (waybar/config.template) to allow +it to be *hidden*. ``` "sway/workspaces": { - "format": "{icon}", + "format": "{icon}", "format-icons": { - "0": "0 \uf073", // Example of workspace with a label - "grave": "", - ... + "0": "0 \uf073", // Example of workspace with a label + "grave": "", + ... ``` **sway/swayidle.sh** Work in progress. These scripts don't currently work the way I like. -Sway has an Idle detection daemon that can flexibly take different actions after certain periods of inactivity as well as prior to sleep and after wake. +Sway has an Idle detection daemon that can flexibly take different actions after +certain periods of inactivity as well as prior to sleep and after wake. -This script is meant to unify all of the actions into one script by accepting an option. +This script is meant to unify all of the actions into one script by accepting an +option. **sway/swayidlecountdown.sh** -Prior to locking, a countdown should be provided. Currently testing how to manage a countdown with Dunst, which doesn't actually support dynamic notifications. - -**sway/toggle_outputs** - -Swap between detached and docked modes using `sway/displays.pl`. Bound to function key for external monitor button. +Prior to locking a countdown should be provided. Currently testing how to manage +a countdown with Dunst, which doesn't actually support dynamic notifications. ## Thinkpad **thinkpad/blc.pl** - -Overly complicated backlight brightness control script. Provides flexible control of backlight so that changes can be easily scripted or called from keyboard shortcuts. --help provides some usage docs. + +Overly complicated backlight brightness control script. Provides flexible +control of backlight so that changes can be easily scripted or called from +keyboard shortcuts. --help provides some usage docs. **thinkpad/kbd_backlight.pl** - -Simple script to cycle keyboard backlight. Gets max brightness, current brightness and then changes then increments the current brightness. Uses mod of max+1 so that it will cycle back around to 0 (disabled) if it is already at max. + +Simple script to cycle keyboard backlight. Gets max brightness, current +brightness and then changes then increments the current brightness. Uses mod of +max+1 so that it will cycle back around to 0 (disabled) if it is already at max. **thinkpad/user-thinkpad-control@.service** - -SystemD unit file used to give ownership of necessary sys files to whichever user it is enabled for `systemctl enable user-thinkpad-control@jpm`. Without this, the user won't be able to write these files and thus cannot set brightness values. + +SystemD unit file used to give ownership of necessary sys files to whichever +user it is enabled for `systemctl enable user-thinkpad-control@jpm`. Without +this, the user won't be able to write these files and thus cannot set brightness +values. ## Waybar -[Waybar](https://github.com/Alexays/Waybar) is a very flexible and customizable taskbar for Sway (and other Wlroots-based wayland compositors). Waybar applets have hover and click functionality and have several scripts related to those. See the .config repository for the actual Waybar and Sway configs. +[Waybar](https://github.com/Alexays/Waybar) is a very flexible and customizable +taskbar for Sway (and other Wlroots-based wayland compositors). Waybar applets +have hover and click functionality and have several scripts related to those. +See the .config repository for the actual Waybar and Sway configs. - **waybar/waybar-cpu.sh** +**waybar/waybar-cpu.sh** Launch htop in floating window (bottom-right). If already running, kill it. **waybar/waybar-disk.sh** -Notification with disk usage summaries. Renders properly with Dunst, but not Mako. +Notification with disk usage summaries. Renders properly with Dunst, but not +Mako. **waybar/waybar-mem.sh** @@ -156,8 +193,13 @@ Launch nmtui in floating window (bottom-right). If already running, kill it. **send-to-kodi.sh** -[This script](https://github.com/allejok96/send-to-kodi) sends a URL or local file to a [Kodi](https://github.com/xbmc) media player. Only modified to have my local media server IP. +[This script](https://github.com/allejok96/send-to-kodi) sends a URL or local +file to a [Kodi](https://github.com/xbmc) media player. Only modified to have my +local media server IP. **apply-gruvbox.sh** -A single theme version of the one provided [here](https://raw.githubusercontent.com/Mayccoll/Gogh). Applies the theme to a variety of terminals. Not really necessary after cloning the 'dotfiles' repository. \ No newline at end of file +A single theme version of the one provided +[here](https://raw.githubusercontent.com/Mayccoll/Gogh). Applies the theme to a +variety of terminals. Not really necessary after cloning the 'dotfiles' +repository. diff --git a/apply-gruvbox.sh b/apply-gruvbox.sh index 6eda344..780a818 100644 --- a/apply-gruvbox.sh +++ b/apply-gruvbox.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash -# Single theme copy of apply-colors.sh from: https://raw.githubusercontent.com/Mayccoll/Gogh +# Single theme copy of apply-colors.sh from: +# https://raw.githubusercontent.com/Mayccoll/Gogh # ====================CONFIG THIS =============================== # export COLOR_01="#282828" # HOST @@ -43,30 +44,31 @@ GS="${GS:-$(command -v gsettings | xargs echo)}" # | handled there in case there was en error before this script was called # | ============================================ GLOBAL_VAR_CLEANUP() { - unset PROFILE_NAME - unset PROFILE_SLUG - unset scratchdir - unset TILIX_RES - unset TERMINAL - unset LOOP - unset OPTLENGTH + unset PROFILE_NAME + unset PROFILE_SLUG + unset scratchdir + unset TILIX_RES + unset TERMINAL + unset LOOP + unset OPTLENGTH - for c in $(seq -s " " -w 16); do - unset DEMO_COLOR_${c} - unset COLOR_${c} - done + for c in $(seq -s " " -w 16); do + unset DEMO_COLOR_${c} + unset COLOR_${c} + done - unset BACKGROUND_COLOR - unset FOREGROUND_COLOR - unset CURSOR_COLOR - unset HIGHLIGHT_FG_COLOR - unset HIGHLIGHT_BG_COLOR - unset USE_SYS_TRANSPARENCY - unset PROFILE_NAME + unset BACKGROUND_COLOR + unset FOREGROUND_COLOR + unset CURSOR_COLOR + unset HIGHLIGHT_FG_COLOR + unset HIGHLIGHT_BG_COLOR + unset USE_SYS_TRANSPARENCY + unset PROFILE_NAME } -# Note: Since all scripts gets invoked in a subshell the traps from the parent shell -# will not get inherited. Hence traps defined in gogh.sh and print-themes.sh will still trigger +# Note: Since all scripts gets invoked in a subshell the traps from the parent +# shell will not get inherited. Hence traps defined in gogh.sh and +# print-themes.sh will still trigger trap 'GLOBAL_VAR_CLEANUP; trap - EXIT' EXIT HUP INT QUIT PIPE TERM # | =========================================== @@ -75,67 +77,65 @@ trap 'GLOBAL_VAR_CLEANUP; trap - EXIT' EXIT HUP INT QUIT PIPE TERM # | ============================================ if [[ -z "${TERMINAL:-}" ]]; then - # | =========================================== - # | Check for the terminal name (depening on os) - # | =========================================== - OS="$(uname)" - if [[ "$OS" = "Darwin" ]]; then - TERMINAL=$TERM_PROGRAM - elif [[ "${OS#CYGWIN}" != "${OS}" ]]; then - TERMINAL="mintty" - else - # | =========================================== - # | Depending on how the script was invoked, we need - # | to loop until pid is no longer a subshell - # | =========================================== - pid="$$" - TERMINAL="$(ps -h -o comm -p $pid)" - while [[ "${TERMINAL:(-2)}" == "sh" ]]; do - pid="$(ps -h -o ppid -p $pid)" - TERMINAL="$(ps -h -o comm -p $pid)" - done - fi + # | =========================================== + # | Check for the terminal name (depening on os) + # | =========================================== + OS="$(uname)" + if [[ "$OS" = "Darwin" ]]; then + TERMINAL=$TERM_PROGRAM + elif [[ "${OS#CYGWIN}" != "${OS}" ]]; then + TERMINAL="mintty" + else + # | =========================================== + # | Depending on how the script was invoked, we need + # | to loop until pid is no longer a subshell + # | =========================================== + pid="$$" + TERMINAL="$(ps -h -o comm -p $pid)" + while [[ "${TERMINAL:(-2)}" == "sh" ]]; do + pid="$(ps -h -o ppid -p $pid)" + TERMINAL="$(ps -h -o comm -p $pid)" + done + fi fi case "${TERMINAL}" in - pantheon-terminal|io.elementary.t* ) - if [[ -z "${GS}" ]]; then - printf '\n%s\n' "Error gsettings not found" - printf '%s\n' "sudo apt install dconf?" - printf '%s\n\n' "or export GS=/path/to/gsettings" - exit 1 - fi - ;; - - mintty ) - CFGFILE="${HOME}/.minttyrc" - if [[ ! -f "${CFGFILE}" ]]; then - printf '\n%s\n' "Warning: Couldn't find an existing configuration file, so one will be created for you." - printf '%s\n\n' "Warning: Are you really running Cygwin's mintty?" - touch "${CFGFILE}" - fi - ;; - - guake|tilix|mate-terminal|gnome-terminal* ) - case "${TERMINAL}" in - guake|gnome-terminal* ) - if [[ -z "${DCONF}" ]] && [[ -z "${GCONF}" ]]; then - printf '\n%s\n' "Error gconftool not found!" - printf '%s\n' "sudo apt install gconftool?" - printf '%s\n\n' "or export GCONF=/path/to/gconftool-2/" - exit 1 +pantheon-terminal|io.elementary.t* ) + if [[ -z "${GS}" ]]; then + printf '\n%s\n' "Error gsettings not found" + printf '%s\n' "sudo apt install dconf?" + printf '%s\n\n' "or export GS=/path/to/gsettings" + exit 1 + fi + ;; +mintty ) + CFGFILE="${HOME}/.minttyrc" + if [[ ! -f "${CFGFILE}" ]]; then + printf '\n%s\n' "Warning: Couldn't find an existing configuration file, \ +so one will be created for you." + printf '%s\n\n' "Warning: Are you really running Cygwin's mintty?" + touch "${CFGFILE}" + fi + ;; +guake|tilix|mate-terminal|gnome-terminal* ) + case "${TERMINAL}" in + guake|gnome-terminal* ) + if [[ -z "${DCONF}" ]] && [[ -z "${GCONF}" ]]; then + printf '\n%s\n' "Error gconftool not found!" + printf '%s\n' "sudo apt install gconftool?" + printf '%s\n\n' "or export GCONF=/path/to/gconftool-2/" + exit 1 + fi + ;; + esac + if [[ -z "${DCONF}" ]]; then + printf '\n%s\n' "Error dconf not found" + printf '%s\n' "sudo apt install dconf?" + printf '%s\n\n' "or export DCONF=/path/to/dconf" + exit 1 fi ;; - esac - if [[ -z "${DCONF}" ]]; then - printf '\n%s\n' "Error dconf not found" - printf '%s\n' "sudo apt install dconf?" - printf '%s\n\n' "or export DCONF=/path/to/dconf" - exit 1 - fi - ;; - esac # | =========================================== @@ -143,192 +143,205 @@ esac # | =========================================== gnome_color () { - AA=${1:1:2} - BB=${1:3:2} - CC=${1:5:2} + AA=${1:1:2} + BB=${1:3:2} + CC=${1:5:2} - echo "#${AA}${AA}${BB}${BB}${CC}${CC}" + echo "#${AA}${AA}${BB}${BB}${CC}${CC}" } hexToDec () { - echo "$((16#${1}))" + echo "$((16#${1}))" } hexRGBtoDecRGB () { - R="$(hexToDec "${1:1:2}")" - G="$(hexToDec "${1:3:2}")" - B="$(hexToDec "${1:5:2}")" + R="$(hexToDec "${1:1:2}")" + G="$(hexToDec "${1:3:2}")" + B="$(hexToDec "${1:5:2}")" - echo "${R}" "${G}" "${B}" + echo "${R}" "${G}" "${B}" } convertRGBtoMac () { - local color="${1}" - set -- - set -- $(hexRGBtoDecRGB "${color}") - R=${1}; shift; G=${1}; shift; B=${1}; shift + local color="${1}" + set -- + set -- $(hexRGBtoDecRGB "${color}") + R=${1}; shift; G=${1}; shift; B=${1}; shift - R=$(echo "${R} / 255" | bc -l) - G=$(echo "${G} / 255" | bc -l) - B=$(echo "${B} / 255" | bc -l) + R=$(echo "${R} / 255" | bc -l) + G=$(echo "${G} / 255" | bc -l) + B=$(echo "${B} / 255" | bc -l) - echo "${R}" "${G}" "${B}" + echo "${R}" "${G}" "${B}" } createMinttyEntry () { - local name="${1}" - local color="${2}" - set -- - set -- $(hexRGBtoDecRGB "${color}") - R=${1}; shift; G=${1}; shift; B=${1}; shift + local name="${1}" + local color="${2}" + set -- + set -- $(hexRGBtoDecRGB "${color}") + R=${1}; shift; G=${1}; shift; B=${1}; shift - echo "${name}=${R},${G},${B}" + echo "${name}=${R},${G},${B}" } updateMinttyConfig () { - local config="${1}" - local color="${2}" - local name="${3}" + local config="${1}" + local color="${2}" + local name="${3}" - sed -i -r -e "s/^${name}=.+/$(createMinttyEntry "${name}" "${color}")/g" "${config}" + sed -i -r -e "s/^${name}=.+/$(createMinttyEntry "${name}" \ +"${color}")/g" "${config}" } convertNameAndRGBtoITerm() { - local name="${1}" - local color="${2}" - set -- - set -- $(convertRGBtoMac "${color}") - R=${1}; shift; G=${1}; shift; B=${1}; shift + local name="${1}" + local color="${2}" + set -- + set -- $(convertRGBtoMac "${color}") + R=${1}; shift; G=${1}; shift; B=${1}; shift - echo "${name}Blue Component${B}Green Component${G}Red Component${R}" + echo "${name}Blue Component${B}\ +Green Component${G}Red Component\ +${R}" } dset() { - local key="${1}"; shift - local val="${1}" + local key="${1}"; shift + local val="${1}" - "${DCONF}" write "${PROFILE_KEY}/${key}" "${val}" + "${DCONF}" write "${PROFILE_KEY}/${key}" "${val}" } # Because dconf still doesn't have "append" dlist_append() { - local key="${1}"; shift - local val="${1}"; shift - local entries + local key="${1}"; shift + local val="${1}"; shift + local entries - entries="$( - { - "${DCONF}" read "${key}" | tr -d "[]" | tr , "\n" | grep -F -v "${val}" - echo "'${val}'" - } | head -c-1 | tr "\n" , - )" + entries="$( + { + "${DCONF}" read "${key}" | tr -d "[]" | tr , "\n" | \ + grep -F -v "${val}" + echo "'${val}'" + } \ + | head -c-1 | tr "\n" , + )" - "${DCONF}" write "${key}" "[${entries}]" + "${DCONF}" write "${key}" "[${entries}]" } gcset() { - local type="${1}"; shift - local key="${1}"; shift - local val="${1}" + local type="${1}"; shift + local key="${1}"; shift + local val="${1}" - "${GCONF}" --set --type "${type}" "${PROFILE_KEY}/${key}" -- "${val}" + "${GCONF}" --set --type "${type}" "${PROFILE_KEY}/${key}" -- "${val}" } # Because gconftool doesn't have "append" glist_append() { - local type="${1}"; shift - local key="${1}"; shift - local val="${1}"; shift - local entries + local type="${1}"; shift + local key="${1}"; shift + local val="${1}"; shift + local entries - entries="$( - { - "${GCONF}" --get "${key}" | tr -d "[]" | tr , "\n" | grep -F -v "${val}" - echo "${val}" - } | head -c-1 | tr "\n" , - )" + entries="$( + { + "${GCONF}" --get "${key}" | tr -d "[]" | tr , "\n" | \ + grep -F -v "${val}" + echo "${val}" + }\ + | head -c-1 | tr "\n" , + )" - "${GCONF}" --set --type list --list-type "${type}" "${key}" "[${entries}]" + "${GCONF}" --set --type list --list-type "${type}" "${key}" \ + "[${entries}]" } gset() { - local key="${1}"; shift - local val="${1}" + local key="${1}"; shift + local val="${1}" - "${GS}" set "${PROFILE_KEY}" "${key}" "${val}" + "${GS}" set "${PROFILE_KEY}" "${key}" "${val}" } set_theme() { - dset visible-name "'${PROFILE_NAME}'" - dset background-color "'${BACKGROUND_COLOR}'" - dset foreground-color "'${FOREGROUND_COLOR}'" + dset visible-name "'${PROFILE_NAME}'" + dset background-color "'${BACKGROUND_COLOR}'" + dset foreground-color "'${FOREGROUND_COLOR}'" - if [[ -n "${HIGHLIGHT_BG_COLOR:-}" ]]; then - dset highlight-colors-set "true" - dset highlight-background-color "'${HIGHLIGHT_BG_COLOR}'" - if [[ -n "${HIGHLIGHT_FG_COLOR:-}" ]]; then - dset highlight-foreground-color "'${HIGHLIGHT_FG_COLOR}'" - fi - fi + if [[ -n "${HIGHLIGHT_BG_COLOR:-}" ]]; then + dset highlight-colors-set "true" + dset highlight-background-color "'${HIGHLIGHT_BG_COLOR}'" + if [[ -n "${HIGHLIGHT_FG_COLOR:-}" ]]; then + dset highlight-foreground-color \ + "'${HIGHLIGHT_FG_COLOR}'" + fi + fi - if [[ -n "${BOLD_COLOR:-}" ]]; then - dset bold-color "'${BOLD_COLOR}'" - dset bold-color-same-as-fg "false" - else - dset bold-color "'${FOREGROUND_COLOR}'" - dset bold-color-same-as-fg "true" - fi - dset use-theme-colors "false" - dset use-theme-background "false" - dset use-theme-transparency "${USE_SYS_TRANSPARENCY:-false}" + if [[ -n "${BOLD_COLOR:-}" ]]; then + dset bold-color "'${BOLD_COLOR}'" + dset bold-color-same-as-fg "false" + else + dset bold-color "'${FOREGROUND_COLOR}'" + dset bold-color-same-as-fg "true" + fi + dset use-theme-colors "false" + dset use-theme-background "false" + dset use-theme-transparency "${USE_SYS_TRANSPARENCY:-false}" } legacy_set_theme() { - gcset string visible_name "${PROFILE_NAME}" - gcset string background_color "${BACKGROUND_COLOR}" - gcset string foreground_color "${FOREGROUND_COLOR}" + gcset string visible_name "${PROFILE_NAME}" + gcset string background_color "${BACKGROUND_COLOR}" + gcset string foreground_color "${FOREGROUND_COLOR}" - if [[ -n "${BOLD_COLOR:-}" ]]; then - gcset string bold_color "${BOLD_COLOR}" - gcset bool bold_color_same_as_fg "false" - else - gcset string bold_color "${FOREGROUND_COLOR}" - gcset bool bold_color_same_as_fg "true" - fi - gcset bool use_theme_colors "false" - gcset bool use_theme_background "false" + if [[ -n "${BOLD_COLOR:-}" ]]; then + gcset string bold_color "${BOLD_COLOR}" + gcset bool bold_color_same_as_fg "false" + else + gcset string bold_color "${FOREGROUND_COLOR}" + gcset bool bold_color_same_as_fg "true" + fi + gcset bool use_theme_colors "false" + gcset bool use_theme_background "false" } # | =========================================== -# | If terminal supports truecolor then we can show theme colors without applying the theme +# | If terminal supports truecolor then we can show theme colors without +# | applying the theme # | =========================================== -if [[ "${COLORTERM:-}" == "truecolor" ]] || [[ "${COLORTERM:-}" == "24bit" ]]; then - # gogh_colors have been moved here to avoid multiple definitions - function gogh_colors () { - # Build up the color string to avoid visual rendering - local color_str - # Note: {01..16} does not work on OSX - for c in $(seq -s " " -w 16); do - local color="COLOR_$c" - set -- $(hexRGBtoDecRGB "${!color}") - color_str+="\033[38;2;${1};${2};${3}m█████$(tput sgr0)" - [[ ${GOGH_DRY_RUN:-0} -eq 1 ]] && export "DEMO_COLOR_$c=\033[38;2;${1};${2};${3}m" - [[ "$c" == "08" ]] && color_str+="\n" # new line - done - printf '\n%b\n\n\n' "${color_str}" - unset color_str - } +if [[ "${COLORTERM:-}" == "truecolor" ]] || [[ "${COLORTERM:-}" == "24bit" ]] +then + # gogh_colors have been moved here to avoid multiple definitions + function gogh_colors () { + # Build up the color string to avoid visual rendering + local color_str + # Note: {01..16} does not work on OSX + for c in $(seq -s " " -w 16); do + local color="COLOR_$c" + set -- $(hexRGBtoDecRGB "${!color}") + color_str+="\033[38;2;${1};${2};${3}m█████$(tput sgr0)" + [[ ${GOGH_DRY_RUN:-0} -eq 1 ]] && \ + export "DEMO_COLOR_$c=\033[38;2;${1};${2};${3}m" + [[ "$c" == "08" ]] && \ + color_str+="\n" # new line + done + printf '\n%b\n\n\n' "${color_str}" + unset color_str + } else - function gogh_colors () { - # Build up the color string to avoid visual rendering - local color_str - for c in {0..15}; do - color_str+="$(tput setaf $c)█████$(tput sgr0)" - [[ $c == 7 ]] && color_str+="\n" # new line - done - printf '\n%b\n\n' "${color_str}" - unset color_str - } + function gogh_colors () { + # Build up the color string to avoid visual rendering + local color_str + for c in {0..15}; do + color_str+="$(tput setaf $c)█████$(tput sgr0)" + [[ $c == 7 ]] && color_str+="\n" # new line + done + printf '\n%b\n\n' "${color_str}" + unset color_str + } fi # | =========================================== @@ -336,417 +349,440 @@ fi # | =========================================== gogh_colors if [[ ${GOGH_DRY_RUN:-0} -eq 1 ]]; then - color - # End here if dry run was initiated - exit 0 + color + # End here if dry run was initiated + exit 0 fi apply_elementary() { - # | =========================================== - # | Applying values on elementary/pantheon terminal - # | =========================================== - gset background "${BACKGROUND_COLOR}" - gset foreground "${FOREGROUND_COLOR}" - gset cursor-color "${CURSOR_COLOR}" - gset palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" + # | =========================================== + # | Applying values on elementary/pantheon terminal + # | =========================================== + gset background "${BACKGROUND_COLOR}" + gset foreground "${FOREGROUND_COLOR}" + gset cursor-color "${CURSOR_COLOR}" + gset palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" } apply_cygwin() { - # | =========================================== - # | Applying values on mintty (cygwin) - # | =========================================== + # | =========================================== + # | Applying values on mintty (cygwin) + # | =========================================== - echo "Patching mintty configuration file (${CFGFILE}) with new colors..." + echo "Patching mintty configuration file (${CFGFILE}) with new colors..." - updateMinttyConfig "$CFGFILE" "$COLOR_01" "Black" - updateMinttyConfig "$CFGFILE" "$COLOR_02" "Red" - updateMinttyConfig "$CFGFILE" "$COLOR_03" "Green" - updateMinttyConfig "$CFGFILE" "$COLOR_04" "Yellow" - updateMinttyConfig "$CFGFILE" "$COLOR_05" "Blue" - updateMinttyConfig "$CFGFILE" "$COLOR_06" "Magenta" - updateMinttyConfig "$CFGFILE" "$COLOR_07" "Cyan" - updateMinttyConfig "$CFGFILE" "$COLOR_08" "White" + updateMinttyConfig "$CFGFILE" "$COLOR_01" "Black" + updateMinttyConfig "$CFGFILE" "$COLOR_02" "Red" + updateMinttyConfig "$CFGFILE" "$COLOR_03" "Green" + updateMinttyConfig "$CFGFILE" "$COLOR_04" "Yellow" + updateMinttyConfig "$CFGFILE" "$COLOR_05" "Blue" + updateMinttyConfig "$CFGFILE" "$COLOR_06" "Magenta" + updateMinttyConfig "$CFGFILE" "$COLOR_07" "Cyan" + updateMinttyConfig "$CFGFILE" "$COLOR_08" "White" - updateMinttyConfig "$CFGFILE" "$COLOR_09" "BoldBlack" - updateMinttyConfig "$CFGFILE" "$COLOR_10" "BoldRed" - updateMinttyConfig "$CFGFILE" "$COLOR_11" "BoldGreen" - updateMinttyConfig "$CFGFILE" "$COLOR_12" "BoldYellow" - updateMinttyConfig "$CFGFILE" "$COLOR_13" "BoldBlue" - updateMinttyConfig "$CFGFILE" "$COLOR_14" "BoldMagenta" - updateMinttyConfig "$CFGFILE" "$COLOR_15" "BoldCyan" - updateMinttyConfig "$CFGFILE" "$COLOR_16" "BoldWhite" + updateMinttyConfig "$CFGFILE" "$COLOR_09" "BoldBlack" + updateMinttyConfig "$CFGFILE" "$COLOR_10" "BoldRed" + updateMinttyConfig "$CFGFILE" "$COLOR_11" "BoldGreen" + updateMinttyConfig "$CFGFILE" "$COLOR_12" "BoldYellow" + updateMinttyConfig "$CFGFILE" "$COLOR_13" "BoldBlue" + updateMinttyConfig "$CFGFILE" "$COLOR_14" "BoldMagenta" + updateMinttyConfig "$CFGFILE" "$COLOR_15" "BoldCyan" + updateMinttyConfig "$CFGFILE" "$COLOR_16" "BoldWhite" - updateMinttyConfig "$CFGFILE" "$BACKGROUND_COLOR" "Backgroundcolor" - updateMinttyConfig "$CFGFILE" "$FOREGROUND_COLOR" "Foregroundcolor" - updateMinttyConfig "$CFGFILE" "$CURSOR_COLOR" "Cursorcolor" + updateMinttyConfig "$CFGFILE" "$BACKGROUND_COLOR" "Backgroundcolor" + updateMinttyConfig "$CFGFILE" "$FOREGROUND_COLOR" "Foregroundcolor" + updateMinttyConfig "$CFGFILE" "$CURSOR_COLOR" "Cursorcolor" - echo "Done - please reopen your Cygwin terminal to see the changes" + echo "Done - please reopen your Cygwin terminal to see the changes" } apply_darwin() { - # | =========================================== - # | Applying values on iTerm2 - # | =========================================== + # | =========================================== + # | Applying values on iTerm2 + # | =========================================== - BACKGROUND_COLOR=$(convertNameAndRGBtoITerm "Background Color" "$BACKGROUND_COLOR") - FOREGROUND_COLOR=$(convertNameAndRGBtoITerm "Foreground Color" "$FOREGROUND_COLOR") - COLOR_01=$(convertNameAndRGBtoITerm "Ansi 0 Color" "$COLOR_01") - COLOR_02=$(convertNameAndRGBtoITerm "Ansi 1 Color" "$COLOR_02") - COLOR_03=$(convertNameAndRGBtoITerm "Ansi 2 Color" "$COLOR_03") - COLOR_04=$(convertNameAndRGBtoITerm "Ansi 3 Color" "$COLOR_04") - COLOR_05=$(convertNameAndRGBtoITerm "Ansi 4 Color" "$COLOR_05") - COLOR_06=$(convertNameAndRGBtoITerm "Ansi 5 Color" "$COLOR_06") - COLOR_07=$(convertNameAndRGBtoITerm "Ansi 6 Color" "$COLOR_07") - COLOR_08=$(convertNameAndRGBtoITerm "Ansi 7 Color" "$COLOR_08") - COLOR_09=$(convertNameAndRGBtoITerm "Ansi 8 Color" "$COLOR_09") - COLOR_10=$(convertNameAndRGBtoITerm "Ansi 9 Color" "$COLOR_10") - COLOR_11=$(convertNameAndRGBtoITerm "Ansi 10 Color" "$COLOR_11") - COLOR_12=$(convertNameAndRGBtoITerm "Ansi 11 Color" "$COLOR_12") - COLOR_13=$(convertNameAndRGBtoITerm "Ansi 12 Color" "$COLOR_13") - COLOR_14=$(convertNameAndRGBtoITerm "Ansi 13 Color" "$COLOR_14") - COLOR_15=$(convertNameAndRGBtoITerm "Ansi 14 Color" "$COLOR_15") - COLOR_16=$(convertNameAndRGBtoITerm "Ansi 15 Color" "$COLOR_16") + BACKGROUND_COLOR=$(convertNameAndRGBtoITerm "Background Color" \ + "$BACKGROUND_COLOR") + FOREGROUND_COLOR=$(convertNameAndRGBtoITerm "Foreground Color" \ + "$FOREGROUND_COLOR") + COLOR_01=$(convertNameAndRGBtoITerm "Ansi 0 Color" \ + "$COLOR_01") + COLOR_02=$(convertNameAndRGBtoITerm "Ansi 1 Color" \ + "$COLOR_02") + COLOR_03=$(convertNameAndRGBtoITerm "Ansi 2 Color" \ + "$COLOR_03") + COLOR_04=$(convertNameAndRGBtoITerm "Ansi 3 Color" \ + "$COLOR_04") + COLOR_05=$(convertNameAndRGBtoITerm "Ansi 4 Color" \ + "$COLOR_05") + COLOR_06=$(convertNameAndRGBtoITerm "Ansi 5 Color" \ + "$COLOR_06") + COLOR_07=$(convertNameAndRGBtoITerm "Ansi 6 Color" \ + "$COLOR_07") + COLOR_08=$(convertNameAndRGBtoITerm "Ansi 7 Color" \ + "$COLOR_08") + COLOR_09=$(convertNameAndRGBtoITerm "Ansi 8 Color" \ + "$COLOR_09") + COLOR_10=$(convertNameAndRGBtoITerm "Ansi 9 Color" \ + "$COLOR_10") + COLOR_11=$(convertNameAndRGBtoITerm "Ansi 10 Color" \ + "$COLOR_11") + COLOR_12=$(convertNameAndRGBtoITerm "Ansi 11 Color" \ + "$COLOR_12") + COLOR_13=$(convertNameAndRGBtoITerm "Ansi 12 Color" \ + "$COLOR_13") + COLOR_14=$(convertNameAndRGBtoITerm "Ansi 13 Color" \ + "$COLOR_14") + COLOR_15=$(convertNameAndRGBtoITerm "Ansi 14 Color" \ + "$COLOR_15") + COLOR_16=$(convertNameAndRGBtoITerm "Ansi 15 Color" \ + "$COLOR_16") - # Assemble color scheme file contents - ITERMCOLORS=''${BACKGROUND_COLOR}${FOREGROUND_COLOR}${COLOR_01}${COLOR_02}${COLOR_03}${COLOR_04}${COLOR_05}${COLOR_06}${COLOR_07}${COLOR_08}${COLOR_09}${COLOR_10}${COLOR_11}${COLOR_12}${COLOR_13}${COLOR_14}${COLOR_15}'' + # Assemble color scheme file contents + ITERMCOLORS=''${BACKGROUND_COLOR}${FOREGROUND_COLOR}${COLOR_01}${COLOR_02}${COLOR_03}${COLOR_04}${COLOR_05}${COLOR_06}${COLOR_07}${COLOR_08}${COLOR_09}${COLOR_10}${COLOR_11}${COLOR_12}${COLOR_13}${COLOR_14}${COLOR_15}'' - # Dump iTerm color scheme to file and import it by opening it - echo "${ITERMCOLORS}" > "${PROFILE_NAME}.itermcolors" - open "${PROFILE_NAME}.itermcolors" - rm "${PROFILE_NAME}.itermcolors" + # Dump iTerm color scheme to file and import it by opening it + echo "${ITERMCOLORS}" > "${PROFILE_NAME}.itermcolors" + open "${PROFILE_NAME}.itermcolors" + rm "${PROFILE_NAME}.itermcolors" } apply_gtk() { - # | =========================================== - # | Applying values to gnome/mate/tilix - # | =========================================== + # | =========================================== + # | Applying values to gnome/mate/tilix + # | =========================================== - local legacy="${1:-}" + local legacy="${1:-}" - # This is to avoid doing the profile loop definition twice - if [[ -z "${legacy}" ]]; then - CONFTOOL="${DCONF} read" - VISIBLE_NAME="visible-name" - else - CONFTOOL="${GCONF} --get" - VISIBLE_NAME="visible_name" - fi + # This is to avoid doing the profile loop definition twice + if [[ -z "${legacy}" ]]; then + CONFTOOL="${DCONF} read" + VISIBLE_NAME="visible-name" + else + CONFTOOL="${GCONF} --get" + VISIBLE_NAME="visible_name" + fi - # Check first wether profile already exists - profile_hashes=($(${CONFTOOL} "${PROFILE_LIST_KEY}" | tr "[]'," " ")) - for profile in "${profile_hashes[@]}"; do - if [[ "$(${CONFTOOL} "${BASE_DIR}${profile}/${VISIBLE_NAME}" | tr -d "'")" == "${PROFILE_NAME}" ]]; then - printf '%s\n' "Profile already exists" "Skipping..." - exit 0 - fi - done + # Check first wether profile already exists + profile_hashes=($(${CONFTOOL} "${PROFILE_LIST_KEY}" | tr "[]'," " ")) + for profile in "${profile_hashes[@]}"; do + if [[ "$(${CONFTOOL} "${BASE_DIR}${profile}/${VISIBLE_NAME}" | \ + tr -d "'")" == "${PROFILE_NAME}" ]]; then + printf '%s\n' "Profile already exists" "Skipping..." + exit 0 + fi + done - # Fallback if there is no default profile - set -- $(${CONFTOOL} ${PROFILE_LIST_KEY} | tr "[]'," " ") - : ${DEFAULT_SLUG:="$1"} + # Fallback if there is no default profile + set -- $(${CONFTOOL} ${PROFILE_LIST_KEY} | tr "[]'," " ") + : ${DEFAULT_SLUG:="$1"} - : ${PROFILE_NAME:="Default"} - : ${PROFILE_SLUG:="Default"} + : ${PROFILE_NAME:="Default"} + : ${PROFILE_SLUG:="Default"} - DEFAULT_KEY="${BASE_DIR}${DEFAULT_SLUG:-}" - PROFILE_KEY="${BASE_DIR}${PROFILE_SLUG:-}" + DEFAULT_KEY="${BASE_DIR}${DEFAULT_SLUG:-}" + PROFILE_KEY="${BASE_DIR}${PROFILE_SLUG:-}" - if [[ -z "${legacy}" ]]; then - if [[ -z "$(${DCONF} list ${BASE_DIR%:})" ]]; then - # Provide a user friendly error text if no saved profile exists, otherwise it will display "Error gconftool not found!" - # it could happen on a newly installed system. (happened on CentOS 7) - printf '%s\n' \ - "Error, no saved profiles found!" \ - "Possible fix, new a profile (Terminal > Edit > Preferences > Profiles > New, then Close) and try again." \ - "You can safely delete the created profile after the installation." - exit 1 - fi + if [[ -z "${legacy}" ]]; then + # Provide a user friendly error text if no saved profile exists, + # otherwise it will display "Error gconftool not found!" + # it could happen on a newly installed system + if [[ -z "$(${DCONF} list ${BASE_DIR%:})" ]]; then + printf '%s\n' \ + "Error, no saved profiles found!" \ + "Possible fix, new a profile (Terminal > Edit > Pref\ +erences > Profiles > New, then Close) and try again." \ + "You can safely delete the created profile after the\ +installation." + exit 1 + fi - BACKGROUND_COLOR=$(gnome_color "$BACKGROUND_COLOR") - FOREGROUND_COLOR=$(gnome_color "$FOREGROUND_COLOR") - HIGHLIGHT_BG_COLOR=$(gnome_color "$HIGHLIGHT_BG_COLOR") - HIGHLIGHT_FG_COLOR=$(gnome_color "$HIGHLIGHT_FG_COLOR") - COLOR_01=$(gnome_color "$COLOR_01") - COLOR_02=$(gnome_color "$COLOR_02") - COLOR_03=$(gnome_color "$COLOR_03") - COLOR_04=$(gnome_color "$COLOR_04") - COLOR_05=$(gnome_color "$COLOR_05") - COLOR_06=$(gnome_color "$COLOR_06") - COLOR_07=$(gnome_color "$COLOR_07") - COLOR_08=$(gnome_color "$COLOR_08") - COLOR_09=$(gnome_color "$COLOR_09") - COLOR_10=$(gnome_color "$COLOR_10") - COLOR_11=$(gnome_color "$COLOR_11") - COLOR_12=$(gnome_color "$COLOR_12") - COLOR_13=$(gnome_color "$COLOR_13") - COLOR_14=$(gnome_color "$COLOR_14") - COLOR_15=$(gnome_color "$COLOR_15") - COLOR_16=$(gnome_color "$COLOR_16") + BACKGROUND_COLOR=$(gnome_color "$BACKGROUND_COLOR") + FOREGROUND_COLOR=$(gnome_color "$FOREGROUND_COLOR") + HIGHLIGHT_BG_COLOR=$(gnome_color "$HIGHLIGHT_BG_COLOR") + HIGHLIGHT_FG_COLOR=$(gnome_color "$HIGHLIGHT_FG_COLOR") + COLOR_01=$(gnome_color "$COLOR_01") + COLOR_02=$(gnome_color "$COLOR_02") + COLOR_03=$(gnome_color "$COLOR_03") + COLOR_04=$(gnome_color "$COLOR_04") + COLOR_05=$(gnome_color "$COLOR_05") + COLOR_06=$(gnome_color "$COLOR_06") + COLOR_07=$(gnome_color "$COLOR_07") + COLOR_08=$(gnome_color "$COLOR_08") + COLOR_09=$(gnome_color "$COLOR_09") + COLOR_10=$(gnome_color "$COLOR_10") + COLOR_11=$(gnome_color "$COLOR_11") + COLOR_12=$(gnome_color "$COLOR_12") + COLOR_13=$(gnome_color "$COLOR_13") + COLOR_14=$(gnome_color "$COLOR_14") + COLOR_15=$(gnome_color "$COLOR_15") + COLOR_16=$(gnome_color "$COLOR_16") - # copy existing settings from default profile - $DCONF dump "${DEFAULT_KEY}/" | $DCONF load "${PROFILE_KEY}/" + # copy existing settings from default profile + $DCONF dump "${DEFAULT_KEY}/" | \ + $DCONF load "${PROFILE_KEY}/" - # add new copy to global list of profiles - dlist_append "${PROFILE_LIST_KEY}" "${PROFILE_SLUG#:}" + # add new copy to global list of profiles + dlist_append "${PROFILE_LIST_KEY}" "${PROFILE_SLUG#:}" - set_theme - dset palette "${LEFT_WRAPPER:-}'${COLOR_01}${PALETTE_DELIM}${COLOR_02}${PALETTE_DELIM}${COLOR_03}${PALETTE_DELIM}${COLOR_04}${PALETTE_DELIM}${COLOR_05}${PALETTE_DELIM}${COLOR_06}${PALETTE_DELIM}${COLOR_07}${PALETTE_DELIM}${COLOR_08}${PALETTE_DELIM}${COLOR_09}${PALETTE_DELIM}${COLOR_10}${PALETTE_DELIM}${COLOR_11}${PALETTE_DELIM}${COLOR_12}${PALETTE_DELIM}${COLOR_13}${PALETTE_DELIM}${COLOR_14}${PALETTE_DELIM}${COLOR_15}${PALETTE_DELIM}${COLOR_16}'${RIGHT_WRAPPER:-}" - ${LEGACY_BOLD:-} && dset allow-bold "true" # mate - else - # Append the Base16 profile to the profile list - glist_append string "${PROFILE_LIST_KEY}" "${PROFILE_SLUG}" + set_theme + dset palette "${LEFT_WRAPPER:-}'${COLOR_01}${PALETTE_DELIM}${COLOR_02}${PALETTE_DELIM}${COLOR_03}${PALETTE_DELIM}${COLOR_04}${PALETTE_DELIM}${COLOR_05}${PALETTE_DELIM}${COLOR_06}${PALETTE_DELIM}${COLOR_07}${PALETTE_DELIM}${COLOR_08}${PALETTE_DELIM}${COLOR_09}${PALETTE_DELIM}${COLOR_10}${PALETTE_DELIM}${COLOR_11}${PALETTE_DELIM}${COLOR_12}${PALETTE_DELIM}${COLOR_13}${PALETTE_DELIM}${COLOR_14}${PALETTE_DELIM}${COLOR_15}${PALETTE_DELIM}${COLOR_16}'${RIGHT_WRAPPER:-}" + ${LEGACY_BOLD:-} && dset allow-bold "true" # mate + else + # Append the Base16 profile to the profile list + glist_append string "${PROFILE_LIST_KEY}" "${PROFILE_SLUG}" - legacy_set_theme - gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" - ${LEGACY_BOLD:-} && gcset bool allow-bold "true" - fi + legacy_set_theme + gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" + ${LEGACY_BOLD:-} && gcset bool allow-bold "true" + fi } apply_guake() { - # | =========================================== - # | Applying values to guake - # | =========================================== + # | =========================================== + # | Applying values to guake + # | =========================================== - local legacy="${1:-}" - PROFILE_KEY="/apps/guake/style/font" + local legacy="${1:-}" + PROFILE_KEY="/apps/guake/style/font" - if [[ -z "${legacy}" ]]; then - dset palette "'${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}:${FOREGROUND_COLOR}:${BACKGROUND_COLOR}'" - dset palette-name "'${PROFILE_NAME}'" - dset allow-bold 'true' - else - gcset string color "${FOREGROUND_COLOR}" - gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" - gcset string palette-name "${PROFILE_NAME}" - PROFILE_KEY="/apps/guake/style/background" - gcset string color "${BACKGROUND_COLOR}" + if [[ -z "${legacy}" ]]; then + dset palette "'${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}:${FOREGROUND_COLOR}:${BACKGROUND_COLOR}'" + dset palette-name "'${PROFILE_NAME}'" + dset allow-bold 'true' + else + gcset string color "${FOREGROUND_COLOR}" + gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}" + gcset string palette-name "${PROFILE_NAME}" + PROFILE_KEY="/apps/guake/style/background" + gcset string color "${BACKGROUND_COLOR}" - fi + fi } appy_tilixschemes() { - # | =========================================== - # | Applying values to tilix colorschemes - # | =========================================== + # | =========================================== + # | Applying values to tilix colorschemes + # | =========================================== - if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then - [[ -d "${HOME}/.config/tilix/schemes" ]] || mkdir -p "${HOME}/.config/tilix/schemes" + if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then + [[ -d "${HOME}/.config/tilix/schemes" ]] || mkdir -p "${HOME}/.config/tilix/schemes" - TILIXCOLORS='{\n\t"name": "'${PROFILE_NAME}'",\n\t"comment": "Generated by Gogh",\n\t"foreground-color": "'${FOREGROUND_COLOR}'",\n\t"background-color":"'${BACKGROUND_COLOR}'",\n\t"cursor-background-color": "'${CURSOR_COLOR}'",\n\t"palette": [\n\t\t"'${COLOR_01}'",\n\t\t"'${COLOR_02}'",\n\t\t"'${COLOR_03}'",\n\t\t"'${COLOR_04}'",\n\t\t"'${COLOR_05}'",\n\t\t"'${COLOR_06}'",\n\t\t"'${COLOR_07}'",\n\t\t"'${COLOR_08}'",\n\t\t"'${COLOR_09}'",\n\t\t"'${COLOR_10}'",\n\t\t"'${COLOR_11}'",\n\t\t"'${COLOR_12}'",\n\t\t"'${COLOR_13}'",\n\t\t"'${COLOR_14}'",\n\t\t"'${COLOR_15}'",\n\t\t"'${COLOR_16}'"\n\t],\n\t"use-badge-color": false,\n\t"use-bold-color": false,\n\t"use-cursor-color": false,\n\t"use-highlight-color": false,\n\t"use-theme-colors": false\n}' - echo -e "${TILIXCOLORS}" > "${scratchdir}/${PROFILE_NAME}.json" + TILIXCOLORS='{\n\t"name": "'${PROFILE_NAME}'",\n\t"comment": "Generated by Gogh",\n\t"foreground-color": "'${FOREGROUND_COLOR}'",\n\t"background-color":"'${BACKGROUND_COLOR}'",\n\t"cursor-background-color": "'${CURSOR_COLOR}'",\n\t"palette": [\n\t\t"'${COLOR_01}'",\n\t\t"'${COLOR_02}'",\n\t\t"'${COLOR_03}'",\n\t\t"'${COLOR_04}'",\n\t\t"'${COLOR_05}'",\n\t\t"'${COLOR_06}'",\n\t\t"'${COLOR_07}'",\n\t\t"'${COLOR_08}'",\n\t\t"'${COLOR_09}'",\n\t\t"'${COLOR_10}'",\n\t\t"'${COLOR_11}'",\n\t\t"'${COLOR_12}'",\n\t\t"'${COLOR_13}'",\n\t\t"'${COLOR_14}'",\n\t\t"'${COLOR_15}'",\n\t\t"'${COLOR_16}'"\n\t],\n\t"use-badge-color": false,\n\t"use-bold-color": false,\n\t"use-cursor-color": false,\n\t"use-highlight-color": false,\n\t"use-theme-colors": false\n}' + echo -e "${TILIXCOLORS}" > "${scratchdir}/${PROFILE_NAME}.json" - # Note: Tilix does not store color scheme name in dconf - # so we have to update color palette for the current profile in order to switch to the new theme - # but only set the palette on the last loop to avoid a flashing terminal - if ((LOOP == OPTLENGTH)); then - cp -f ${scratchdir}/* "$HOME/.config/tilix/schemes/" - rm -rf "${scratchdir}" - read -r -p "All done - apply new theme? [y/N] " -n 1 TILIX_RES - if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then - PROFILE_KEY="${BASE_DIR}${DEFAULT_SLUG}" - PROFILE_NAME="$(${DCONF} read ${PROFILE_KEY}/visible-name | tr -d \')" - set_theme - dset palette "['${COLOR_01}', '${COLOR_02}', '${COLOR_03}', '${COLOR_04}', '${COLOR_05}', '${COLOR_06}', '${COLOR_07}', '${COLOR_08}', '${COLOR_09}', '${COLOR_10}', '${COLOR_11}', '${COLOR_12}', '${COLOR_13}', '${COLOR_14}', '${COLOR_15}', '${COLOR_16}']" - fi - fi + # Note: Tilix does not store color scheme name in dconf + # so we have to update color palette for the current profile in order to switch to the new theme + # but only set the palette on the last loop to avoid a flashing terminal + if ((LOOP == OPTLENGTH)); then + cp -f ${scratchdir}/* "$HOME/.config/tilix/schemes/" + rm -rf "${scratchdir}" + read -r -p "All done - apply new theme? [y/N] " -n 1 TILIX_RES + if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then + PROFILE_KEY="${BASE_DIR}${DEFAULT_SLUG}" + PROFILE_NAME="$(${DCONF} read ${PROFILE_KEY}/visible-name | tr -d \')" + set_theme + dset palette "['${COLOR_01}', '${COLOR_02}', '${COLOR_03}', '${COLOR_04}', '${COLOR_05}', '${COLOR_06}', '${COLOR_07}', '${COLOR_08}', '${COLOR_09}', '${COLOR_10}', '${COLOR_11}', '${COLOR_12}', '${COLOR_13}', '${COLOR_14}', '${COLOR_15}', '${COLOR_16}']" + fi + fi - unset PROFILE_NAME - unset PROFILE_SLUG - unset TILIXCOLORS - exit 0 - fi + unset PROFILE_NAME + unset PROFILE_SLUG + unset TILIXCOLORS + exit 0 + fi } apply_xfce4-terminal() { - # XFCE4 terminal has no profiles, instead it uses color presets - SCHEMEDIR="${HOME}/.local/share/xfce4/terminal/colorschemes" - CONFFILE="${HOME}/.config/xfce4/terminal/terminalrc" + # XFCE4 terminal has no profiles, instead it uses color presets + SCHEMEDIR="${HOME}/.local/share/xfce4/terminal/colorschemes" + CONFFILE="${HOME}/.config/xfce4/terminal/terminalrc" - if [[ ! (-w "${CONFFILE}") ]]; then - if [[ -r "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ]]; then - cp "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ${CONFFILE} - else - echo "ERROR: config file not present or not writable!" - exit 1 + if [[ ! (-w "${CONFFILE}") ]]; then + if [[ -r "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ]]; then + cp "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ${CONFFILE} + else + echo "ERROR: config file not present or not writable!" + exit 1 + fi fi - fi - [[ -d "${SCHEMEDIR}" ]] || mkdir -p "${SCHEMEDIR}" + [[ -d "${SCHEMEDIR}" ]] || mkdir -p "${SCHEMEDIR}" - F_NAME=${PROFILE_NAME// /-} - F_NAME=$(echo ${F_NAME} | tr -d ":()") - F_NAME=$(echo "${F_NAME}" | awk '{print tolower($0)}') + F_NAME=${PROFILE_NAME// /-} + F_NAME=$(echo ${F_NAME} | tr -d ":()") + F_NAME=$(echo "${F_NAME}" | awk '{print tolower($0)}') - FF_NAME="${SCHEMEDIR}/${F_NAME}.theme" + FF_NAME="${SCHEMEDIR}/${F_NAME}.theme" - touch "${FF_NAME}" + touch "${FF_NAME}" - L_COLORCURSOR="ColorCursor=${CURSOR_COLOR}" - L_COLORPALETTE="ColorPalette=${COLOR_01};${COLOR_02};${COLOR_03};${COLOR_04};${COLOR_05};${COLOR_06};${COLOR_07};${COLOR_08};${COLOR_09};${COLOR_10};${COLOR_11};${COLOR_12};${COLOR_13};${COLOR_14};${COLOR_15};${COLOR_16}" + L_COLORCURSOR="ColorCursor=${CURSOR_COLOR}" + L_COLORPALETTE="ColorPalette=${COLOR_01};${COLOR_02};${COLOR_03};${COLOR_04};${COLOR_05};${COLOR_06};${COLOR_07};${COLOR_08};${COLOR_09};${COLOR_10};${COLOR_11};${COLOR_12};${COLOR_13};${COLOR_14};${COLOR_15};${COLOR_16}" - printf '%s\n' \ - "; Generated by Gogh" \ - "; https://mayccoll.github.io/Gogh" \ - "[Scheme]" \ - "Name=${PROFILE_NAME}" \ - "ColorForeground=${FOREGROUND_COLOR}" \ - "ColorBackground=${BACKGROUND_COLOR}" \ - "${L_COLORCURSOR}" \ - "${L_COLORPALETTE}" \ - "ColorCursorUseDefault=FALSE" > ${FF_NAME} + printf '%s\n' \ + "; Generated by Gogh" \ + "; https://mayccoll.github.io/Gogh" \ + "[Scheme]" \ + "Name=${PROFILE_NAME}" \ + "ColorForeground=${FOREGROUND_COLOR}" \ + "ColorBackground=${BACKGROUND_COLOR}" \ + "${L_COLORCURSOR}" \ + "${L_COLORPALETTE}" \ + "ColorCursorUseDefault=FALSE" > ${FF_NAME} - # apply last theme in queue - # xfce4-terminal monitors its rc file and doesn't reference - # any of the themes in there. The color settings need to - # be written there directly. - if ((LOOP == OPTLENGTH)); then - read -r -p "All done - apply new theme? [y/N] " -n 1 XFCE4_APPLY_CURR_THEME - if [[ ${XFCE4_APPLY_CURR_THEME::1} =~ ^(y|Y)$ ]]; then - if grep -q "^ColorPalette=" "${CONFFILE}"; then - sed -i -r -e "s/^ColorPalette=.*/${L_COLORPALETTE}/" "${CONFFILE}" - else - echo "${L_COLORPALETTE}" >> "${CONFFILE}" - fi + # apply last theme in queue + # xfce4-terminal monitors its rc file and doesn't reference + # any of the themes in there. The color settings need to + # be written there directly. + if ((LOOP == OPTLENGTH)); then + read -r -p "All done - apply new theme? [y/N] " -n 1 XFCE4_APPLY_CURR_THEME + if [[ ${XFCE4_APPLY_CURR_THEME::1} =~ ^(y|Y)$ ]]; then + if grep -q "^ColorPalette=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorPalette=.*/${L_COLORPALETTE}/" "${CONFFILE}" + else + echo "${L_COLORPALETTE}" >> "${CONFFILE}" + fi - if grep -q "^ColorCursor=" "${CONFFILE}"; then - sed -i -r -e "s/^ColorCursor=.*/${L_COLORCURSOR}/" "${CONFFILE}" - else - echo "${L_COLORCURSOR}" >> "${CONFFILE}" - fi + if grep -q "^ColorCursor=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorCursor=.*/${L_COLORCURSOR}/" "${CONFFILE}" + else + echo "${L_COLORCURSOR}" >> "${CONFFILE}" + fi - if grep -q "^ColorForeground=" "${CONFFILE}"; then - sed -i -r -e "s/^ColorForeground=.*/ColorForeground=${FOREGROUND_COLOR}/" "${CONFFILE}" - else - echo "ColorForeground=${FOREGROUND_COLOR}" >> "${CONFFILE}" - fi + if grep -q "^ColorForeground=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorForeground=.*/ColorForeground=${FOREGROUND_COLOR}/" "${CONFFILE}" + else + echo "ColorForeground=${FOREGROUND_COLOR}" >> "${CONFFILE}" + fi - if grep -q "^ColorBackground=" "${CONFFILE}"; then - sed -i -r -e "s/^ColorBackground=.*/ColorBackground=${BACKGROUND_COLOR}/" "${CONFFILE}" - else - echo "ColorBackground=${BACKGROUND_COLOR}" >> "${CONFFILE}" - fi + if grep -q "^ColorBackground=" "${CONFFILE}"; then + sed -i -r -e "s/^ColorBackground=.*/ColorBackground=${BACKGROUND_COLOR}/" "${CONFFILE}" + else + echo "ColorBackground=${BACKGROUND_COLOR}" >> "${CONFFILE}" + fi - if grep -q "^ColorCursorUseDefault=FALSE" "${CONFFILE}"; then - true - else - echo "ColorCursorUseDefault=FALSE" >> "${CONFFILE}" - fi + if grep -q "^ColorCursorUseDefault=FALSE" "${CONFFILE}"; then + true + else + echo "ColorCursorUseDefault=FALSE" >> "${CONFFILE}" + fi + fi fi - fi - unset SCHEMEDIR - unset CONFFILE - unset PROFILE_NAME - unset F_NAME - unset FF_NAME - unset L_COLORCURSOR - unset L_COLORPALETTE - exit 0 + unset SCHEMEDIR + unset CONFFILE + unset PROFILE_NAME + unset F_NAME + unset FF_NAME + unset L_COLORCURSOR + unset L_COLORPALETTE + exit 0 } [[ -n "${UUIDGEN}" ]] && PROFILE_SLUG="$(uuidgen)" case "${TERMINAL}" in - pantheon-terminal|io.elementary.t* ) - if [[ "${TERMINAL}" == "pantheon-terminal" ]]; then - PROFILE_KEY="org.pantheon.terminal.settings" - else - PROFILE_KEY="io.elementary.terminal.settings" - fi - apply_elementary - ;; +pantheon-terminal|io.elementary.t* ) + if [[ "${TERMINAL}" == "pantheon-terminal" ]]; then + PROFILE_KEY="org.pantheon.terminal.settings" + else + PROFILE_KEY="io.elementary.terminal.settings" + fi + apply_elementary + ;; - iTerm.app ) - apply_darwin - ;; +iTerm.app ) + apply_darwin + ;; - mintty ) - apply_cygwin - ;; +mintty ) + apply_cygwin + ;; - guake ) - if [[ -n "$(${DCONF} list /apps/guake/style/)" ]]; then - apply_guake - else - apply_guake legacy - fi - ;; +guake ) + if [[ -n "$(${DCONF} list /apps/guake/style/)" ]]; then + apply_guake + else + apply_guake legacy + fi + ;; - gnome-terminal* ) - if [[ -n "$(${DCONF} list /org/gnome/terminal/)" ]]; then - BASE_DIR="/org/gnome/terminal/legacy/profiles:/:" - PROFILE_LIST_KEY="${BASE_DIR%:}list" - PROFILE_SLUG="${PROFILE_SLUG}" +gnome-terminal* ) + if [[ -n "$(${DCONF} list /org/gnome/terminal/)" ]]; then + BASE_DIR="/org/gnome/terminal/legacy/profiles:/:" + PROFILE_LIST_KEY="${BASE_DIR%:}list" + PROFILE_SLUG="${PROFILE_SLUG}" - # Note -- ${BASE_DIR%s} is a workaround to avoid doing additional conditional testing for existing profiles - # if terminal is set to gnome-terminal - : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR%:}default | tr -d \')"} + # Note -- ${BASE_DIR%s} is a workaround to avoid doing additional conditional testing for existing profiles + # if terminal is set to gnome-terminal + : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR%:}default | tr -d \')"} - LEFT_WRAPPER="[" - RIGHT_WRAPPER="]" - PALETTE_DELIM="', '" + LEFT_WRAPPER="[" + RIGHT_WRAPPER="]" + PALETTE_DELIM="', '" - apply_gtk - else - BASE_DIR="/apps/gnome-terminal/profiles/" - PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile_list" - LEGACY_BOLD=true + apply_gtk + else + BASE_DIR="/apps/gnome-terminal/profiles/" + PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile_list" + LEGACY_BOLD=true - : ${DEFAULT_SLUG:="$(${GCONF} read ${BASE_DIR}default_profile)"} + : ${DEFAULT_SLUG:="$(${GCONF} read ${BASE_DIR}default_profile)"} - apply_gtk legacy - fi - ;; + apply_gtk legacy + fi + ;; - mate-terminal ) - BASE_DIR="/org/mate/terminal/profiles/" - PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile-list" - LEGACY_BOLD=true +mate-terminal ) + BASE_DIR="/org/mate/terminal/profiles/" + PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile-list" + LEGACY_BOLD=true - : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR/profiles/global}default-profile | tr -d \')"} + : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR/profiles/global}default-profile | tr -d \')"} - PALETTE_DELIM=":" + PALETTE_DELIM=":" - apply_gtk - ;; + apply_gtk + ;; - tilix ) - BASE_DIR="/com/gexperts/Tilix/profiles/" - PROFILE_LIST_KEY="${BASE_DIR}list" +tilix ) + BASE_DIR="/com/gexperts/Tilix/profiles/" + PROFILE_LIST_KEY="${BASE_DIR}list" - : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR}default | tr -d \')"} + : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR}default | tr -d \')"} - LEFT_WRAPPER="[" - RIGHT_WRAPPER="]" - PALETTE_DELIM="', '" + LEFT_WRAPPER="[" + RIGHT_WRAPPER="]" + PALETTE_DELIM="', '" - appy_tilixschemes - apply_gtk - ;; + appy_tilixschemes + apply_gtk + ;; - xfce4-terminal ) - apply_xfce4-terminal - ;; +xfce4-terminal ) + apply_xfce4-terminal + ;; - * ) - printf '%s\n' \ - "Unsupported terminal!" \ - "" \ - "Supported terminals:" \ - " mintty and deriviates" \ - " guake" \ - " iTerm2" \ - " elementary terminal (pantheon/elementary)" \ - " mate-terminal" \ - " gnome-terminal" \ - " tilix" \ - " xfce4-terminal" \ - "" \ - "If you believe you have recieved this message in error," \ - "try manually setting \`TERMINAL', hint: ps -h -o comm -p \$PPID" - exit 1 - ;; +* ) + printf '%s\n' \ + "Unsupported terminal!" \ + "" \ + "Supported terminals:" \ + " mintty and deriviates" \ + " guake" \ + " iTerm2" \ + " elementary terminal (pantheon/elementary)" \ + " mate-terminal" \ + " gnome-terminal" \ + " tilix" \ + " xfce4-terminal" \ + "" \ + "If you believe you have recieved this message in error," \ + "try manually setting \`TERMINAL', hint: ps -h -o comm -p \$PPID" + exit 1 + ;; esac diff --git a/audio/noise-cancel.sh b/audio/noise-cancel.sh index a9fd86c..6feea85 100755 --- a/audio/noise-cancel.sh +++ b/audio/noise-cancel.sh @@ -1,6 +1,7 @@ # Microphone Realtime background noise reduction script # author Luigi Maselli - https://grigio.org licence: AS-IS -# credits: http://askubuntu.com/questions/18958/realtime-noise-removal-with-pulseaudio +# credits: +# http://askubuntu.com/questions/18958/realtime-noise-removal-with-pulseaudio # run as: sudo && pulseaudio -k sudo cp /etc/pulse/default.pa /etc/pulse/default.pa.bak @@ -8,4 +9,4 @@ sudo cat <> /etc/pulse/default.pa load-module module-echo-cancel source_name=noechosource sink_name=noechosink set-default-source noechosource set-default-sink noechosink -EOT \ No newline at end of file +EOT diff --git a/i3/detached.sh b/i3/detached.sh index 6b569ac..6759ef5 100755 --- a/i3/detached.sh +++ b/i3/detached.sh @@ -1,3 +1,10 @@ #!/bin/sh -xrandr --output DP-2-1 --off --output DP-2-2 --off --output DP-2-3 --off --output eDP-1 --primary --mode 1920x1080 --pos 0x0 --rotate normal --output HDMI-2 --off --output HDMI-1 --off --output DP-2 --off --output DP-1 --off +xrandr \ +--output DP-2-1 --off \ +--output DP-2-2 --off \ +--output DP-2-3 --off \ +--output eDP-1 --primary --mode 1920x1080 --pos 0x0 --rotate normal \ +--output HDMI-2 --off \ +--output HDMI-1 --off --output DP-2 --off --output DP-1 --off + echo "detached" > ~/.config/screenlayout/i3.current diff --git a/i3/home.sh b/i3/home.sh index 64a3659..1777381 100755 --- a/i3/home.sh +++ b/i3/home.sh @@ -1,3 +1,12 @@ #!/bin/sh -xrandr --output DP-2-1 --mode 1366x768 --pos 0x0 --rotate left --output DP-2-2 --mode 1920x1200 --pos 768x0 --rotate normal --output DP-2-3 --off --output eDP-1 --primary --mode 1920x1080 --pos 768x1200 --rotate normal --output HDMI-2 --off --output HDMI-1 --off --output DP-2 --off --output DP-1 --off +xrandr \ +--output DP-2-1 --mode 1366x768 --pos 0x0 --rotate left \ +--output DP-2-2 --mode 1920x1200 --pos 768x0 --rotate normal \ +--output DP-2-3 --off \ +--output eDP-1 --primary --mode 1920x1080 --pos 768x1200 --rotate normal \ +--output HDMI-2 --off \ +--output HDMI-1 --off \ +--output DP-2 --off \ +--output DP-1 --off + echo "home" > ~/.config/screenlayout/i3.current diff --git a/i3/i3move.sh b/i3/i3move.sh index 43e6873..d3e90b8 100755 --- a/i3/i3move.sh +++ b/i3/i3move.sh @@ -4,25 +4,25 @@ LAYOUT=`cat ~/.config/screenlayout/i3.current` MIDDLE="eDP-1" if [[ $LAYOUT == 'home' ]]; then - RIGHT="DP-2-2" - LEFT="DP-2-1" + RIGHT="DP-2-2" + LEFT="DP-2-1" elif [[ $LAYOUT == 'work' ]]; then - RIGHT="DP-2-2" - LEFT="DP-2-1" + RIGHT="DP-2-2" + LEFT="DP-2-1" elif [[ $LAYOUT == '3' ]]; then - MIDDLE="DP-2-2" - LEFT="DP-2-1" - RIGHT="eDP-1" + MIDDLE="DP-2-2" + LEFT="DP-2-1" + RIGHT="eDP-1" else - echo "No external displays connected" + echo "No external displays connected" fi if [[ $1 == 'right' ]]; then - i3 move workspace to output $RIGHT + i3 move workspace to output $RIGHT elif [[ $1 == 'middle' ]]; then - i3 move workspace to output $MIDDLE + i3 move workspace to output $MIDDLE elif [[ $1 == 'left' ]]; then - i3 move workspace to output $LEFT + i3 move workspace to output $LEFT else - echo "Invalid direction. Requires either 'up', 'left', or 'middle'" + echo "Invalid direction. Requires either 'up', 'left', or 'middle'" fi diff --git a/i3/work.sh b/i3/work.sh index cdf7bbb..7d060bf 100755 --- a/i3/work.sh +++ b/i3/work.sh @@ -1,3 +1,12 @@ #!/bin/sh -xrandr --output DP-2-1 --mode 1920x1080 --pos 0x0 --rotate left --output DP-2-2 --mode 1920x1080 --pos 1080x0 --rotate normal --output DP-2-3 --off --output eDP-1 --primary --mode 1920x1080 --pos 1080x1080 --rotate normal --output HDMI-2 --off --output HDMI-1 --off --output DP-2 --off --output DP-1 --off +xrandr \ +--output DP-2-1 --mode 1920x1080 --pos 0x0 --rotate left \ +--output DP-2-2 --mode 1920x1080 --pos 1080x0 --rotate normal \ +--output DP-2-3 --off \ +--output eDP-1 --primary --mode 1920x1080 --pos 1080x1080 --rotate normal \ +--output HDMI-2 --off \ +--output HDMI-1 --off \ +--output DP-2 --off \ +--output DP-1 --off + echo "work" > ~/.config/screenlayout/i3.current diff --git a/rofi/drun.sh b/rofi/drun.sh index afd9659..616818d 100755 --- a/rofi/drun.sh +++ b/rofi/drun.sh @@ -4,7 +4,7 @@ ROFI=$(pgrep -c rofi | cut -b 1) echo $ROFI if [[ "$ROFI" -eq "0" ]]; then - rofi -config /home/jpm/.config/rofi/config -show drun + rofi -config /home/jpm/.config/rofi/config -show drun else - killall rofi 2&>1 /dev/null + killall rofi 2&>1 /dev/null fi diff --git a/rofi/rofi-openvpn.sh b/rofi/rofi-openvpn.sh index 7cf8db3..d83eaf4 100755 --- a/rofi/rofi-openvpn.sh +++ b/rofi/rofi-openvpn.sh @@ -5,25 +5,25 @@ res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) if [ $res = "Connection" ]; then - /usr/bin/uxterm -e 'sudo /usr/bin/nmtui' + /usr/bin/uxterm -e 'sudo /usr/bin/nmtui' elif [ $res = "John.Me.tz" ]; then - sudo /usr/bin/systemctl stop openvpn-client@mailcleaner - sudo /usr/bin/systemctl restart wg-quick@wg0 -elif [ $res = "MailCleaner" ]; then - sudo /usr/bin/systemctl stop wg-quick@wg0 - sudo /usr/bin/systemctl restart openvpn-client@mailcleaner -elif [ $res = "Disconnect" ]; then - sudo /usr/bin/systemctl stop openvpn-client@mailcleaner - sudo /usr/bin/systemctl stop wg-quick@wg0 -elif [ $res = "Restart" ]; then - if [ "`ip addr show wg0 2> /dev/null`" != "" ]; then + sudo /usr/bin/systemctl stop openvpn-client@mailcleaner sudo /usr/bin/systemctl restart wg-quick@wg0 - fi - if [ "`ip addr show tun0 2> /dev/null`" != "" ]; then +elif [ $res = "MailCleaner" ]; then + sudo /usr/bin/systemctl stop wg-quick@wg0 sudo /usr/bin/systemctl restart openvpn-client@mailcleaner - fi +elif [ $res = "Disconnect" ]; then + sudo /usr/bin/systemctl stop openvpn-client@mailcleaner + sudo /usr/bin/systemctl stop wg-quick@wg0 +elif [ $res = "Restart" ]; then + if [ "`ip addr show wg0 2> /dev/null`" != "" ]; then + sudo /usr/bin/systemctl restart wg-quick@wg0 + fi + if [ "`ip addr show tun0 2> /dev/null`" != "" ]; then + sudo /usr/bin/systemctl restart openvpn-client@mailcleaner + fi else - exit + exit fi # Waybar sometimes doesn't update with the VPN IP, for whatever reason. Restart it. diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh index 12fdcdd..1af68dc 100755 --- a/rofi/rofi-power-menu.sh +++ b/rofi/rofi-power-menu.sh @@ -4,39 +4,39 @@ # Determine if Sway or i3 if [ -z ${SWAYSOCK+x} ]; then - WM="i3" + WM="i3" else - WM="sway" + WM="sway" fi if [[ $WM == 'i3' ]]; then - res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) + res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) else - res=$(echo "🔒 Lock|↩ Logout|↻ Reload Sway|↻ Reload Waybar|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) + res=$(echo "🔒 Lock|↩ Logout|↻ Reload Sway|↻ Reload Waybar|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) fi if [ "$res" == "🔒 Lock" ]; then - ${WM}lock -c 323232 + ${WM}lock -c 323232 elif [ "$res" == "↩ Logout" ]; then - # Prevent auto-login - rm /home/jpm/.config/last_login_gui - ${WM} exit + # Prevent auto-login + rm /home/jpm/.config/last_login_gui + ${WM} exit elif [ "$res" == "↻ Reload i3" ]; then - i3 reload + i3 reload elif [ "$res" == "↹ Restart i3" ]; then - i3 restart + i3 restart elif [ "$res" == "↻ Reload Sway" ]; then - sway reload + sway reload elif [ "$res" == "↻ Reload Waybar" ]; then - # Need to integrate with sway/displays.pl for alternative outputs - /home/jpm/scripts/sway/displays.pl -w + # Need to integrate with sway/displays.pl for alternative outputs + /home/jpm/scripts/sway/displays.pl -w elif [ "$res" == "🡙 Reboot" ]; then - rm $SSH_AUTH_SOCK - sudo systemctl reboot -i + rm $SSH_AUTH_SOCK + sudo systemctl reboot -i elif [ "$res" == "⏻ Shutdown" ]; then - rm $SSH_AUTH_SOCK - sudo systemctl poweroff -i + rm $SSH_AUTH_SOCK + sudo systemctl poweroff -i elif [ "$res" == "↯ Hibernate" ]; then - sudo systemctl hibernate -i + sudo systemctl hibernate -i fi exit 0 diff --git a/rofi/rofi-send-to-kodi.sh b/rofi/rofi-send-to-kodi.sh index 735b552..9b3bd1e 100755 --- a/rofi/rofi-send-to-kodi.sh +++ b/rofi/rofi-send-to-kodi.sh @@ -1,5 +1,6 @@ #!/bin/bash -INPUT="$(rofi -dmenu -i -p 'Kodi:' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100)" +INPUT="$(rofi -dmenu -i -p 'Kodi:' "" -columns 1 -rows 7 -width 32 -l 1 \ + -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100)" /home/jpm/scripts/send-to-kodi.sh $INPUT 2>&1 /dev/null diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh index c46ce99..1e06f14 100755 --- a/rofi/rofi-ssh-menu.sh +++ b/rofi/rofi-ssh-menu.sh @@ -1,28 +1,33 @@ #!/bin/bash -res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|kipary.mailcleaner.net|media.lan.john.me.tz|pipcam.lan.john.me.tz|therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -yoffset 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) +res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|\ +kipary.mailcleaner.net|media.lan.john.me.tz|pipcam.lan.john.me.tz|\ +therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz" | \ +rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config \ +/home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ +-padding 12 -opacity 100 -auto-select -no-fullscreen) if [ $res = "john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs w' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs w' elif [ $res = "root@john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs r' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs r' elif [ $res = "shb.ng" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs s' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs s' elif [ $res = "kipary.mailcleaner.net" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs d' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs d' elif [ $res = "camera.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs c' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs c' elif [ $res = "hud.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs h' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs h' elif [ $res = "media.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs m' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs m' elif [ $res = "programmer.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs p' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs p' elif [ $res = "t470s.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs l' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs l' elif [ $res = "therm.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs t' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs t' elif [ $res = "vm.lan.john.me.tz" ]; then - /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs v' + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs v' fi exit 0 diff --git a/rofi/sway-alt-tab.sh b/rofi/sway-alt-tab.sh index 032500e..bc1f56b 100755 --- a/rofi/sway-alt-tab.sh +++ b/rofi/sway-alt-tab.sh @@ -9,10 +9,10 @@ sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | rofi -dmenu -config ~/.config/rofi/sidebar.rasi | { -read -r + read -r -id=`echo $REPLY | rev | cut -d' ' -f1 | rev` + id=`echo $REPLY | rev | cut -d' ' -f1 | rev` -swaymsg "[con_id=$id]" focus + swaymsg "[con_id=$id]" focus } diff --git a/send-to-kodi.sh b/send-to-kodi.sh index 9b41bac..e538f01 100755 --- a/send-to-kodi.sh +++ b/send-to-kodi.sh @@ -14,7 +14,7 @@ local_port=12345 show_help() { - cat</dev/null; then - zenity --error --ellipsize --text "$*" - else - echo "$*" 1>&2 - fi + if type zenity &>/dev/null; then + zenity --error --ellipsize --text "$*" + else + echo "$*" 1>&2 + fi - exit 1 + exit 1 } send_json() { - curl \ - ${user:+--user "$user:$pass"} \ - -X POST \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","method":"Player.Open","params":{"item":{"file":"'"$1"'"}},"id":1}' \ - http://$host:$port/jsonrpc \ - || error "Failed to send link - is Kodi running?" + curl \ + ${user:+--user "$user:$pass"} \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"Player.Open","params":{"item":{"file":"'"$1"'"}},"id":1}' \ + http://$host:$port/jsonrpc \ + || error "Failed to send link - is Kodi running?" } ytplugin='plugin://plugin.video.youtube/?action=play_video&videoid=' @@ -61,30 +61,35 @@ ytplugin='plugin://plugin.video.youtube/?action=play_video&videoid=' # Dialog box? input=$1 until [[ $input ]]; do - input="$(zenity --entry --title "Send to Kodi" --text "Paste a video link here")" || exit + input="$(zenity --entry --title "Send to Kodi" --text \ + "Paste a video link here")" || exit done if [[ $input =~ ^file:// ]]; then - # Remove file:// and carrige return (\r) at the end - input="$(sed 's%^file://%%;s/\r$//' <<< "$input")" + # Remove file:// and carrige return (\r) at the end + input="$(sed 's%^file://%%;s/\r$//' <<< "$input")" fi # Get URL for... # Local media if [[ -e $input ]]; then - type nc &>/dev/null || error "netcat required" - [[ $local_hostname && $local_port ]] || error "Please set local hostname and port in configuration" + type nc &>/dev/null || error "netcat required" + [[ $local_hostname && $local_port ]] || \ + error "Please set local hostname and port in configuration" - # Start netcat in background and kill it when we exit - nc -lp $local_port < "$input" & - trap "kill $!" EXIT + # Start netcat in background and kill it when we exit + nc -lp $local_port < "$input" & + trap "kill $!" EXIT - url="tcp://$local_hostname:$local_port" + url="tcp://$local_hostname:$local_port" # youtube.com / youtu.be elif [[ $input =~ ^https?://(www\.)?youtu(\.be/|be\.com/watch\?v=) ]]; then - url="$ytplugin$(sed 's/.*\(youtu\.be\/\|[&?]v=\)\([a-zA-Z0-9_-]\+\).*/\2/' <<< "$input")" + url="$ytplugin$(\ + sed 's/.*\(youtu\.be\/\|[&?]v=\)\([a-zA-Z0-9_-]\+\).*/\2/'\ + <<< "$input"\ + )" # Playable formats elif [[ $input =~ \.(mp4|mkv|mov|avi|flv|wmv|asf|mp3|flac|mka|m4a|aac|ogg|pls|jpg|png|gif|jpeg|tiff)(\?.*)?$ ]]; then @@ -92,8 +97,9 @@ elif [[ $input =~ \.(mp4|mkv|mov|avi|flv|wmv|asf|mp3|flac|mka|m4a|aac|ogg|pls|jp # Youtube-dl else - type youtube-dl &>/dev/null || error "youtube-dl required" - url="$(youtube-dl -gf best "$input")" || error "No videos found, or site not supported by youtube-dl" + type youtube-dl &>/dev/null || error "youtube-dl required" + url="$(youtube-dl -gf best "$input")" || \ + error "No videos found, or site not supported by youtube-dl" fi [[ $url ]] && send_json "$url" diff --git a/sway/displays.pl b/sway/displays.pl index 8d9d3c4..7ddc06f 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -45,10 +45,10 @@ my $last = "$ENV{'HOME'}/.config/last_display"; # $ swaymsg -t get_outputs # Output eDP-1 'Unknown 0x057D *0x00000000*' my %outputs = ( - '0x00000101' => 'Sam', - '3CQ4342S6W' => 'HP-1', - '3CQ3310Q1Q' => 'HP-2', - '0x00000000' => 'LVDS' + '0x00000101' => 'Sam', + '3CQ4342S6W' => 'HP-1', + '3CQ3310Q1Q' => 'HP-2', + '0x00000000' => 'LVDS' ); ######################################################################## @@ -59,90 +59,90 @@ my %outputs = ( # Second-level keys are the display friendly-names, above # Third-level are the actual settings for that display my %configs = ( - 'detached' => { - 'HP-1' => { - 'on' => 0 + 'detached' => { + 'HP-1' => { + 'on' => 0 + }, + 'HP-2' => { + 'on' => 0 + }, + 'Sam' => { + 'on' => 0 + }, + 'LVDS' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 0, + 'y' => 0, + 'rotate' => 0, + 'waybar' => 'bottom' + } }, - 'HP-2' => { - 'on' => 0 + 'stacked' => { + 'Sam' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 960, + 'y' => 0, + 'rotate' => 0, + 'waybar' => 'bottom' + }, + 'HP-1' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 0, + 'y' => 1200, + 'rotate' => 0, + 'waybar' => 'top' + }, + 'HP-2' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 1920, + 'y' => 1200, + 'rotate' => 0, + 'waybar' => 'top' + }, + 'LVDS' => { + 'on' => 0 + } }, - 'Sam' => { - 'on' => 0 - }, - 'LVDS' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 0, - 'y' => 0, - 'rotate' => 0, - 'waybar' => 'bottom' + 'sidebyside' => { + 'HP-1' => { + 'on' => 1, + 'width' => 1080, + 'height' => 1920, + 'x' => 0, + 'y' => 225, + 'rotate' => 270, + 'waybar' => 'top' + }, + 'Sam' => { + 'on' => 1, + 'width' => 1200, + 'height' => 1920, + 'x' => 1080, + 'y' => 0, + 'rotate' => 90, + 'waybar' => 'top' + }, + 'HP-2' => { + 'on' => 1, + 'width' => 1080, + 'height' => 1920, + 'x' => 2280, + 'y' => 225, + 'rotate' => 90, + 'waybar' => 'top' + }, + 'LVDS' => { + 'on' => 0, + } } - }, - 'stacked' => { - 'Sam' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 960, - 'y' => 0, - 'rotate' => 0, - 'waybar' => 'bottom' - }, - 'HP-1' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 0, - 'y' => 1200, - 'rotate' => 0, - 'waybar' => 'top' - }, - 'HP-2' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 1920, - 'y' => 1200, - 'rotate' => 0, - 'waybar' => 'top' - }, - 'LVDS' => { - 'on' => 0 - } - }, - 'sidebyside' => { - 'HP-1' => { - 'on' => 1, - 'width' => 1080, - 'height' => 1920, - 'x' => 0, - 'y' => 225, - 'rotate' => 270, - 'waybar' => 'top' - }, - 'Sam' => { - 'on' => 1, - 'width' => 1200, - 'height' => 1920, - 'x' => 1080, - 'y' => 0, - 'rotate' => 90, - 'waybar' => 'top' - }, - 'HP-2' => { - 'on' => 1, - 'width' => 1080, - 'height' => 1920, - 'x' => 2280, - 'y' => 225, - 'rotate' => 90, - 'waybar' => 'top' - }, - 'LVDS' => { - 'on' => 0, - } - } ); ######################################################################## @@ -156,34 +156,37 @@ my $waybar_only = 0; my $config; if (scalar(@ARGV)) { - while (@ARGV) { - my $arg = shift; - if ($arg eq "-w") { - $waybar_only = 1; - } else { - if (defined $config) { - die "Too many arguments.\n"; - } - $config = $arg; + while (@ARGV) { + my $arg = shift; + if ($arg eq "-w") { + $waybar_only = 1; + } else { + if (defined $config) { + die "Too many arguments.\n"; + } + $config = $arg; + } } - } } # Get previous config if one is not provided unless (defined $config) { - open(my $fh, '<', $last) || die "Config name not provided and failed to open $last\n"; - $config = <$fh>; - close($fh); - chomp $config; + open(my $fh, '<', $last) || + die "Config name not provided and failed to open $last\n"; + $config = <$fh>; + close($fh); + chomp $config; } # Bail if requested config doesn't exist unless (defined $configs{$config}) { - die "$config is not a defined configuration: " . join(', ', keys %configs) . "\n"; + die "$config is not a defined configuration: " + . join(', ', keys %configs) . "\n"; } # Write config that is to be used so that it can be recovered as default -open(my $fh, '>', $last) || print STDERR "Config name cannot be written to $last\n"; +open(my $fh, '>', $last) || + print STDERR "Config name cannot be written to $last\n"; print $fh $config; close($fh); @@ -199,72 +202,77 @@ my $on; my @off; for (my $i = 0; $i < scalar(@$displays); $i++) { - # If a display is found without any settings, print error and turn it off - unless (defined $configs{$config}{$outputs{$displays->[$i]->{serial}}}) { - print STDERR "Output $displays->[$i]->{name} ($displays->[$i]->{serial}) found without defined function. Disabling.\n"; - push @off, $displays->[$i]->{name}; - next; - } + # If a display is found without any settings print error and turn it off + unless (defined $configs{$config}{$outputs{$displays->[$i]->{serial}}}){ + print STDERR "Output $displays->[$i]->{name} (" + . $displays->[$i]->{serial} + . ") found without defined function. Disabling.\n"; + push @off, $displays->[$i]->{name}; + next; + } - # If display is enabled, copy all of the desired settings - if ($configs{$config}{$outputs{$displays->[$i]->{serial}}}{on}) { - $on->{$outputs{$displays->[$i]->{serial}}} = $configs{$config}{$outputs{$displays->[$i]->{serial}}}; - $on->{$outputs{$displays->[$i]->{serial}}}{output} = $displays->[$i]->{name}; - # Otherwise simply list it for disabling - } else { - push @off, $displays->[$i]->{name}; - } + # If display is enabled, copy all of the desired settings + if ($configs{$config}{$outputs{$displays->[$i]->{serial}}}{on}) { + $on->{$outputs{$displays->[$i]->{serial}}} = + $configs{$config}{$outputs{$displays->[$i]->{serial}}}; + $on->{$outputs{$displays->[$i]->{serial}}}{output} = + $displays->[$i]->{name}; + # Otherwise simply list it for disabling + } else { + push @off, $displays->[$i]->{name}; + } } # Skip enabling/disabling displays if only running waybar (re)start unless ($waybar_only) { - # Number of simultaneous outputs is limited by gpu, so disabled displays first - foreach (@off) { + # Number of simultaneous outputs is limited by gpu, so disabled displays + # first + foreach (@off) { - # Sway returns status as JSON - my $res_raw = `sway output $_ disable`; - my $res = $json->decode($res_raw)->[0]; + # Sway returns status as JSON + my $res_raw = `sway output $_ disable`; + my $res = $json->decode($res_raw)->[0]; + + # If failed, print to STDERR + unless ($res->{success}) { + print STDERR "Error ($res->{error}) in command 'sway" + . "output $_ disable'\n"; + } - # If failed, print to STDERR - unless ($res->{success}) { - print STDERR "Error ($res->{error}) in command 'sway output $_ disable'\n"; } - - } } # Kill existing Waybars require Proc::ProcessTable; my $t = new Proc::ProcessTable; foreach my $p ( @{ $t->table } ) { - my $cmndline = $p->{'cmndline'}; - $cmndline =~ s/\s*$//g; - if ($cmndline =~ /^waybar.*/) { - # Never kill this process - if ($p->{'pid'} == $$) { - next; - # SIGKILL match - # TODO BUG: when multiple processes are running, some respawn with new PIDs. IDK why? - } else { - $p->kill(9); + my $cmndline = $p->{'cmndline'}; + $cmndline =~ s/\s*$//g; + if ($cmndline =~ /^waybar.*/) { + # Never kill this process + if ($p->{'pid'} == $$) { + next; + } else { + $p->kill(9); + } } - } } # Load in config template my $template; if (open (my $fh, '<', $waybar_template)) { - while (<$fh>) { - $template .= $_; - } - close $fh; - chomp $template; + while (<$fh>) { + $template .= $_; + } + close $fh; + chomp $template; } else { - print STDERR "Failed to load template $waybar_template\n"; + print STDERR "Failed to load template $waybar_template\n"; } -# If template is already set up as an array, remove the square brackets so that we can concatenate multiple displays +# If template is already set up as an array, remove the square brackets so that +# we can concatenate multiple displays $template =~ s/^[^\[\{]*\[(.*)\]$/$1/s; # Setup waybar config file @@ -273,52 +281,57 @@ my $waybar = ''; # Configure each enabled display foreach my $out (keys %$on) { - unless ($waybar_only) { - # Build command, starting by enabling and powering on - my $cmd = "sway output $on->{$out}->{output} enable dpms on"; + unless ($waybar_only) { + # Build command, starting by enabling and powering on + my $cmd = "sway output $on->{$out}->{output} enable dpms on"; - # If additional options are provided, add them to command - if (defined $on->{$out}->{rotate}) { - $cmd .= " transform $on->{$out}->{rotate}"; - } - if (defined $on->{$out}->{x} && defined $on->{$out}->{y}) { - $cmd .= " position $on->{$out}->{x} $on->{$out}->{y}"; - } - if (defined $on->{$out}->{width} && defined $on->{$out}->{height}) { - $cmd .= " mode $on->{$out}->{width}x$on->{$out}->{height}"; + # If additional options are provided, add them to command + if (defined $on->{$out}->{rotate}) { + $cmd .= " transform $on->{$out}->{rotate}"; + } + if (defined $on->{$out}->{x} && defined $on->{$out}->{y}) { + $cmd .= " position $on->{$out}->{x} $on->{$out}->{y}"; + } + if (defined $on->{$out}->{width} && + defined $on->{$out}->{height} ) + { + $cmd .= " mode $on->{$out}->{width}x$on->{$out}->{height}"; + } + + # Sway returns status as JSON + my $res_raw = `$cmd`; + my $res = $json->decode($res_raw)->[0]; + + # If failed, print to STDERR + unless ($res->{success}) { + print STDERR "Error ($res->{error}) in command '$cmd'\n"; + } } - # Sway returns status as JSON - my $res_raw = `$cmd`; - my $res = $json->decode($res_raw)->[0]; + # Skip waybar setup if template failed to be loaded + if ( (defined $template) && + (defined $on->{$out}->{waybar}) && + ($on->{$out}->{waybar} =~ m/(top|bottom|left|right)/) ) + { + + # If there's already a display set up, add a comma + unless ($waybar eq '') { + $waybar .= ','; + } + + $waybar .= $template; + + # Replace basic preferences + $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; + $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; + if (defined $on->{$out}->{width}) { + $waybar =~ s/__WIDTH__/$on->{$out}->{width}/; + # If width is not set, comment that line out to use default + } else { + $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; + } - # If failed, print to STDERR - unless ($res->{success}) { - print STDERR "Error ($res->{error}) in command '$cmd'\n"; } - } - - # Skip waybar setup if template failed to be loaded - if ( (defined $template) && (defined $on->{$out}->{waybar}) && ($on->{$out}->{waybar} =~ m/(top|bottom|left|right)/) ) { - - # If there's already a display set up, add a comma - unless ($waybar eq '') { - $waybar .= ','; - } - - $waybar .= $template; - - # Replace basic preferences - $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; - $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; - if (defined $on->{$out}->{width}) { - $waybar =~ s/__WIDTH__/$on->{$out}->{width}/; - # If width is not set, comment that line out to use default - } else { - $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; - } - - } } # Restore array formatting @@ -327,16 +340,16 @@ $waybar = '[' . $waybar . ']'; # Start Waybar as fork my $pid = fork; unless ($pid) { - open STDIN, '/dev/null'; - open STDOUT, '>>/dev/null'; - open STDERR, '>>/dev/null'; - # Write config to a temporary file - my $tmp = $waybar_temporary . "/waybar-" . time() .".config"; - open ($fh, '>', $tmp); - print $fh $waybar; - close $fh; - `nohup waybar --config=$tmp`; + open STDIN, '/dev/null'; + open STDOUT, '>>/dev/null'; + open STDERR, '>>/dev/null'; + # Write config to a temporary file + my $tmp = $waybar_temporary . "/waybar-" . time() .".config"; + open ($fh, '>', $tmp); + print $fh $waybar; + close $fh; + `nohup waybar --config=$tmp`; - # Remove config - unlink $tmp; + # Remove config + unlink $tmp; } diff --git a/sway/gammastep.pl b/sway/gammastep.pl index 3d71179..cc252c5 100755 --- a/sway/gammastep.pl +++ b/sway/gammastep.pl @@ -16,27 +16,28 @@ my $lat_lon = fetch_lat_lon($ua, $json, $location); my $pid = fork; unless ($pid) { - open STDIN, '/dev/null'; - open STDOUT, '>>/dev/null'; - open STDERR, '>>/dev/null'; + open STDIN, '/dev/null'; + open STDOUT, '>>/dev/null'; + open STDERR, '>>/dev/null'; - `gammastep -l $lat_lon`; + `gammastep -l $lat_lon`; } -sub fetch_lat_lon { - my ($ua, $json, $location) = @_; +sub fetch_lat_lon +{ + my ($ua, $json, $location) = @_; + + my $raw = $ua->get($location)->content(); + if (defined $raw) { + my $decoded = $json->decode($raw); + if (defined $decoded->{lat} && defined $decoded->{lon}) { + return "$decoded->{lat}:$decoded->{lon}"; + } + print $decoded->{lat}; - my $raw = $ua->get($location)->content(); - if (defined $raw) { - my $decoded = $json->decode($raw); - if (defined $decoded->{lat} && defined $decoded->{lon}) { - return "$decoded->{lat}:$decoded->{lon}"; } - print $decoded->{lat}; - - } - sleep 5; - return fetch_lat_lon($ua, $json, $location); + sleep 5; + return fetch_lat_lon($ua, $json, $location); } exit; diff --git a/sway/popup-term.pl b/sway/popup-term.pl index 50eaae8..5e70e4f 100755 --- a/sway/popup-term.pl +++ b/sway/popup-term.pl @@ -19,57 +19,61 @@ my $root = $json->decode($raw); my $display = $root->{focus}->[0]; my ($workspace, $term_id, $term_ws); foreach my $d (@{$root->{nodes}}) { - # If both the current workspace and terminal have been found, nothing else to look for - if (defined($workspace) && defined($term_id)) { - last; - # If the display from this iteration of the loop is in focus, look for the active workspace - } elsif ($d->{id} eq $display) { - foreach my $w (@{$d->{nodes}}) { - # Again, if both found, skip - if (defined($workspace) && defined($term_id)) { + # If both the current workspace and terminal have been found + # nothing else to look for + if (defined($workspace) && defined($term_id)) { last; - # Otherwise if the current workspace is active, mark it - } elsif ($w->{id} eq $d->{focus}->[0]) { - $workspace = $w->{name}; - } - # In any case, look for the terminal app - foreach my $n (@{$w->{floating_nodes}}) { - if ($n->{name} eq $term) { - $term_id = $n->{id}; - $term_ws = $w->{name}; - last; + # If the display from this iteration of the loop is in focus + # look for the active workspace + } elsif ($d->{id} eq $display) { + foreach my $w (@{$d->{nodes}}) { + # Again, if both found, skip + if (defined($workspace) && defined($term_id)) { + last; + # Otherwise if the current workspace is active, mark it + } elsif ($w->{id} eq $d->{focus}->[0]) { + $workspace = $w->{name}; + } + # In any case, look for the terminal app + foreach my $n (@{$w->{floating_nodes}}) { + if ($n->{name} eq $term) { + $term_id = $n->{id}; + $term_ws = $w->{name}; + last; + } + } } - } - } - # All other displays only need to be quickly searched for the term_id - } else { - foreach my $w (@{$d->{nodes}}) { - if (defined($term_id)) { - last; - } - foreach my $n (@{$w->{floating_nodes}}) { - if ($n->{name} eq $term) { - $term_id = $n->{id}; - $term_ws = $w->{name}; - last; + # All other displays only need to be quickly searched for the term_id + } else { + foreach my $w (@{$d->{nodes}}) { + if (defined($term_id)) { + last; + } + foreach my $n (@{$w->{floating_nodes}}) { + if ($n->{name} eq $term) { + $term_id = $n->{id}; + $term_ws = $w->{name}; + last; + } + } } - } } - } } -print "Active workspace = $workspace\nTerminal ID = $term_id\nTerminal WS = $term_ws\n"; +print "Active workspace = $workspace\n" + . "Terminal ID = $term_id\n" + . "Terminal WS = $term_ws\n"; # If there is no terminal found, spawn one if (!defined($term_id)) { - print "No term running, starting one\n"; - exec $term -# If the current workspace is known and terminal isn't on it, bring and give focus + print "No term running, starting one\n"; + exec $term +# If the current workspace is known and terminal isn't on it, bring and focus } elsif ($workspace != $term_ws) { - print "Term not on current workspace, bringing it\n"; - `swaymsg "[con_id=$term_id]" move workspace $workspace`; - `swaymsg "[con_id=$term_id]" focus`; + print "Term not on current workspace, bringing it\n"; + `swaymsg "[con_id=$term_id]" move workspace $workspace`; + `swaymsg "[con_id=$term_id]" focus`; # Otherwise hide it from whereever it is } else { - print "Term is on current workspace or lost, moving to $hidden\n"; - `swaymsg "[con_id=$term_id]" move workspace $hidden`; + print "Term is on current workspace or lost, moving to $hidden\n"; + `swaymsg "[con_id=$term_id]" move workspace $hidden`; } diff --git a/sway/swayidle.sh b/sway/swayidle.sh index 1b855e6..83d47da 100755 --- a/sway/swayidle.sh +++ b/sway/swayidle.sh @@ -3,30 +3,34 @@ BLFILE="/tmp/blc" if [ -z $1 ]; then - echo "Missing argument: swayidlerun, swayidlewarn, swayidlesleep or swayidlewake" + echo "Missing argument: swayidlerun, swayidlewarn, swayidlesleep or" \ + " swayidlewake" elif [ $1 == "swayidlerun" ]; then - swayidle timeout 270 "/home/jpm/scripts/swayidle.sh swayidlewarn" before-sleep "/home/jpm/scripts/swayidle.sh swayidlesleep" resume "/home/jpm/scripts/swayidle.sh swayidlewake" + swayidle timeout 270 "/home/jpm/scripts/swayidle.sh swayidlewarn" \ + before-sleep "/home/jpm/scripts/swayidle.sh swayidlesleep" \ + resume "/home/jpm/scripts/swayidle.sh swayidlewake" elif [ $1 == "swayidlewarn" ]; then - # Store current brightness - echo $(/home/jpm/bin/blc.pl %) > $BLFILE - # Dim display - /home/jpm/bin/blc.pl = 1 - # Warning notifications - /home/jpm/scripts/swayidlecountdown.sh + # Store current brightness + echo $(/home/jpm/bin/blc.pl %) > $BLFILE + # Dim display + /home/jpm/bin/blc.pl = 1 + # Warning notifications + /home/jpm/scripts/swayidlecountdown.sh elif [ $1 == "swayidlesleep" ]; then - # Change nick to AFK - ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t 'screen -S irssi -X stuff "/nick jpmAFK^M"' - # Turn off monitor - swaymsg 'swaymsg "output * dpms off"' - # Lock screen - swaylock -c 323232 + # Change nick to AFK + ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t \ + 'screen -S irssi -X stuff "/nick jpmAFK^M"' + # Turn off monitor + swaymsg 'swaymsg "output * dpms off"' + # Lock screen + swaylock -c 323232 elif [ $1 == "swayidlewake" ]; then - # Kill sleep if running - # Turn on monitor - swaymsg 'swaymsg "output * dpms on"' - # Restore brightness level - kill `pgrep swayidlecountdo` - /home/jpm/bin/blc.pl = $(cat /tmp/blc) + # Kill sleep if running + # Turn on monitor + swaymsg 'swaymsg "output * dpms on"' + # Restore brightness level + kill `pgrep swayidlecountdo` + /home/jpm/bin/blc.pl = $(cat /tmp/blc) else - echo "Invalid argument: run, sleep or wake" + echo "Invalid argument: run, sleep or wake" fi diff --git a/sway/swayidlecountdown.sh b/sway/swayidlecountdown.sh index 0c8574b..b2cef69 100755 --- a/sway/swayidlecountdown.sh +++ b/sway/swayidlecountdown.sh @@ -1,5 +1,5 @@ #!/bin/bash for i in `seq 0 30`; do - notify-send -t 999 "Sleeping" $(expr 30 - $i); sleep 1 + notify-send -t 999 "Sleeping" $(expr 30 - $i); sleep 1 done diff --git a/sway/toggle_outputs.sh b/sway/toggle_outputs.sh index 072718c..aae4255 100755 --- a/sway/toggle_outputs.sh +++ b/sway/toggle_outputs.sh @@ -3,7 +3,7 @@ CURRENT=`cat /home/jpm/.config/last_display` if [ "$CURRENT" == "detached" ]; then - /home/jpm/scripts/sway/displays.pl stacked + /home/jpm/scripts/sway/displays.pl stacked else - /home/jpm/scripts/sway/displays.pl detached + /home/jpm/scripts/sway/displays.pl detached fi diff --git a/thinkpad/blc.pl b/thinkpad/blc.pl index d9a4f0e..1183039 100755 --- a/thinkpad/blc.pl +++ b/thinkpad/blc.pl @@ -5,107 +5,117 @@ my $cur_file = "/sys/class/backlight/intel_backlight/brightness"; my $max_file = "/sys/class/backlight/intel_backlight/max_brightness"; my $last_file = "/home/jpm/.config/blc.last"; -sub to_percent { - my $value = shift; - if ($value eq "Permission Denied") { - return $value; - } else { - $value = int($value/get_max()*100); - return $value . '%'; - } -} - -sub get_offset { - return int(get_max()/100); -} - -sub get_current { - open(my $c,'<',"$cur_file"); - my $current = <$c>; - close $c; - chomp $current; - return $current; -} - -sub get_max { - open(my $m,'<',"$max_file"); - my $max = <$m>; - close $m; - chomp $max; - return $max; -} - -sub get_min { - return int((get_max()/100)+2); -} - -sub writable { - if (! -w $cur_file) { - return 0; - } else { - return 1; - } -} - -sub increment { - if (writable()) { - my $current = get_current(); - my $max = get_max(); - my $target = $current+get_offset(); - if ($target > $max) { - $target = $max; - } - open(my $c,'>',"$cur_file"); - print $c $target; - close $c; - return $target; - } else { - return "Permission Denied"; - } -} - -sub decrement { - if (writable()) { - my $current = get_current(); - my $min = get_min(); - my $target = $current-get_offset(); - if ($target < $min) { - $target = $min; - } - open(my $c,'>',"$cur_file"); - print $c $target; - close $c; - return $target; - } else { - return "Permission Denied"; - } -} - -sub set { - my $value = shift; - if (writable()) { - $current = get_current(); - if ($value > $current) { - for (my $i=$current;$i<=$value;$i++) { - open(my $c,'>',"$cur_file"); - print $c $i; - close $c; - } +sub to_percent +{ + my $value = shift; + if ($value eq "Permission Denied") { + return $value; } else { - for (my $i=$current;$i>=$value;$i--) { - open(my $c,'>',"$cur_file"); - print $c $i; - close $c; - } + $value = int($value/get_max()*100); + return $value . '%'; } - return $value; - } else { - return "Permission Denied"; - } } -sub help { - print " +sub get_offset +{ + return int(get_max()/100); +} + +sub get_current +{ + open(my $c,'<',"$cur_file"); + my $current = <$c>; + close $c; + chomp $current; + return $current; +} + +sub get_max +{ + open(my $m,'<',"$max_file"); + my $max = <$m>; + close $m; + chomp $max; + return $max; +} + +sub get_min +{ + return int((get_max()/100)+2); +} + +sub writable +{ + if (! -w $cur_file) { + return 0; + } else { + return 1; + } +} + +sub increment +{ + if (writable()) { + my $current = get_current(); + my $max = get_max(); + my $target = $current+get_offset(); + if ($target > $max) { + $target = $max; + } + open(my $c,'>',"$cur_file"); + print $c $target; + close $c; + return $target; + } else { + return "Permission Denied"; + } +} + +sub decrement +{ + if (writable()) { + my $current = get_current(); + my $min = get_min(); + my $target = $current-get_offset(); + if ($target < $min) { + $target = $min; + } + open(my $c,'>',"$cur_file"); + print $c $target; + close $c; + return $target; + } else { + return "Permission Denied"; + } +} + +sub set +{ + my $value = shift; + if (writable()) { + $current = get_current(); + if ($value > $current) { + for (my $i=$current;$i<=$value;$i++) { + open(my $c,'>',"$cur_file"); + print $c $i; + close $c; + } + } else { + for (my $i=$current;$i>=$value;$i--) { + open(my $c,'>',"$cur_file"); + print $c $i; + close $c; + } + } + return $value; + } else { + return "Permission Denied"; + } +} + +sub help +{ + print " Backlight Control Usage: blc.pl [--silent|--notify] [OPTION] [VALUE] @@ -146,29 +156,30 @@ Print: Any other option will be printed literally"; } -sub advanced { - $current = get_current(); - $max = get_max(); - print ". +sub advanced +{ + $current = get_current(); + $max = get_max(); + print ". Print functions can be strung together but command will exit with the first non-print option. eg. - \$ blc.pl == / ^ - 21/100 - \$ blc.pl == ++ - ('==' ignored) - (Backlight incremented) + \$ blc.pl == / ^ + 21/100 + \$ blc.pl == ++ + ('==' ignored) + (Backlight incremented) Escape options with \\ in quotes to display them literally. eg. - \$ blc.pl == / ^ '\\=' % \'\\%\' - " . $current . "/" . $max . "=" . int($current/$max*100) . "% + \$ blc.pl == / ^ '\\=' % \'\\%\' + " . $current . "/" . $max . "=" . int($current/$max*100) . "% Only one \'\\' is removed per block. eg. - \$ blc.pl '\\% \\' - % \\ + \$ blc.pl '\\% \\' + % \\ "; } @@ -177,107 +188,121 @@ my $current = get_current(); my (@output, $target, $silent, $notify); if (scalar @ARGV) { - for (my $i=0;$i get_max()) { + $target = set(get_max()); + } elsif ($target > 100) { + $target = set($target); + } else { + $target = set( + int((get_max()*$target/100)+1) + ); + } + if ($target eq "Permission Denied") { + @output = $target; + } else { + @output = to_percent($target); + } + last; + } else { + @output = ("No value after $ARGV[$i]"); + last; + } + } elsif ($ARGV[$i] eq '%') { + push @output,int(get_current()/get_max()*100); + } elsif ($ARGV[$i] eq '^') { + push @output,get_max(); + } elsif ($ARGV[$i] eq '==') { + push @output,get_current(); + } elsif ($ARGV[$i] eq '--help') { + help(); + print " (see --HELP).\n\n"; + exit(); + } elsif ($ARGV[$i] eq '--HELP') { + help(); + advanced(); + exit(); + } elsif ($ARGV[$i] eq '--silent') { + $silent = 'TRUE'; + } elsif ($ARGV[$i] =~ /^--notify/) { + $notify = 'TRUE'; + if ($ARGV[$i] =~ /=[0-9]+$/) { + $duration = $ARGV[$i]; + $duration =~ s/.*=([0-9]+)/$1/; + } else { + $duration = 200; + } } else { - $target = set(int((get_max()*$target/100)+1)); + my $add = $ARGV[$i]; + $add =~ s/\\//; + push @output,$add; } - if ($target eq "Permission Denied") { - @output = $target; - } else { - @output = to_percent($target); - } - last; - } else { - @output = ("No value after $ARGV[$i]"); - last; - } - } elsif ($ARGV[$i] eq '%') { - push @output,int(get_current()/get_max()*100); - } elsif ($ARGV[$i] eq '^') { - push @output,get_max(); - } elsif ($ARGV[$i] eq '==') { - push @output,get_current(); - } elsif ($ARGV[$i] eq '--help') { - help(); - print " (see --HELP).\n\n"; - exit(); - } elsif ($ARGV[$i] eq '--HELP') { - help(); - advanced(); - exit(); - } elsif ($ARGV[$i] eq '--silent') { - $silent = 'TRUE'; - } elsif ($ARGV[$i] =~ /^--notify/) { - $notify = 'TRUE'; - if ($ARGV[$i] =~ /=[0-9]+$/) { - $duration = $ARGV[$i]; - $duration =~ s/.*=([0-9]+)/$1/; - } else { - $duration = 200; - } - } else { - my $add = $ARGV[$i]; - $add =~ s/\\//; - push @output,$add; } - } } else { - @output = ('{"Backlight":{"Max":"' . get_max() . '","Current":"' . get_current() . '","Percentage","' . int(get_current()/get_max()*100) . '%"}}'); + @output = ( + '{"Backlight":{"Max":"' + . get_max() + . '","Current":"' + . get_current() + . '","Percentage","' + . int(get_current()/get_max()*100) + . '%"}}' + ); } @@ -286,20 +311,26 @@ print $fh get_current(); close($fh); if ($silent) { - exit(); -} elsif ($notify) { - # Don't output anything if the value didn't change - if ($current == get_current()) { exit(); - } - my $concat; - foreach (@output) { - $concat .= $_; - } - system "notify-send --urgency=normal -i /usr/share/icons/Papirus-Dark-Grey/48x48/status/notification-display-brightness.svg -t $duration \"$concat\""; - exit(); +} elsif ($notify) { + # Don't output anything if the value didn't change + if ($current == get_current()) { + exit(); + } + my $concat; + foreach (@output) { + $concat .= $_; + } + system "notify-send --urgency=normal -i " + . "/usr/share/icons/Papirus-Dark-Grey/48x48/status/" + . "notification-display-brightness.svg -t " + . $duration + . ' "' + . $concat + . '"'; + exit(); } else { - print foreach @output; - print "\n"; - exit(); + print foreach @output; + print "\n"; + exit(); } diff --git a/thinkpad/kbd_backlight.pl b/thinkpad/kbd_backlight.pl index e195341..2107247 100755 --- a/thinkpad/kbd_backlight.pl +++ b/thinkpad/kbd_backlight.pl @@ -8,32 +8,32 @@ my $current = "/sys/class/leds/tpacpi\:\:kbd_backlight/brightness"; my ($max, $now, $new); if (open(my $m, '<', $maxfile)) { - $max = readline($m); - chomp $max; - close($m); + $max = readline($m); + chomp $max; + close($m); } else { - print "Failed to read $maxfile\n"; - exit; + print "Failed to read $maxfile\n"; + exit; } print STDERR "max = $max\n"; if (open(my $c, '<', $current)) { - $now = readline($c); - chomp $now; - close($c); + $now = readline($c); + chomp $now; + close($c); } else { - print "Failed to read $current\n"; - exit; + print "Failed to read $current\n"; + exit; } print STDERR "now = $now\n"; if (open(my $fh, '>', $current)) { - $new = (($now+1) % ($max+1)); - chomp $new; - print $fh $new; - close($fh); + $new = (($now+1) % ($max+1)); + chomp $new; + print $fh $new; + close($fh); } else { - print "Failed to write $current\n"; - exit; + print "Failed to write $current\n"; + exit; } print STDERR "new = $new\n"; diff --git a/thinkpad/user-thinkpad-controls@.service b/thinkpad/user-thinkpad-controls@.service index 7d10487..980dd4a 100644 --- a/thinkpad/user-thinkpad-controls@.service +++ b/thinkpad/user-thinkpad-controls@.service @@ -2,7 +2,9 @@ Description=Give ownership of backlight to %I [Service] -ExecStart=chown %i:%i /sys/class/backlight/intel_backlight/brightness /sys/class/leds/tpacpi::kbd_backlight/brightness +ExecStart=chown %i:%i \ + /sys/class/backlight/intel_backlight/brightness \ + /sys/class/leds/tpacpi::kbd_backlight/brightness [Install] WantedBy=multi-user.target diff --git a/update-firefox.pl b/update-firefox.pl index 149c280..ac83e94 100755 --- a/update-firefox.pl +++ b/update-firefox.pl @@ -11,43 +11,52 @@ my $install = "$ENV{HOME}/.local/bin"; my $working = "/tmp/firefox.new"; # Download link as provided by https://www.mozilla.org/$lang/firefox/developer/ -my $url = 'https://download.mozilla.org/?product=firefox-devedition-latest-ssl&os=linux64&lang='.$lang; +my $url = 'https://download.mozilla.org/?product=firefox-devedition-latest-ssl' + . '&os=linux64&lang='.$lang; # Ensure that we can unzip unless (which("bunzip2")) { - die "Requires bunzip2. Try:\nsudo apt install zutils or your distro's equivalent\n"; + die "Requires bunzip2. Try:\n" + . "sudo apt install zutils or your distro's equivalent\n"; } # Only understood argument is to not bother verifying the package my ($download_key, $verify) = (0,1); if (defined $ARGV[0]) { - if ($ARGV[0] eq '--no-verify') { - $verify = 0; - } else { - die "Didn't understand argument $ARGV[0]\n"; - } + if ($ARGV[0] eq '--no-verify') { + $verify = 0; + } else { + die "Didn't understand argument $ARGV[0]\n"; + } } # If verification is to be done, make sure we have the key unless ($verify) { - print "Checking for Mozilla GPG key in keyring...\n"; - system("gpg --list-keys release\@mozillla.com 2>&1 > /dev/null"); - if ($?) { - my $YN = prompt (-in => *STDIN, "You don't currently have Mozilla's GPG key in your keyring.\nWould you like to install it? If not, installation will not be verified. [y/N]: ", -single); - if ($YN eq 'y' || $YN eq 'Y') { - $download_key = 1; - } else { - $verify = 0; + print "Checking for Mozilla GPG key in keyring...\n"; + system("gpg --list-keys release\@mozillla.com 2>&1 > /dev/null"); + if ($?) { + my $YN = prompt (-in => *STDIN, "You don't currently have " + . "Mozilla's GPG key in your keyring.\n" + . "Would you like to install it? If not, installation " + . "will not be verified. [y/N]: ", + -single + ); + if ($YN eq 'y' || $YN eq 'Y') { + $download_key = 1; + } else { + $verify = 0; + } } - } } # If a previous download still exists remove it if ( -e $working ) { - system("rm -rf $working"); - if ($?) { - die "Working directory $working already exists and failed to remove: $!\n"; - } + system("rm -rf $working"); + if ($?) { + die "Working directory " + . $working + . "already exists and failed to remove: $!\n"; + } } # Get version currently installed @@ -58,19 +67,21 @@ chomp $current; use WWW::Mechanize; my $mech = WWW::Mechanize->new(); -# $url is actually going to redirect to the proper current dowload, so just get the redirect. +# $url is actually going to redirect to the proper current dowload so just get +# the redirect. my $head = $mech->head($url); my ($location, $version); -# This redirect will have the version id, so we can use that to determine if a new version actually exists +# This redirect will have the version id, so we can use that to determine if a +# new version actually exists if ($head->{'_msg'}) { - $version = $location = $head->{'_previous'}->{'_headers'}->{'location'}; - $version =~ s/^.*\-([^\-]*)\.tar\.bz2$/$1/; - if ($version eq $current) { - die "Current ($current) is the same as New ($version)\n"; - } + $version = $location = $head->{'_previous'}->{'_headers'}->{'location'}; + $version =~ s/^.*\-([^\-]*)\.tar\.bz2$/$1/; + if ($version eq $current) { + die "Current ($current) is the same as New ($version)\n"; + } } else { - print "unable to find new download\n"; + print "unable to find new download\n"; } mkdir($working) || die "Couldn't make $working: $!\n"; @@ -78,77 +89,106 @@ mkdir($working) || die "Couldn't make $working: $!\n"; # Download package print "Fetching package $location...\n"; $mech->get($location); -$mech->save_content( $working."/firefox-".$version.".tar.bz2", binmode => ':raw', decoded_by_headers => 1 ); +$mech->save_content( $working."/firefox-".$version.".tar.bz2", + binmode => ':raw', + decoded_by_headers => 1 +); # If verification is required, get signature as well if ($verify) { - $location .= '.asc'; - print "Fetching GPG signature $location...\n"; - $mech->get($location); - $mech->save_content( $working."/firefox-".$version.".tar.bz2.asc", binmode => ':raw', decoded_by_headers => 1 ); + $location .= '.asc'; + print "Fetching GPG signature $location...\n"; + $mech->get($location); + $mech->save_content( $working."/firefox-".$version.".tar.bz2.asc", + binmode => ':raw', + decoded_by_headers => 1 + ); } # If key still needs to be fetched, get it if ($download_key) { - $location =~ s/linux-x86_64.*$/KEY/; - print "Fetching GPG key $location...\n"; - $mech->get($location); - $mech->save_content( $working."/mozilla.pgp", binmode => ':raw', decoded_by_headers => 1 ); - # And install it - print "Installing Mozilla GPG key in keyring...\n"; - system("gpg --import $working/mozilla.pgp 2>&1 > /dev/null"); - if ($?) { - die "Warning: failed to import key. Cannot verify integrity.\nDownloaded to $working. You can check and install it to $install manually: $!\n"; - } - unlink("$working/mozilla.pgp"); + $location =~ s/linux-x86_64.*$/KEY/; + print "Fetching GPG key $location...\n"; + $mech->get($location); + $mech->save_content( $working."/mozilla.pgp", + binmode => ':raw', + decoded_by_headers => 1 + ); + # And install it + print "Installing Mozilla GPG key in keyring...\n"; + system("gpg --import $working/mozilla.pgp 2>&1 > /dev/null"); + if ($?) { + die "Warning: failed to import key. Cannot verify integrity.\n" + . "Downloaded to " + . $working + . ". You can check and install it to " + . $install + . "manually: " + . $! + . "\n"; + } + unlink("$working/mozilla.pgp"); } # Verify the package if ($verify) { - print "Verifying download with Mozilla GPG key...\n"; - system("gpg --verify $working/firefox-$version.tar.bz2.asc"); - if ($?) { - die "Warning: failed to verify download. Signing failed.\nDownloaded to $working. You can check and install it to $install manually: $!\n"; - } + print "Verifying download with Mozilla GPG key...\n"; + system("gpg --verify $working/firefox-$version.tar.bz2.asc"); + if ($?) { + die "Warning: failed to verify download. Signing failed.\n" + . "Downloaded to " + . $working + . ". You can check and install it to " + . $install + . " manually: " + . $! + . "\n"; + } } # Uncompress print "Uncompressing download with bunzip2...\n"; system("bunzip2 $working/firefox-$version.tar.bz2"); if ($?) { - die "Failed to uncompress: $!\n"; + die "Failed to uncompress: $!\n"; } # Extract print "Extracting from TAR archive...\n"; system("tar -xf $working/firefox-$version.tar -C $working"); if ($?) { - die "Failed to extract: $!\n"; + die "Failed to extract: $!\n"; } # Bin the old backup if (-e "$install/.firefox.old") { - print "Removing previous backup folder...\n"; - system("rm -rf $install/.firefox.old"); - if ($?) { - die "Failed to remove: $!\n"; - } + print "Removing previous backup folder...\n"; + system("rm -rf $install/.firefox.old"); + if ($?) { + die "Failed to remove: $!\n"; + } } # Move current to old -print "Backing up currently installed version ($current) to $install/.firefox.old...\n"; +print "Backing up currently installed version (" + . $current + . ") to " + . $install + . "/.firefox.old...\n"; system("mv $install/firefox $install/.firefox.old"); if ($?) { - die "Failed to move: $!\n"; + die "Failed to move: $!\n"; } # Move new to current print "Moving new version to $install for final installation...\n"; system("mv $working/firefox $install/"); if ($?) { - die "Failed to move: $!\n"; + die "Failed to move: $!\n"; } # Hurray! -print "Installation of version $version complete. You should restart firefox whenever it is convenient.\n"; +print "Installation of version " + . $version + . " complete. You should restart firefox whenever it is convenient.\n"; exit(); diff --git a/waybar/waybar-cpu.sh b/waybar/waybar-cpu.sh index 01c19e6..9346057 100755 --- a/waybar/waybar-cpu.sh +++ b/waybar/waybar-cpu.sh @@ -1,7 +1,7 @@ #!/bin/bash if [ "$(pgrep -c htop)" -gt 0 ]; then - pkill htop + pkill htop else - /usr/bin/uxterm -e htop + /usr/bin/uxterm -e htop fi diff --git a/waybar/waybar-disk.sh b/waybar/waybar-disk.sh index 023388e..69495c1 100755 --- a/waybar/waybar-disk.sh +++ b/waybar/waybar-disk.sh @@ -1,3 +1,7 @@ #!/bin/bash -notify-send -t 3000 Disks "$(lsblk -o NAME,SIZE,FSUSE%,MOUNTPOINT | grep -vP '^loop' | sed 's/MOUNTPOINT/MOUNT/' | sed -e 's/│ └─/+---/' | sed -e 's/ └─/+---/' | sed -e 's/├─/+-/' | sed -e 's/└─/+-/' | awk {'printf "%-20s %-7s %- 6s %-7s\n", $1, $2, $3, $4'})" +notify-send -t 3000 Disks \ + "$(lsblk -o NAME,SIZE,FSUSE%,MOUNTPOINT | grep -vP '^loop' | \ + sed 's/MOUNTPOINT/MOUNT/' | sed -e 's/│ └─/+---/' | \ + sed -e 's/ └─/+---/' | sed -e 's/├─/+-/' | sed -e 's/└─/+-/' | \ + awk {'printf "%-20s %-7s %- 6s %-7s\n", $1, $2, $3, $4'})" diff --git a/waybar/waybar-mem.sh b/waybar/waybar-mem.sh index 7f5bbc5..02cf10a 100755 --- a/waybar/waybar-mem.sh +++ b/waybar/waybar-mem.sh @@ -1,3 +1,5 @@ #!/bin/bash -notify-send 'Memory Usage' "`free -h | awk '{printf(\"%6s %6s %6s %6s\n\", $1, $2, $3, $4)}' | sed -r 's/(.*) shared$/ \1/'`" +notify-send 'Memory Usage' "`free -h | \ + awk '{printf(\"%6s %6s %6s %6s\n\", $1, $2, $3, $4)}' | \ + sed -r 's/(.*) shared$/ \1/'`" diff --git a/waybar/waybar-nmtui.sh b/waybar/waybar-nmtui.sh index 1e9dc4e..8d4252a 100755 --- a/waybar/waybar-nmtui.sh +++ b/waybar/waybar-nmtui.sh @@ -1,9 +1,9 @@ #!/bin/bash if [ "$(pgrep -c nmtui | cut -b 1)" -eq "0" ]; then - echo true - /usr/bin/xterm -e '/usr/bin/nmtui' + echo true + /usr/bin/xterm -e '/usr/bin/nmtui' else - echo false - pkill nmtui 2&>1 /dev/null + echo false + pkill nmtui 2&>1 /dev/null fi From 8f6199cd3dda2c9dedb7cd5fda7dea2fdf1b9260 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 1 Dec 2020 04:59:29 -0500 Subject: [PATCH 015/110] Script to look up and stream today's podcasts --- audio/stream-podcasts.pl | 83 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 audio/stream-podcasts.pl diff --git a/audio/stream-podcasts.pl b/audio/stream-podcasts.pl new file mode 100755 index 0000000..1a32d90 --- /dev/null +++ b/audio/stream-podcasts.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +# Dependencies +use LWP::UserAgent; # Usually pre-installed, available on CPAN +use XML::Hash::XS; # CPAN or libxml-hash-xs-perl on Debian + +# Feeds that should be used if no arguments are provided +my @default_feeds = ( + # CBC FrontBurner + "https://www.cbc.ca/podcasting/includes/frontburner.xml", + # Majority Report AM Quickie + "https://feeds.fans.fm/5883fe04-e11e-4578-a018-3b93ddfb5723.xml" +); + +# Player command (must accept stream as STDIN) +#my $player = "| mpv -"; +# OMXPlayer is the only one capable of playing without stutter on the pi +# It requires FIFO to stream. For a player that does support STDIN, uncomment +# above and delete the following 4 lines +unless (-e "/tmp/fifo.mp3") { + system("mkfifo /tmp/fifo.mp3"); +} +my $player = "> /tmp/fifo.mp3 & omxplayer /tmp/fifo.mp3"; + +# Multiple feeds can be given as CLI arguments instead +my @feeds; +if (scalar @ARGV) { + foreach (@ARGV) { + push @feeds, $_; + } +} + +# Only use default feeds if no CLI feeds were given +unless (scalar @feeds) { + @feeds = @default_feeds; +} + +# Local function to get date pattern provided as 'pubDate' +my $today = get_date(); + +# Setup Webpage agent and XML parser +my $ua = LWP::UserAgent->new(); +my $xml = XML::Hash::XS->new(utf8 => 0, encoding => 'utf-8'); + +my @playlist; +# Go through each feed +foreach my $url (@feeds) { + # Ensure that it's actual an XML link + next unless $url =~ m#^https?://.*\.xml$#; + # Ensure it is fetched okay + my $raw = $ua->get("$url")->content() || next; + # Ensure it is parsed okay + my $xml_hash = $xml->xml2hash($raw) || next; + + # Collect all episodes published today + foreach my $item (@{$xml_hash->{'channel'}->{'item'}}) { + if ($item->{'pubDate'} =~ m/$today/) { + # Add any found to playlist + push @playlist, $item->{'enclosure'}->{'url'}; + } + } +} + +# Fetch each item and pass it to player via STDIN +foreach (@playlist) { + # Uncomment the following to print the media URL + print $_ . "\n"; + system("curl -NL $_ $player"); +} +unlink("/tmp/fifo.mp3"); + +sub get_date +{ + my ($second, $minute, $hour, $day, $month, $year) = localtime(time); + my @months = ( + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' + ); + return $day . ' ' . $months[$month] . ' ' . ($year+1900); +} From e93c37a6398244eef2803982c24cb36115fc6a59 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 1 Dec 2020 05:06:41 -0500 Subject: [PATCH 016/110] Script to install wireguard and generate config --- setup-wireguard.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 setup-wireguard.sh diff --git a/setup-wireguard.sh b/setup-wireguard.sh new file mode 100755 index 0000000..b29b228 --- /dev/null +++ b/setup-wireguard.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +SERVER_KEY='abcdefghijklmnopqrstuvwxyz0123456789abcdefg='; +SERVER_IP='1.1.1.1'; +WG_BLOCK='10.10.0'; + +if [[ $1 == '' ]]; then + echo "Need last octet as argument" + exit +elif grep -Pq '^[0-9]*$' <<< $(echo $1); then + echo "Good" +else + echo "Argument must be a number representing the last octet" + exit +fi + +sudo apt update + +if grep -Pq '^arm' <<< $(uname -m); then + sudo apt install -y wireguard wireguard-dkms wireguard-tools raspberrypi-kernel raspberrypi-kernel-headers resolvconf +else + sudo apt install -y wireguard wireguard-tools linux-headers-$(uname -r) resolvconf +fi + +if [[ "`which wg 2> /dev/null`" == '' ]]; then + echo "Failed to install wireguard" + exit +fi + +wg genkey | sudo tee /etc/wireguard/client_private.key | wg pubkey | sudo tee /etc/wireguard/client_public.key + +if [[ "`sudo cat /etc/wireguard/client_public.key 2> /dev/null`" == '' ]]; then + echo "Failed to create keys" + exit +fi + +echo "[Interface] +Address = 10.10.0.${1}/24 +DNS = 10.10.0.1 +PrivateKey = $(sudo cat /etc/wireguard/client_private.key) + +[Peer] +PublicKey = $SERVER_KEY +AllowedIPs = 0.0.0.0/0 +Endpoint = $SERVER_IP:51820 +PersistentKeepalive = 25" > wg0.conf + +sudo mv wg0.conf /etc/wireguard/ +sudo chown root:root /etc/wireguard/wg0.conf +sudo chmod 600 /etc/wireguard/wg0.conf + +sudo systemctl enable wg-quick@wg0 + +echo "On server run: + +sudo systemctl stop wg-quick@wg0 + +Then append the following to /etc/wireguard/wg0.conf: + +[Peer] +PublicKey = $(sudo cat /etc/wireguard/client_public.key) +AllowedIPs = $WG_BLOCK.${1}/32 + +Then start it again with + +sudo systemctl start wg-quick@wg0 + +Then on this client, enable and start wireguard: + +sudo systemctl enable wg-quick@wg0 +sudo systemctl start wg-quick@wg0 +" From 40bfe2560633dcd108cf7dde943914ce33f27034 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 1 Dec 2020 05:13:20 -0500 Subject: [PATCH 017/110] Add description for stream-podcasts.pl and setup-wireguard.sh --- README.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4087bf2..613dd1d 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Just a simple script to toggle Alsa mute. Add a noise-cancelled version of existing interfaces to Pulseaudio. +**audio/stream-podcasts.pl** + +Commandline podcast streamer. Fetchs the feed for desired podcasts, find items +published today, then plays them in order. Given arguments, it will use those +as feeds, otherwise it will use the hash listed in the script. + ## i3 I haven't used i3 in earnest for quite some time since moving to Sway, so it is @@ -191,15 +197,22 @@ Launch nmtui in floating window (bottom-right). If already running, kill it. ## Miscellaneous -**send-to-kodi.sh** - -[This script](https://github.com/allejok96/send-to-kodi) sends a URL or local -file to a [Kodi](https://github.com/xbmc) media player. Only modified to have my -local media server IP. - **apply-gruvbox.sh** A single theme version of the one provided [here](https://raw.githubusercontent.com/Mayccoll/Gogh). Applies the theme to a variety of terminals. Not really necessary after cloning the 'dotfiles' repository. + +**send-to-kodi.sh** + +[This script](https://github.com/allejok96/send-to-kodi) sends a URL or local +file to a [Kodi](https://github.com/xbmc) media player. Only modified to have my +local media server IP. + +**setup_wireguard.sh** + +Script to install WireGuard and generate a config file. Requires modification +with the server public IP, server public key, and change to first 3 octets if +necessary. Will attempt to resolve dependencies and has a special case for +Raspberry Pi (detected with `uname -m` as 'arm'. From aa7ac22226bcd04e76742a676a6b5e73fecfefde Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 17 Jan 2021 21:48:20 -0500 Subject: [PATCH 018/110] Add quick switch between docked and detached displays to power menu --- rofi/rofi-power-menu.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh index 1af68dc..03124d4 100755 --- a/rofi/rofi-power-menu.sh +++ b/rofi/rofi-power-menu.sh @@ -12,7 +12,7 @@ fi if [[ $WM == 'i3' ]]; then res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) else - res=$(echo "🔒 Lock|↩ Logout|↻ Reload Sway|↻ Reload Waybar|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) + res=$(echo "🔒 Lock|🖵 Toggle Displays|↩ Logout|↻ Reload Sway|↻ Reload Waybar|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) fi if [ "$res" == "🔒 Lock" ]; then @@ -21,6 +21,8 @@ elif [ "$res" == "↩ Logout" ]; then # Prevent auto-login rm /home/jpm/.config/last_login_gui ${WM} exit +elif [ "$res" == "🖵 Toggle Displays" ]; then + /home/jpm/scripts/sway/toggle_outputs.sh elif [ "$res" == "↻ Reload i3" ]; then i3 reload elif [ "$res" == "↹ Restart i3" ]; then From 31fe7a032be9edf4347a0741d6a76b894d31a08d Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 17 Jan 2021 21:49:54 -0500 Subject: [PATCH 019/110] Simple script to toggle docked and detached output layouts --- sway/toggle_outputs.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/toggle_outputs.sh b/sway/toggle_outputs.sh index aae4255..5df74c0 100755 --- a/sway/toggle_outputs.sh +++ b/sway/toggle_outputs.sh @@ -7,3 +7,5 @@ if [ "$CURRENT" == "detached" ]; then else /home/jpm/scripts/sway/displays.pl detached fi +pkill mako +mako & From 7fb00b5f09425d2d1f08f93a954e75a0721376f9 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 17 Jan 2021 21:51:31 -0500 Subject: [PATCH 020/110] Default displays changed. Added fallback action. If a config is selected for which the displays do not exist, either bail or if in recovery mode, restore 'detached'. The latter was added in anticipation of the swayidle script which will attempt to restore a layout that may no longer be possible. Since swayidle disables dpms, it must allow a backup display to come live if the last logged layout is not possible. --- sway/displays.pl | 57 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index 7ddc06f..5c1d306 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -36,6 +36,9 @@ my $waybar_temporary = '/tmp'; # File to log and recover last used layout name my $last = "$ENV{'HOME'}/.config/last_display"; +# File to log active outputs (used by swayidle, and to attempt to restore +my $active_outputs = "$ENV{'HOME'}/.config/active_outputs"; + ######################################################################## # Display Serials and Names ######################################################################## @@ -45,9 +48,12 @@ my $last = "$ENV{'HOME'}/.config/last_display"; # $ swaymsg -t get_outputs # Output eDP-1 'Unknown 0x057D *0x00000000*' my %outputs = ( - '0x00000101' => 'Sam', + #'0x00000101' => 'Sam', + 'HTNCB00059' => 'Sam', + #'3CQ3310Q1Q' => 'Sam', '3CQ4342S6W' => 'HP-1', - '3CQ3310Q1Q' => 'HP-2', + '0x00000101' => 'HP-2', + #'3CQ3310Q1Q' => 'HP-2', '0x00000000' => 'LVDS' ); @@ -93,7 +99,7 @@ my %configs = ( 'on' => 1, 'width' => 1920, 'height' => 1080, - 'x' => 0, + 'x' => 1920, 'y' => 1200, 'rotate' => 0, 'waybar' => 'top' @@ -102,7 +108,7 @@ my %configs = ( 'on' => 1, 'width' => 1920, 'height' => 1080, - 'x' => 1920, + 'x' => 0, 'y' => 1200, 'rotate' => 0, 'waybar' => 'top' @@ -153,6 +159,7 @@ use strict; use warnings; my $waybar_only = 0; +my $restore = 0; # Set if no config is provided. Requires validation. my $config; if (scalar(@ARGV)) { @@ -176,12 +183,18 @@ unless (defined $config) { $config = <$fh>; close($fh); chomp $config; + $restore = 1; } # Bail if requested config doesn't exist -unless (defined $configs{$config}) { - die "$config is not a defined configuration: " - . join(', ', keys %configs) . "\n"; +if (!defined($configs{$config})) { + if ($restore) { + # If restoration is attempted with invalid config, just enable eDP-1 + $config = 'detached'; + } else { + die "$config is not a defined configuration: " + . join(', ', keys %configs) . "\n"; + } } # Write config that is to be used so that it can be recovered as default @@ -190,6 +203,7 @@ open(my $fh, '>', $last) || print $fh $config; close($fh); + # Fetch connected displays use JSON::XS; my $json = JSON::XS->new(); @@ -224,6 +238,24 @@ for (my $i = 0; $i < scalar(@$displays); $i++) { } +# Verify that all requested displays are actually available +my @unavailable; +foreach my $output (keys %$on) { + my $found = 0; + foreach my $o (keys %outputs) { + if ($outputs{$o} eq $output) { + $found = 1; + last; + } + } + unless ($found) { + push @unavailable, $output; + } +} +if (scalar(@unavailable)) { + die "Config requires unavailable output(s) " . join(', ', @unavailable) . "\n"; +} + # Skip enabling/disabling displays if only running waybar (re)start unless ($waybar_only) { # Number of simultaneous outputs is limited by gpu, so disabled displays @@ -279,9 +311,11 @@ $template =~ s/^[^\[\{]*\[(.*)\]$/$1/s; my $waybar = ''; # Configure each enabled display +my @active; foreach my $out (keys %$on) { - unless ($waybar_only) { + push @active, $on->{$out}->{output}; + unless ($waybar_only) { # Build command, starting by enabling and powering on my $cmd = "sway output $on->{$out}->{output} enable dpms on"; @@ -334,6 +368,11 @@ foreach my $out (keys %$on) { } } +open($fh, '>', $active_outputs); +print $fh join(' ', @active); +close($fh); + + # Restore array formatting $waybar = '[' . $waybar . ']'; @@ -348,7 +387,7 @@ unless ($pid) { open ($fh, '>', $tmp); print $fh $waybar; close $fh; - `nohup waybar --config=$tmp`; + `nohup waybar --config=$tmp >> waybar.log`; # Remove config unlink $tmp; From bbd69f5e7334c0001ce1989e718625f9703e4122 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 17 Jan 2021 21:54:21 -0500 Subject: [PATCH 021/110] A simulacrum of a functional swayidle script. Working: A proper countdown to idle works and is cancelled on resume. Displays are dimmed if possible at countdown start and restorted at resume. The screens properly lock. The power to the displays is turned off. The power is restore upon first resume. Layout and brightness restored on unlock. Known issue: Displays are not restored if the system idles again while on lock screen. This shouldn't really happen and is a possible indicator of tampering, which is kind of cool, but it's janky. Power needs to be restored with the toggle_displays hotkey. --- sway/idle.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ sway/idlecountdown.sh | 5 +++++ 2 files changed, 48 insertions(+) create mode 100755 sway/idle.sh create mode 100755 sway/idlecountdown.sh diff --git a/sway/idle.sh b/sway/idle.sh new file mode 100755 index 0000000..5fc8a38 --- /dev/null +++ b/sway/idle.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +BLFILE="/home/jpm/.config/blc.last" +OPFILE="/home/jpm/.config/active_outputs" + +if [ -z $1 ]; then + echo "Missing argument: run, warn, sleep or" \ + " wake" +elif [ $1 == "start" ]; then + swayidle -w timeout 270 "/home/jpm/scripts/sway/idle.sh warn" \ + resume "/home/jpm/scripts/sway/idle.sh resume" \ + timeout 300 "/home/jpm/scripts/sway/idle.sh sleep" \ + resume "/home/jpm/scripts/sway/idle.sh wake" \ + before-sleep "/usr/bin/swaylock -c 323232" +elif [ $1 == "warn" ]; then + # Store current brightness + echo $(/home/jpm/scripts/thinkpad/blc.pl %) > $BLFILE + # Dim display + /home/jpm/scripts/thinkpad/blc.pl = 1 + # Warning notifications + /home/jpm/scripts/sway/idlecountdown.sh +elif [ $1 == "sleep" ]; then + # Change nick to AFK + ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t \ + 'screen -S irssi -X stuff "/nick jpmAFK^M"' + # Turn off monitor + for i in `cat $OPFILE`; do swaymsg "output $i dpms off"; done +elif [ $1 == "wake" ]; then + # Kill additional counters that might have been started + /home/jpm/scripts/sway/idle.sh resume + # Restore output(s) + /home/jpm/scripts/sway/displays.pl + #for i in `cat $OPFILE`; do swaymsg "output $i dpms on"; done + # Lock screen + swaylock -c 323232 + # Restore brightness level + /home/jpm/scripts/thinkpad/blc.pl = $(cat $BLFILE) +elif [ $1 == "resume" ]; then + # Kill warning + for i in `pgrep idlecountdown`; do kill $i; done +else + echo "Invalid argument: run, sleep or wake" +fi diff --git a/sway/idlecountdown.sh b/sway/idlecountdown.sh new file mode 100755 index 0000000..b2cef69 --- /dev/null +++ b/sway/idlecountdown.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +for i in `seq 0 30`; do + notify-send -t 999 "Sleeping" $(expr 30 - $i); sleep 1 +done From c419c8d2ed6ec9f16dac46a0c70cb1db2fed227c Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sun, 17 Jan 2021 22:03:13 -0500 Subject: [PATCH 022/110] Files were moved and updated. Deleting old. --- sway/swayidle.sh | 36 ------------------------------------ sway/swayidlecountdown.sh | 5 ----- 2 files changed, 41 deletions(-) delete mode 100755 sway/swayidle.sh delete mode 100755 sway/swayidlecountdown.sh diff --git a/sway/swayidle.sh b/sway/swayidle.sh deleted file mode 100755 index 83d47da..0000000 --- a/sway/swayidle.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -BLFILE="/tmp/blc" - -if [ -z $1 ]; then - echo "Missing argument: swayidlerun, swayidlewarn, swayidlesleep or" \ - " swayidlewake" -elif [ $1 == "swayidlerun" ]; then - swayidle timeout 270 "/home/jpm/scripts/swayidle.sh swayidlewarn" \ - before-sleep "/home/jpm/scripts/swayidle.sh swayidlesleep" \ - resume "/home/jpm/scripts/swayidle.sh swayidlewake" -elif [ $1 == "swayidlewarn" ]; then - # Store current brightness - echo $(/home/jpm/bin/blc.pl %) > $BLFILE - # Dim display - /home/jpm/bin/blc.pl = 1 - # Warning notifications - /home/jpm/scripts/swayidlecountdown.sh -elif [ $1 == "swayidlesleep" ]; then - # Change nick to AFK - ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t \ - 'screen -S irssi -X stuff "/nick jpmAFK^M"' - # Turn off monitor - swaymsg 'swaymsg "output * dpms off"' - # Lock screen - swaylock -c 323232 -elif [ $1 == "swayidlewake" ]; then - # Kill sleep if running - # Turn on monitor - swaymsg 'swaymsg "output * dpms on"' - # Restore brightness level - kill `pgrep swayidlecountdo` - /home/jpm/bin/blc.pl = $(cat /tmp/blc) -else - echo "Invalid argument: run, sleep or wake" -fi diff --git a/sway/swayidlecountdown.sh b/sway/swayidlecountdown.sh deleted file mode 100755 index b2cef69..0000000 --- a/sway/swayidlecountdown.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -for i in `seq 0 30`; do - notify-send -t 999 "Sleeping" $(expr 30 - $i); sleep 1 -done From 4d2fbf6254a243b606ca5975bd0df942a9023709 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:05:13 -0400 Subject: [PATCH 023/110] Togglable NetworkManager window for waybar using nmtui --- waybar/waybar-nm.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 waybar/waybar-nm.sh diff --git a/waybar/waybar-nm.sh b/waybar/waybar-nm.sh new file mode 100755 index 0000000..54d5c94 --- /dev/null +++ b/waybar/waybar-nm.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +RUNNING=$(pgrep nmtui) + +if [ "$RUNNING" ]; then + kill $RUNNING 2&>1 /dev/null +else + /usr/bin/xterm -e '/usr/bin/nmtui' +fi From 855d9ca492aba774d5ea2c5d75f505799b218054 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:11:42 -0400 Subject: [PATCH 024/110] Fetcher for Battery and Power status Features outputs as JSON, simple output for status bar and notification-ready pretty formatting. --- thinkpad/pow.pl | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100755 thinkpad/pow.pl diff --git a/thinkpad/pow.pl b/thinkpad/pow.pl new file mode 100755 index 0000000..c49fd2b --- /dev/null +++ b/thinkpad/pow.pl @@ -0,0 +1,159 @@ +#!/usr/bin/perl + +my $output; +my ($bar, $pretty) = (0, 0); + +if ( defined($ARGV[0]) && $ARGV[0] ne '-b' && $ARGV[0] ne '--bar' && $ARGV[0] ne '-p' && $ARGV[0] ne '--pretty' ) { + print' +pow.pl - Power Status Script + +Usage: pow.pl + +Prints information about all power devices as JSON. + +-p --pretty Display as human-readable +-b --bar Waybar simplified output +-h --help Display help. This is the only option. + +'; +exit(); +} elsif ($ARGV[0] eq '-b' || $ARGV[0] eq '--bar') { + $bar = 1; +} elsif ($ARGV[0] eq '-p' || $ARGV[0] eq '--pretty') { + $pretty = 1; +} + +my %battery_total = ( + 'current' => 0, + 'max' => 0, + 'percentage' => 0 +); + +my @devices = <"/sys/class/power_supply/*">; +$output .= "{"; +foreach (@devices) { + my $path = $_; + my $name = $_; + $name =~ s/.*\///; + $output .= '"' . $name . '":{'; + open(my $t,'<',"$_/type"); + my $type = <$t>; + chomp $type; + close $t; + $output .= '"Type":"' . $type . '"'; + if ($name =~ /BAT[0-9]+/) { + open(my $s,'<',"$_/status"); + my $status = <$s>; + chomp $status; + $output .= ',"Status":"' . $status . '"'; + } else { + open(my $s,'<',"$_/online"); + my $status = <$s>; + chomp $status; + if ($status) { + $status = "Plugged-In"; + } else { + $status = "Unplugged"; + } + $output .= ',"Status":"' . $status . '"'; + } + close $s; + if ($name =~ /BAT[0-9]+/) { + open(my $m,'<',"$_/energy_full"); + my $max = <$m>; + close $m; + chomp $max; + $battery_total{'max'} += $max; + open(my $c,'<',"$_/energy_now"); + my $current = <$c>; + chomp $current; + #$current =~ s/\n//; + $battery_total{'current'} += $current; + close $c; + $output .= ',"Current":"' + . $current + . '","Max":"' + . $max + . '","Percentage":"' + . int($current/$max*100) + . '"'; + } + $output .= "},"; +} + +$battery_total{'percentage'} = sprintf("%0d", + $battery_total{'current'} / $battery_total{'max'} * 100 +); +$output .= '"Total":{"Current":"' + . $battery_total{'current'} + . '","Max":"' + . $battery_total{'max'} + . '","Percentage":"' + . $battery_total{'percentage'} + . '"}}'; + +if ($bar) { + use JSON::XS; + my $json = JSON::XS->new(); + my $powref = $json->decode($output); + my $icon; + my $class = 'discharging'; + $output = '{"text": "' . $powref->{Total}->{Percentage} . '% '; + if ($powref->{AC}->{Status} eq "Plugged-In") { + $class = 'charging'; + $output .= ""; + } elsif ($powref->{Total}->{Percentage} le 10) { + $class = 'critical'; + $output .= ""; + } elsif ($powref->{Total}->{Percentage} le 35) { + $class = 'low'; + $output .= ""; + } elsif ($powref->{Total}->{Percentage} le 60) { + $output .= ""; + } elsif ($powref->{Total}->{Percentage} le 85) { + $output .= ""; + } else { + $output .= ""; + } + $output .= '", "tooltip": "' . $class . '", "class": "' . $class . '"}'; +} elsif ($pretty) { + use JSON::XS; + my $json = JSON::XS->new(); + my $powref = $json->decode($output); + my $total = ''; + $output = "Device Status Percentage\n"; + foreach my $device (keys %{$powref}) { + my $status; + if ($powref->{$device}->{Status} eq "Plugged-In") { + $status = ""; + } elsif (!defined($powref->{$device}->{Percentage}) || $powref->{$device}->{Percentage} == 0) { + $status = " "; + } elsif ($powref->{$device}->{Percentage} <= 10) { + $status = " " . $powref->{$device}->{'Percentage'} . "%"; + } elsif ($powref->{$device}->{Percentage} <= 35) { + $status = " " . $powref->{$device}->{'Percentage'} . "%"; + } elsif ($powref->{$device}->{Percentage} <= 60) { + $status = " " . $powref->{$device}->{'Percentage'} . "%"; + } elsif ($powref->{$device}->{Percentage} <= 85) { + $status = " " . $powref->{$device}->{'Percentage'} . "%"; + } else { + $status = " " . $powref->{$device}->{'Percentage'} . "%"; + } + if ($device eq 'Total') { + $total .= sprintf("%-24s %-12s", $device, $status); + } else { + #$output .= sprintf("%".length($powref->{$device->{'Type'}})."s (%".length($powref->{$device->{'Type'}})."s): %3d\%\n", $device, $device->{'Type'}, $device->{'Percentage'}); + my $name = ' ('.$powref->{$device}->{'Type'}.')'; + if ((length($device)+length($name)) >= 24) { + $name = substr($device, 0, (21-length($name))) . '...' . $name; + } else { + $name = substr(($device.$name), 0, 24); + } + $output .= sprintf("%-24s %-12s %-12s\n", $name, $powref->{$device}->{Status}, $status); + } + } + $output .= $total; +} +print $output . "\n"; + +exit(); From 87a9d29298e0f1e345890bc9bd1fa08ee4786331 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:17:23 -0400 Subject: [PATCH 025/110] Document thinkpad/pow.pl --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 613dd1d..7fd54dc 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,12 @@ Simple script to cycle keyboard backlight. Gets max brightness, current brightness and then changes then increments the current brightness. Uses mod of max+1 so that it will cycle back around to 0 (disabled) if it is already at max. +**thinkpad/pow.pl** + +Overly complicated battery and power status fetcher script. Can output stats as +JSON, Waybar-friendly percentage and icon, or a pretty table suitable for use with +plain-text notifications via notify-send or similar. + **thinkpad/user-thinkpad-control@.service** SystemD unit file used to give ownership of necessary sys files to whichever @@ -191,7 +197,7 @@ Mako. Notification with memory usage summaries. -**waybar/waybar-nmtui.sh** +**waybar/waybar-nm.sh** Launch nmtui in floating window (bottom-right). If already running, kill it. From 4a6a59029d3282b3691af5599a38321a5db2f67f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:20:28 -0400 Subject: [PATCH 026/110] Correct Fastnet hostname, add VNC shortcut to Mac --- rofi/rofi-ssh-menu.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh index 1e06f14..ad9cdcc 100755 --- a/rofi/rofi-ssh-menu.sh +++ b/rofi/rofi-ssh-menu.sh @@ -1,19 +1,20 @@ #!/bin/bash res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|\ -kipary.mailcleaner.net|media.lan.john.me.tz|pipcam.lan.john.me.tz|\ -therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz" | \ +kipary.fastnet.ch|media.lan.john.me.tz|pipcam0.lan.john.me.tz|\ +therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz" | \ rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config \ /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ -padding 12 -opacity 100 -auto-select -no-fullscreen) +echo $res > /home/jpm/.last_ssh_shortcut if [ $res = "john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs w' elif [ $res = "root@john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs r' elif [ $res = "shb.ng" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs s' -elif [ $res = "kipary.mailcleaner.net" ]; then +elif [ $res = "kipary.fastnet.ch" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs d' elif [ $res = "camera.lan.john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs c' @@ -29,5 +30,7 @@ elif [ $res = "therm.lan.john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs t' elif [ $res = "vm.lan.john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs v' +elif [ $res = "mac.lan.john.me.tz" ]; then + /usr/bin/gvncviewer 192.168.2.10 >> /home/jpm/macos fi exit 0 From 3ace506009a9d3025708334c18b526f060692bae Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:22:03 -0400 Subject: [PATCH 027/110] Fix resolution of Sam, change new output mapping --- sway/displays.pl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index 5c1d306..739ca23 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -50,10 +50,9 @@ my $active_outputs = "$ENV{'HOME'}/.config/active_outputs"; my %outputs = ( #'0x00000101' => 'Sam', 'HTNCB00059' => 'Sam', - #'3CQ3310Q1Q' => 'Sam', - '3CQ4342S6W' => 'HP-1', - '0x00000101' => 'HP-2', - #'3CQ3310Q1Q' => 'HP-2', + #'3CQ4342S6W' => 'HP-1', + '0x00000101' => 'HP-1', + '3CQ3310Q1Q' => 'HP-2', '0x00000000' => 'LVDS' ); @@ -89,7 +88,7 @@ my %configs = ( 'Sam' => { 'on' => 1, 'width' => 1920, - 'height' => 1080, + 'height' => 1280, 'x' => 960, 'y' => 0, 'rotate' => 0, From e88e59231fce8e733ed4c8e5d0d72895396091e2 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:23:35 -0400 Subject: [PATCH 028/110] Kodi no longer on Wireguard and requires (horrible) auth on LAN --- send-to-kodi.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/send-to-kodi.sh b/send-to-kodi.sh index e538f01..e40e422 100755 --- a/send-to-kodi.sh +++ b/send-to-kodi.sh @@ -1,12 +1,12 @@ #!/bin/bash # Required settings -host=10.10.0.66 +host=192.168.2.66 port=8080 # Optional login for Kodi -#user= -#pass= +user=kodi +pass=kodi # Settings for netcat (local file) local_hostname=$(hostname) From b754308a90d3dde33905b7ab46b085a1efcf9ecb Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:25:41 -0400 Subject: [PATCH 029/110] Move setup into function where it is required --- sway/gammastep.pl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sway/gammastep.pl b/sway/gammastep.pl index cc252c5..61e791f 100755 --- a/sway/gammastep.pl +++ b/sway/gammastep.pl @@ -8,11 +8,8 @@ use warnings; use LWP::UserAgent; use JSON::XS; -my $ua = LWP::UserAgent->new(); -my $json = JSON::XS->new(); my $location = "https://papillon.john.me.tz/data/location.json"; - -my $lat_lon = fetch_lat_lon($ua, $json, $location); +my $lat_lon = fetch_lat_lon($location); my $pid = fork; unless ($pid) { @@ -25,10 +22,15 @@ unless ($pid) { sub fetch_lat_lon { - my ($ua, $json, $location) = @_; + my ($location) = shift; + + my $ua = LWP::UserAgent->new(); + my $json = JSON::XS->new(); my $raw = $ua->get($location)->content(); + if (defined $raw) { + print($raw."\n"); my $decoded = $json->decode($raw); if (defined $decoded->{lat} && defined $decoded->{lon}) { return "$decoded->{lat}:$decoded->{lon}"; From a4a6f9a6b8690ddb380ca875b61383d49faa9d7a Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:27:52 -0400 Subject: [PATCH 030/110] Clean old file --- waybar/waybar-nmtui.sh | 9 --------- 1 file changed, 9 deletions(-) delete mode 100755 waybar/waybar-nmtui.sh diff --git a/waybar/waybar-nmtui.sh b/waybar/waybar-nmtui.sh deleted file mode 100755 index 8d4252a..0000000 --- a/waybar/waybar-nmtui.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -if [ "$(pgrep -c nmtui | cut -b 1)" -eq "0" ]; then - echo true - /usr/bin/xterm -e '/usr/bin/nmtui' -else - echo false - pkill nmtui 2&>1 /dev/null -fi From 216c264a7fe12de5c1fa9495d403648f3577b20d Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 27 Jul 2021 01:43:45 -0400 Subject: [PATCH 031/110] Add hyperlinks in README to relevant scripts --- README.md | 62 ++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 7fd54dc..60f4ce5 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ ## Audio -**audio/mute.sh** +[**audio/mute.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/audio/mute.sh) Just a simple script to toggle Alsa mute. -**audio/noise-cancel.sh** +[**audio/noise-cancel.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/audio/noise-cancel.sh) Add a noise-cancelled version of existing interfaces to Pulseaudio. -**audio/stream-podcasts.pl** +[**audio/stream-podcasts.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/audio/stream-podcasts.pl) Commandline podcast streamer. Fetchs the feed for desired podcasts, find items published today, then plays them in order. Given arguments, it will use those @@ -21,27 +21,23 @@ as feeds, otherwise it will use the hash listed in the script. I haven't used i3 in earnest for quite some time since moving to Sway, so it is very likely that some of these scripts are broken based on other config changes. -**i3/i3move.sh** +[**i3/i3move.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/i3/i3move.sh) When any of the Xrandr scripts below is run, it will print it's name to a config file. This script will read that config file and then knows how the outputs are arranged. Once this is known, it allows hotkeys to know which output to move a workspace to. -**i3/detached.sh** +[**i3/detached.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/i3/detached.sh) Xrandr config. Just the laptop display. -**i3/detached.sh** - -Xrandr config. Just the laptop display. - -**i3/home.sh** +[**i3/home.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/i3/home.sh) Xrandr config. Not a layout I currently use. Home is now the "stacked" view from sway/displays. -**i3/work.sh** +[**i3/work.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/i3/work.sh) Xrandr config. Vertical on the left, horizontal aligned to top of the vertical, and laptop directly below that. Left-to-right order is @@ -53,28 +49,28 @@ Vertical-Horizontal-Laptop. system. I use it for a bunch of stuff to supplement i3 and Sway to fill out same desktop niceties. See configs in 'dotfiles' repository. -**rofi/drun.sh** +[**rofi/drun.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/drun.sh) Simple launcher. -**rofi/rofi-openvpn.sh** +[**rofi/rofi-openvpn.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/rofi-openvpn.sh) Quick VPN switcher. -**rofi/rofi-power-menu.sh** +[**rofi/rofi-power-menu.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/rofi-power-menu.sh) Lock, log out, restart Sway/i3, restart waybar, hibernate, reboot, shutdown. -**rofi/rofi-send-to-kodi.sh** +[**rofi/rofi-send-to-kodi.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/rofi-send-to-kodi.sh) Forward pasted link to ./send-to-kodi.sh. -**rofi/rofi-ssh-menu.sh** +[**rofi/rofi-ssh-menu.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/rofi-ssh-menu.sh) Open a terminal to any SSH shortcut machine. (TODO: Integrate with 'sshs' to get machine list from there instead of a static list). -**rofi/sway-alt-tab.sh** +[**rofi/sway-alt-tab.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/sway/sway-alt-tab.sh) Show all currently running applications in Sway to locate window. @@ -84,14 +80,14 @@ Show all currently running applications in Sway to locate window. and tiling window manager. See configs in 'dotfiles' repository. Here are some scripts exclusively for automating or enhancing Sway. -**sway/displays.pl** +[**sway/displays.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/sway/displays.pl) Script to automatically configure wayland outputs using swaymsg. Also forks waybars for each display. Allows custom configurations. No argument will run the last used configuration (~/config/last_display). '-w' will run only waybar without changing displays. -**sway/gammastep.pl** +[**sway/gammastep.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/sway/gammastep.pl) Setup Gammastep based on current location. I don't have geolocation in my laptop, so this requires a URL that returns JSON, including a "lat" and "lon". @@ -105,7 +101,7 @@ phone similar to: It forks to keep running if terminal is killed. If location fails to be fetched it will try again every 5 seconds. -**sway/popup-term.pl** +[**sway/popup-term.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/sway/popup-term.pl) A DIY version of the Tilde terminal. If terminal is not running, it opens on the current display. If it is running but not on current dislpay, it moves to @@ -135,7 +131,7 @@ it to be *hidden*. ... ``` -**sway/swayidle.sh** +[**sway/swayidle.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/sway/swayidle.sh) Work in progress. These scripts don't currently work the way I like. @@ -145,32 +141,32 @@ certain periods of inactivity as well as prior to sleep and after wake. This script is meant to unify all of the actions into one script by accepting an option. -**sway/swayidlecountdown.sh** +[**sway/swayidlecountdown.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/sway/swayidlecountdown.sh) Prior to locking a countdown should be provided. Currently testing how to manage a countdown with Dunst, which doesn't actually support dynamic notifications. ## Thinkpad -**thinkpad/blc.pl** +[**thinkpad/blc.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/thinkpad/blc.pl) Overly complicated backlight brightness control script. Provides flexible control of backlight so that changes can be easily scripted or called from keyboard shortcuts. --help provides some usage docs. -**thinkpad/kbd_backlight.pl** +[**thinkpad/kbd_backlight.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/thinkpad/kbd_backlight.pl) Simple script to cycle keyboard backlight. Gets max brightness, current brightness and then changes then increments the current brightness. Uses mod of max+1 so that it will cycle back around to 0 (disabled) if it is already at max. -**thinkpad/pow.pl** +[**thinkpad/pow.pl**](https://git.john.me.tz/jpm/scripts/src/branch/master/thinkpad/pow.pl) Overly complicated battery and power status fetcher script. Can output stats as JSON, Waybar-friendly percentage and icon, or a pretty table suitable for use with plain-text notifications via notify-send or similar. -**thinkpad/user-thinkpad-control@.service** +[**thinkpad/user-thinkpad-controls@.service**](https://git.john.me.tz/jpm/scripts/src/branch/master/thinkpad/user-thinkpad-controls@.service) SystemD unit file used to give ownership of necessary sys files to whichever user it is enabled for `systemctl enable user-thinkpad-control@jpm`. Without @@ -184,39 +180,39 @@ taskbar for Sway (and other Wlroots-based wayland compositors). Waybar applets have hover and click functionality and have several scripts related to those. See the .config repository for the actual Waybar and Sway configs. -**waybar/waybar-cpu.sh** +[**waybar/waybar-cpu.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/waybar/waybar-cpu.sh) Launch htop in floating window (bottom-right). If already running, kill it. -**waybar/waybar-disk.sh** +[**waybar/waybar-disk.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/waybar/waybar-disk.sh) Notification with disk usage summaries. Renders properly with Dunst, but not Mako. -**waybar/waybar-mem.sh** +[**waybar/waybar-mem.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/waybar/waybar-mem.sh) Notification with memory usage summaries. -**waybar/waybar-nm.sh** +[**waybar/waybar-nm.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/waybar/waybar-nm.sh) Launch nmtui in floating window (bottom-right). If already running, kill it. ## Miscellaneous -**apply-gruvbox.sh** +[**apply-gruvbox.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/apply-gruvbox.sh) A single theme version of the one provided [here](https://raw.githubusercontent.com/Mayccoll/Gogh). Applies the theme to a variety of terminals. Not really necessary after cloning the 'dotfiles' repository. -**send-to-kodi.sh** +[**send-to-kodi.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/send-to-kodi.sh) [This script](https://github.com/allejok96/send-to-kodi) sends a URL or local file to a [Kodi](https://github.com/xbmc) media player. Only modified to have my local media server IP. -**setup_wireguard.sh** +[**setup_wireguard.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/setup_wireguard.sh) Script to install WireGuard and generate a config file. Requires modification with the server public IP, server public key, and change to first 3 octets if From c5d8ade430f202fbe07a6f6e7169b0856aeb7e87 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 30 Jul 2021 21:30:28 -0400 Subject: [PATCH 032/110] Added AndroidUSB mirroring option --- rofi/rofi-ssh-menu.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh index ad9cdcc..fad9032 100755 --- a/rofi/rofi-ssh-menu.sh +++ b/rofi/rofi-ssh-menu.sh @@ -2,7 +2,7 @@ res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|\ kipary.fastnet.ch|media.lan.john.me.tz|pipcam0.lan.john.me.tz|\ -therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz" | \ +therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz|AndroidUSB" | \ rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config \ /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ -padding 12 -opacity 100 -auto-select -no-fullscreen) @@ -32,5 +32,7 @@ elif [ $res = "vm.lan.john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs v' elif [ $res = "mac.lan.john.me.tz" ]; then /usr/bin/gvncviewer 192.168.2.10 >> /home/jpm/macos +elif [ $res = "AndroidUSB" ]; then + /usr/bin/scrcpy fi exit 0 From 77db7f3640d898f53e9ac35aa0f4e5a1fcf97b89 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 11 Aug 2021 18:05:30 -0400 Subject: [PATCH 033/110] Dump waybar config to semi-permanent destination Since a previous change combined all displays into a single file, it is no longer necessary to create many temporary configs. The latest config can just be dumped to the standard path so that running `waybar` on it's own will load it. --- sway/displays.pl | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index 739ca23..bee2afe 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -30,8 +30,8 @@ # "width": __WIDTH__ (optional) my $waybar_template = "$ENV{'HOME'}/.config/waybar/config.template"; -# Temporary directory to save generated waybar config(s) -my $waybar_temporary = '/tmp'; +# Path to actual config file generated from template +my $waybar_config = "$ENV{'HOME'}/.config/waybar/config"; # File to log and recover last used layout name my $last = "$ENV{'HOME'}/.config/last_display"; @@ -382,12 +382,8 @@ unless ($pid) { open STDOUT, '>>/dev/null'; open STDERR, '>>/dev/null'; # Write config to a temporary file - my $tmp = $waybar_temporary . "/waybar-" . time() .".config"; - open ($fh, '>', $tmp); + open ($fh, '>', $waybar_config); print $fh $waybar; close $fh; - `nohup waybar --config=$tmp >> waybar.log`; - - # Remove config - unlink $tmp; + `nohup waybar --config=$waybar_config >> waybar.log`; } From a4fcb838ef031ad25e0f7e3ae782bda3081e41b9 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 11 Aug 2021 18:36:36 -0400 Subject: [PATCH 034/110] Add a shortcut to (re)start yubioath-desktop --- README.md | 3 ++- rofi/rofi-power-menu.sh | 6 ++++-- rofi/rofi-yubioath.sh | 12 ++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100755 rofi/rofi-yubioath.sh diff --git a/README.md b/README.md index 60f4ce5..f334947 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,8 @@ Quick VPN switcher. [**rofi/rofi-power-menu.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/rofi-power-menu.sh) -Lock, log out, restart Sway/i3, restart waybar, hibernate, reboot, shutdown. +Lock, toggle displays, reload yubico authenticator, log out, restart Sway/i3, +reload waybar, hibernate, reboot, shutdown. [**rofi/rofi-send-to-kodi.sh**](https://git.john.me.tz/jpm/scripts/src/branch/master/rofi/rofi-send-to-kodi.sh) diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh index 03124d4..ba7eed7 100755 --- a/rofi/rofi-power-menu.sh +++ b/rofi/rofi-power-menu.sh @@ -12,17 +12,19 @@ fi if [[ $WM == 'i3' ]]; then res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) else - res=$(echo "🔒 Lock|🖵 Toggle Displays|↩ Logout|↻ Reload Sway|↻ Reload Waybar|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) + res=$(echo "🔒 Lock|🖵 Toggle Displays|⚿ Yubico Authenticator|↻ Reload Sway|↻ Reload Waybar|↩ Logout|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) fi if [ "$res" == "🔒 Lock" ]; then - ${WM}lock -c 323232 + ${WM}lock -c 1D2021 elif [ "$res" == "↩ Logout" ]; then # Prevent auto-login rm /home/jpm/.config/last_login_gui ${WM} exit elif [ "$res" == "🖵 Toggle Displays" ]; then /home/jpm/scripts/sway/toggle_outputs.sh +elif [ "$res" == "⚿ Yubico Authenticator" ]; then + /home/jpm/scripts/rofi/rofi-yubioath.sh elif [ "$res" == "↻ Reload i3" ]; then i3 reload elif [ "$res" == "↹ Restart i3" ]; then diff --git a/rofi/rofi-yubioath.sh b/rofi/rofi-yubioath.sh new file mode 100755 index 0000000..04467b5 --- /dev/null +++ b/rofi/rofi-yubioath.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +RUNNING=$(pgrep yubioath-deskto) + +if [ "$RUNNING" ]; then + kill $RUNNING + sudo systemctl stop pcscd.socket + sudo systemctl restart pcscd.service + sudo systemctl start pcscd.socket +fi + +QT_QPA_PLATFORMTHEME=qt5ct QT_QPA_PLATFORM=wayland QT_PLUGIN_PATH=/usr/lib/qt/plugins /usr/bin/yubioath-desktop & From b7beb9e6e7dc187f670e5a16a3aa38b23bd78522 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 11 Aug 2021 18:40:48 -0400 Subject: [PATCH 035/110] Remove timeout for disk usage notification --- waybar/waybar-disk.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waybar/waybar-disk.sh b/waybar/waybar-disk.sh index 69495c1..9800f5e 100755 --- a/waybar/waybar-disk.sh +++ b/waybar/waybar-disk.sh @@ -1,6 +1,6 @@ #!/bin/bash -notify-send -t 3000 Disks \ +notify-send Disks \ "$(lsblk -o NAME,SIZE,FSUSE%,MOUNTPOINT | grep -vP '^loop' | \ sed 's/MOUNTPOINT/MOUNT/' | sed -e 's/│ └─/+---/' | \ sed -e 's/ └─/+---/' | sed -e 's/├─/+-/' | sed -e 's/└─/+-/' | \ From 567d271786497155b429693ecd66d6735047da1d Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 11 Aug 2021 18:41:22 -0400 Subject: [PATCH 036/110] Switch to Xterm for htop window --- waybar/waybar-cpu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waybar/waybar-cpu.sh b/waybar/waybar-cpu.sh index 9346057..a38a684 100755 --- a/waybar/waybar-cpu.sh +++ b/waybar/waybar-cpu.sh @@ -3,5 +3,5 @@ if [ "$(pgrep -c htop)" -gt 0 ]; then pkill htop else - /usr/bin/uxterm -e htop + /usr/bin/xterm -e htop fi From 24457ca3385bf3b09c09103788096edb4989bd25 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 12 Aug 2021 17:27:40 -0400 Subject: [PATCH 037/110] Add sock and display id to allow non-attached execution SWAYSOCK is now static so it can be referenced by all of the swaymsg commands. waybar now includes a static WAYLAND_DISPLAY declaration. This allows for recovery/configuration via SSH as well as groundwork for udev (un)docking rules. --- sway/displays.pl | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index bee2afe..cad1074 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -30,6 +30,8 @@ # "width": __WIDTH__ (optional) my $waybar_template = "$ENV{'HOME'}/.config/waybar/config.template"; +my $swaysock = "/home/jpm/.config/sway-ipc.sock"; + # Path to actual config file generated from template my $waybar_config = "$ENV{'HOME'}/.config/waybar/config"; @@ -206,7 +208,7 @@ close($fh); # Fetch connected displays use JSON::XS; my $json = JSON::XS->new(); -my $displays_raw = `swaymsg -t get_outputs --raw`; +my $displays_raw = `swaymsg -s $swaysock -t get_outputs --raw`; my $displays = $json->decode($displays_raw); # For each connected display, collect the desired settings for enabled @@ -252,7 +254,8 @@ foreach my $output (keys %$on) { } } if (scalar(@unavailable)) { - die "Config requires unavailable output(s) " . join(', ', @unavailable) . "\n"; + die "Config requires unavailable output(s) " . join(', ', @unavailable) + . "\n"; } # Skip enabling/disabling displays if only running waybar (re)start @@ -262,13 +265,13 @@ unless ($waybar_only) { foreach (@off) { # Sway returns status as JSON - my $res_raw = `sway output $_ disable`; + my $res_raw = `swaymsg -s $swaysock output $_ disable`; my $res = $json->decode($res_raw)->[0]; # If failed, print to STDERR unless ($res->{success}) { - print STDERR "Error ($res->{error}) in command 'sway" - . "output $_ disable'\n"; + print STDERR "Error ($res->{error}) in command 'swaymsg" + . " -s $swaysock output $_ disable'\n"; } } @@ -316,7 +319,8 @@ foreach my $out (keys %$on) { push @active, $on->{$out}->{output}; unless ($waybar_only) { # Build command, starting by enabling and powering on - my $cmd = "sway output $on->{$out}->{output} enable dpms on"; + my $cmd = "swaymsg -s $swaysock output $on->{$out}->{output}" . + " enable dpms on"; # If additional options are provided, add them to command if (defined $on->{$out}->{rotate}) { @@ -328,7 +332,8 @@ foreach my $out (keys %$on) { if (defined $on->{$out}->{width} && defined $on->{$out}->{height} ) { - $cmd .= " mode $on->{$out}->{width}x$on->{$out}->{height}"; + $cmd .= " mode $on->{$out}->{width}x" . + "$on->{$out}->{height}"; } # Sway returns status as JSON @@ -337,7 +342,8 @@ foreach my $out (keys %$on) { # If failed, print to STDERR unless ($res->{success}) { - print STDERR "Error ($res->{error}) in command '$cmd'\n"; + print STDERR "Error ($res->{error}) in command " . + "'$cmd'\n"; } } @@ -371,7 +377,6 @@ open($fh, '>', $active_outputs); print $fh join(' ', @active); close($fh); - # Restore array formatting $waybar = '[' . $waybar . ']'; @@ -385,5 +390,5 @@ unless ($pid) { open ($fh, '>', $waybar_config); print $fh $waybar; close $fh; - `nohup waybar --config=$waybar_config >> waybar.log`; + `WAYLAND_DISPLAY=wayland-1 nohup waybar --config=$waybar_config >> waybar.log`; } From 4e388030f8dff01985b9ec37a362d7e3e4bb7ce0 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 31 Aug 2021 14:15:12 -0400 Subject: [PATCH 038/110] Rofi no longer supports Xresources config format --- rofi/drun.sh | 2 +- rofi/rofi-openvpn.sh | 2 +- rofi/rofi-ssh-menu.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rofi/drun.sh b/rofi/drun.sh index 616818d..f733a6f 100755 --- a/rofi/drun.sh +++ b/rofi/drun.sh @@ -4,7 +4,7 @@ ROFI=$(pgrep -c rofi | cut -b 1) echo $ROFI if [[ "$ROFI" -eq "0" ]]; then - rofi -config /home/jpm/.config/rofi/config -show drun + rofi -config /home/jpm/.config/rofi/config.rasi -show drun else killall rofi 2&>1 /dev/null fi diff --git a/rofi/rofi-openvpn.sh b/rofi/rofi-openvpn.sh index d83eaf4..e69bd47 100755 --- a/rofi/rofi-openvpn.sh +++ b/rofi/rofi-openvpn.sh @@ -2,7 +2,7 @@ # Passwordless sudo required -res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) +res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config.rasi -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) if [ $res = "Connection" ]; then /usr/bin/uxterm -e 'sudo /usr/bin/nmtui' diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh index fad9032..a93c6a9 100755 --- a/rofi/rofi-ssh-menu.sh +++ b/rofi/rofi-ssh-menu.sh @@ -4,7 +4,7 @@ res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|\ kipary.fastnet.ch|media.lan.john.me.tz|pipcam0.lan.john.me.tz|\ therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz|AndroidUSB" | \ rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config \ -/home/jpm/.config/rofi/config -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ +/home/jpm/.config/rofi/config.rasi -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ -padding 12 -opacity 100 -auto-select -no-fullscreen) echo $res > /home/jpm/.last_ssh_shortcut From 93125c95ee9cf5c1844119e73b0b95ff91fee7c6 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 11 Nov 2021 22:01:07 -0500 Subject: [PATCH 039/110] Dynamic scale for Yoga This is a big-ol hack. I should ideally just have an external file for the configs which differs for each device. --- sway/displays.pl | 79 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index cad1074..8a86095 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -30,7 +30,9 @@ # "width": __WIDTH__ (optional) my $waybar_template = "$ENV{'HOME'}/.config/waybar/config.template"; -my $swaysock = "/home/jpm/.config/sway-ipc.sock"; +#my $swaysock = "/home/jpm/.config/sway-ipc.sock"; +my $swaysock = `ls /run/user/1000/sway-ipc.1000*`; +chomp($swaysock); # Path to actual config file generated from template my $waybar_config = "$ENV{'HOME'}/.config/waybar/config"; @@ -76,13 +78,45 @@ my %configs = ( 'Sam' => { 'on' => 0 }, - 'LVDS' => { + 'eDP-1' => { 'on' => 1, 'width' => 1920, 'height' => 1080, 'x' => 0, 'y' => 0, 'rotate' => 0, + 'waybar' => 'bottom', + } + }, + 'stacked-laptop' => { + 'Sam' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1200, + 'x' => 960, + 'y' => 0, + 'rotate' => 0, + 'waybar' => 'bottom' + }, + 'HP-1' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 1920, + 'y' => 1200, + 'rotate' => 0, + 'waybar' => 'top' + }, + 'HP-2' => { + 'on' => 0 + }, + 'eDP-1' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 0, + 'y' => 1200, + 'rotate' => 0, 'waybar' => 'bottom' } }, @@ -90,7 +124,7 @@ my %configs = ( 'Sam' => { 'on' => 1, 'width' => 1920, - 'height' => 1280, + 'height' => 1200, 'x' => 960, 'y' => 0, 'rotate' => 0, @@ -114,7 +148,7 @@ my %configs = ( 'rotate' => 0, 'waybar' => 'top' }, - 'LVDS' => { + 'eDP-1' => { 'on' => 0 } }, @@ -152,6 +186,30 @@ my %configs = ( } ); +my $hostname = `hostname`; +chomp($hostname); +if ($hostname eq "yoga.lan.john.me.tz") { + $configs{'detached'}->{'eDP-1'}->{'width'} = 2560; + $configs{'detached'}->{'eDP-1'}->{'height'} = 1440; + $configs{'detached'}->{'eDP-1'}->{'scale'} = 1.333333; +} + + +######################################################################## +# Disable display from other laptop +######################################################################## + +if ($ENV{'SSH_AUTH_SOCK'} eq '/home/jpm/.ssh/ssh-agent.yoga.lan.john.me.tz.sock') { + foreach my $layout (keys %configs) { + delete($configs{$layout}{'LVDS'}); + } + $outputs{'0x00000000'} = 'eDP-1'; +} else { + foreach my $layout (keys %configs) { + delete($configs{$layout}{'eDP-1'}); + } +} + ######################################################################## # Program (do not edit below) ######################################################################## @@ -323,6 +381,9 @@ foreach my $out (keys %$on) { " enable dpms on"; # If additional options are provided, add them to command + if (defined $on->{$out}->{scale}) { + $cmd .= " scale $on->{$out}->{scale}"; + } if (defined $on->{$out}->{rotate}) { $cmd .= " transform $on->{$out}->{rotate}"; } @@ -364,7 +425,12 @@ foreach my $out (keys %$on) { $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; if (defined $on->{$out}->{width}) { - $waybar =~ s/__WIDTH__/$on->{$out}->{width}/; + my $x = $on->{$out}->{width}; + if (defined $on->{$out}->{scale}) { + $x = sprintf("%.0d", $x / $on->{$out}->{scale}); + print "width: $x\n"; + } + $waybar =~ s/__WIDTH__/$x/; # If width is not set, comment that line out to use default } else { $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; @@ -390,5 +456,6 @@ unless ($pid) { open ($fh, '>', $waybar_config); print $fh $waybar; close $fh; - `WAYLAND_DISPLAY=wayland-1 nohup waybar --config=$waybar_config >> waybar.log`; + my $waydisplay = $ENV{'WAYLAND_DISPLAY'} || 'wayland-0'; + `WAYLAND_DISPLAY=$waydisplay nohup waybar --config=$waybar_config >> waybar.log`; } From 2ef12fe5de751114ca38c1e18c5445e76b405260 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 10:47:35 -0500 Subject: [PATCH 040/110] Hack to support waybar autohide Small C program to send hide signal to bar. Coordination script which expects the C program to be compiled at scripts/waybar/toggle --- waybar/toggle-visibility.c | 30 ++++++++++++++++++++++++++++++ waybar/toggle.sh | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 waybar/toggle-visibility.c create mode 100755 waybar/toggle.sh diff --git a/waybar/toggle-visibility.c b/waybar/toggle-visibility.c new file mode 100644 index 0000000..1b2485f --- /dev/null +++ b/waybar/toggle-visibility.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include + +int main(int argc, char*argv[]) +{ + int pid; + if (argc <= 1) { + printf("No PID given\n"); + return(1); + } else if (argc > 2) { + printf("Too many arguments\n"); + return(1); + } else { + long val; + char *next; + val = strtol(argv[1], &next, 10); + if ((next == argv[1]) || (*next != '\0')) { + printf("Argument '%s' is not a number\n", argv[1]); + return(1); + } else { + pid = val; + } + } + kill(pid, SIGUSR1); + return(0); +} + diff --git a/waybar/toggle.sh b/waybar/toggle.sh new file mode 100755 index 0000000..705b053 --- /dev/null +++ b/waybar/toggle.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +ARG=$1 +if [[ $ARG == '' ]]; then + ARG="toggle" +fi + +if [[ $ARG == 'toggle' ]]; then + if [[ -e '/home/jpm/.config/waybar/.hidden' ]]; then + rm '/home/jpm/.config/waybar/.hidden'; + else + touch '/home/jpm/.config/waybar/.hidden'; + fi +elif [[ $ARG == 'hide' ]]; then + if [[ ! -e '/home/jpm/.config/waybar/.hidden' ]]; then + touch '/home/jpm/.config/waybar/.hidden'; + else + echo 'Already hidden. You may need to use the "invert" option if action is reversed'; + exit; + fi +elif [[ $ARG == 'show' ]]; then + if [[ -e '/home/jpm/.config/waybar/.hidden' ]]; then + rm '/home/jpm/.config/waybar/.hidden'; + else + echo 'Already shown. You may need to use the "invert" option if action is reversed'; + exit; + fi +elif [[ $ARG != 'invert' ]]; then + echo "Invalid argument"; +fi + +/home/jpm/scripts/waybar/toggle `pgrep waybar` From f13778fe52cb0fc97e1b5a96711990ea6c024284 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 10:57:34 -0500 Subject: [PATCH 041/110] Additional waybar commands --- waybar/waybar-audio.sh | 9 +++++++++ waybar/waybar-keyboard.sh | 10 ++++++++++ waybar/waybar-mpd.sh | 10 ++++++++++ waybar/waybar-todo.sh | 9 +++++++++ 4 files changed, 38 insertions(+) create mode 100755 waybar/waybar-audio.sh create mode 100755 waybar/waybar-keyboard.sh create mode 100755 waybar/waybar-mpd.sh create mode 100755 waybar/waybar-todo.sh diff --git a/waybar/waybar-audio.sh b/waybar/waybar-audio.sh new file mode 100755 index 0000000..e0dc2a1 --- /dev/null +++ b/waybar/waybar-audio.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +RUNNING=$(pgrep pavucontrol) + +if [ "$RUNNING" ]; then + kill $RUNNING 2&>1 /dev/null +else + /usr/bin/pavucontrol +fi diff --git a/waybar/waybar-keyboard.sh b/waybar/waybar-keyboard.sh new file mode 100755 index 0000000..5c49617 --- /dev/null +++ b/waybar/waybar-keyboard.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +FILE=/home/jpm/.config/onscreen-keyboard +if [ -f $FILE ]; then + rm $FILE + busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b false +else + touch $FILE + busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true +fi diff --git a/waybar/waybar-mpd.sh b/waybar/waybar-mpd.sh new file mode 100755 index 0000000..f35af59 --- /dev/null +++ b/waybar/waybar-mpd.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +RUNNING=$(pgrep ncmpcpp) + +if [ "$RUNNING" ]; then + kill $RUNNING 2&>1 /dev/null +else + echo "starting" + /usr/bin/xterm -e /usr/bin/ncmpcpp +fi diff --git a/waybar/waybar-todo.sh b/waybar/waybar-todo.sh new file mode 100755 index 0000000..83397ac --- /dev/null +++ b/waybar/waybar-todo.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +RUNNING=$(pgrep todotxt-machine) + +if [ "$RUNNING" ]; then + kill $RUNNING 2&>1 /dev/null +else + /usr/bin/xterm -e "/home/jpm/.local/bin/todotxt-machine /home/jpm/nextcloud/phone/todo.txt" +fi From b17582621b6589499d926cb935e442be56700eaa Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 11:04:49 -0500 Subject: [PATCH 042/110] Rofi screen rotation prompt --- rofi/rofi-sway-rotate.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100755 rofi/rofi-sway-rotate.sh diff --git a/rofi/rofi-sway-rotate.sh b/rofi/rofi-sway-rotate.sh new file mode 100755 index 0000000..4e617f9 --- /dev/null +++ b/rofi/rofi-sway-rotate.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Passwordless sudo required + +res=$(echo "Rotate 0 (Normal)|Rotate 90 (Keyboard right)|Rotate 180 (Upside-down)|Rotate 270 (Keyborad left)" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config.rasi -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) +if [[ $res == "Rotate 0 (Normal)" ]]; then + swaymsg output eDP-1 transform 0 +elif [[ $res == "Rotate 90 (Keyboard right)" ]]; then + swaymsg output eDP-1 transform 90 +elif [[ $res == "Rotate 180 (Upside-down)" ]]; then + swaymsg output eDP-1 transform 180 +elif [[ $res == "Rotate 270 (Keyboard left)" ]]; then + swaymsg output eDP-1 transform 270 +else + exit +fi From fb89f3eabc53165f3b5379d4d4fe96f3b449e661 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 11:08:28 -0500 Subject: [PATCH 043/110] Fix rofi theme Version change. Theme can no longer be referenced inside the main config --- rofi/drun.sh | 4 ++-- rofi/rofi-openvpn.sh | 4 ++-- rofi/rofi-power-menu.sh | 5 +++-- rofi/rofi-send-to-kodi.sh | 3 ++- rofi/rofi-ssh-menu.sh | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rofi/drun.sh b/rofi/drun.sh index f733a6f..490d1e3 100755 --- a/rofi/drun.sh +++ b/rofi/drun.sh @@ -1,10 +1,10 @@ #!/bin/bash -ROFI=$(pgrep -c rofi | cut -b 1) +ROFI=$(pgrep -xc rofi | cut -b 1) echo $ROFI if [[ "$ROFI" -eq "0" ]]; then - rofi -config /home/jpm/.config/rofi/config.rasi -show drun + rofi -config /home/jpm/.config/rofi/config.rasi -theme /home/jpm/.config/rofi/sidebar.rasi -show drun -lines 20 else killall rofi 2&>1 /dev/null fi diff --git a/rofi/rofi-openvpn.sh b/rofi/rofi-openvpn.sh index e69bd47..b8144c6 100755 --- a/rofi/rofi-openvpn.sh +++ b/rofi/rofi-openvpn.sh @@ -2,7 +2,7 @@ # Passwordless sudo required -res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config.rasi -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) +res=$(echo "Connection|John.Me.tz|MailCleaner|Disconnect|Restart" | rofi -sep "|" -dmenu -i -p 'P ' "" -columns 9 -width 45 -l 1 -config /home/jpm/.config/rofi/config.rasi -theme /home/jpm/.config/rofi/sidebar -hide-scrollbar -eh 1 -location 0 -auto-select -no-fullscreen) if [ $res = "Connection" ]; then /usr/bin/uxterm -e 'sudo /usr/bin/nmtui' @@ -28,4 +28,4 @@ fi # Waybar sometimes doesn't update with the VPN IP, for whatever reason. Restart it. # exits above because I change outputs more often than I change VPNs -/home/jpm/scripts/sway/displays.pl -w +#/home/jpm/scripts/sway/displays.pl -w diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh index ba7eed7..c574e02 100755 --- a/rofi/rofi-power-menu.sh +++ b/rofi/rofi-power-menu.sh @@ -10,9 +10,9 @@ else fi if [[ $WM == 'i3' ]]; then - res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) + res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -theme /home/jpm/.config/rofi/sidebar -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) else - res=$(echo "🔒 Lock|🖵 Toggle Displays|⚿ Yubico Authenticator|↻ Reload Sway|↻ Reload Waybar|↩ Logout|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -no-lazy-grab -auto-select -no-fullscreen) + res=$(echo "🔒 Lock|🖵 Toggle Displays|⚿ Yubico Authenticator|↻ Reload Sway|↻ Reload Waybar|↩ Logout|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -theme /home/jpm/.config/rofi/sidebar -no-lazy-grab -auto-select -no-fullscreen) fi if [ "$res" == "🔒 Lock" ]; then @@ -31,6 +31,7 @@ elif [ "$res" == "↹ Restart i3" ]; then i3 restart elif [ "$res" == "↻ Reload Sway" ]; then sway reload + /home/jpm/scripts/sway/displays.pl elif [ "$res" == "↻ Reload Waybar" ]; then # Need to integrate with sway/displays.pl for alternative outputs /home/jpm/scripts/sway/displays.pl -w diff --git a/rofi/rofi-send-to-kodi.sh b/rofi/rofi-send-to-kodi.sh index 9b3bd1e..412af0d 100755 --- a/rofi/rofi-send-to-kodi.sh +++ b/rofi/rofi-send-to-kodi.sh @@ -1,6 +1,7 @@ #!/bin/bash INPUT="$(rofi -dmenu -i -p 'Kodi:' "" -columns 1 -rows 7 -width 32 -l 1 \ - -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100)" + -theme /home/jpm/.config/rofi/sidebar -hide-scrollbar -eh 1 -location \ + 0 -padding 12 -opacity 100)" /home/jpm/scripts/send-to-kodi.sh $INPUT 2>&1 /dev/null diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh index a93c6a9..3e578f1 100755 --- a/rofi/rofi-ssh-menu.sh +++ b/rofi/rofi-ssh-menu.sh @@ -4,7 +4,7 @@ res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|\ kipary.fastnet.ch|media.lan.john.me.tz|pipcam0.lan.john.me.tz|\ therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz|AndroidUSB" | \ rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config \ -/home/jpm/.config/rofi/config.rasi -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ +/home/jpm/.config/rofi/config.rasi -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ -padding 12 -opacity 100 -auto-select -no-fullscreen) echo $res > /home/jpm/.last_ssh_shortcut From 04f1af06e69ee7bbe346500ee2f4dd1dc7780dcd Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 11:09:29 -0500 Subject: [PATCH 044/110] Ignore waybar toggle binary --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 31e27cf..ce22044 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ sshs # Just backups of Papillon scripts that don't have their own repo yet data +# binary file. From waybar/toggle-visibility.c +waybar/toggle From b8cbbb330b578591c49f2eb230ad3acf6f4465cc Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 11:48:24 -0500 Subject: [PATCH 045/110] working notifications for blc Not ideal. Requires manual installation of Gtk2::Notify which is no longer packaged by Debian and has broken dependencies. Need to migrate to a better notification library. Migration was initially made to Gtk2::Notify because it allows for replacing the content of an existing notification. No newer libraries appear to support this in Perl. This was the first "substantial" Perl program I've ever written; it may become the first which is re-written in a better supported language. --- thinkpad/blc.pl | 300 +++++++++++++++++++++++++++++------------------- 1 file changed, 180 insertions(+), 120 deletions(-) diff --git a/thinkpad/blc.pl b/thinkpad/blc.pl index 1183039..07f912b 100755 --- a/thinkpad/blc.pl +++ b/thinkpad/blc.pl @@ -1,5 +1,68 @@ #!/usr/bin/perl -w +# TODO: I reworked the argument parsing and broke the formatted output +# It was terrible in the first place, so rework that too. +# +# Work on a `date`-like format like: +# "+%c/%m = %p\%" +# %c - Current absolute +# %m - Maximum absolute value +# %p - Current percent +# +# to output like: +# 1000/10000 = 10% +# +# Create a new array of hashes to classify the ARGV elements, eg: +# $0 + "+%c" -= 10 +=4 =1 =100 "+%p" +# [ +# { +# "action" => "increment", +# "value" => 1 +# },{ +# "action" => "print", +# "value" => "+%c" +# },{ +# "action" => "decrement", +# "value" => 10 +# },{ +# "action" => "increment", +# "value" => 4 +# },{ +# "action" => "set", +# "value" => 1 +# },{ +# "action" => "set", +# "value" => 100 +# },{ +# "action" => "print", +# "value" => "+%p" +# } +# ] +# +# Process all of these in order. Add an option to show/hide action output +# so you can either get (shown): +# 100% 100000 90% 94% 1% 100% 100% +# or (hidden): +# 100000 100% +# +# All of the events would still occur between the output values. +# +# Add a delay option between increments and a delay between actions (does not +# apply to 'print'). This could be used to make a gradual sweep with: +# +# --delay-increment=100 --delay-action=0 +# +# or to blink with: +# +# --delay-increment=0 --delay-action=1000 +# +# With the latter, you could even have the backlight do morse code: +# clear | S ( . . . ) |pause| O ( _ _ _ ) |pause| +# =0 =100 =0 =100 =0 =100 =0 =0 =100 =100 =0 =100 =100 =0 =100 =100 =0 =0 ... +# +# Perhaps add an argument to repeat indefinitely. This is all getting a bit +# silly, but kinda fun to think about. + # Files containing current and max brightness values my $cur_file = "/sys/class/backlight/intel_backlight/brightness"; my $max_file = "/sys/class/backlight/intel_backlight/max_brightness"; @@ -8,12 +71,8 @@ my $last_file = "/home/jpm/.config/blc.last"; sub to_percent { my $value = shift; - if ($value eq "Permission Denied") { - return $value; - } else { - $value = int($value/get_max()*100); - return $value . '%'; - } + $value = int($value/get_max()*100); + return $value . '%'; } sub get_offset @@ -47,10 +106,9 @@ sub get_min sub writable { if (! -w $cur_file) { - return 0; - } else { - return 1; + die "You don't have permission to write $cur_file\n"; } + return 1; } sub increment @@ -66,8 +124,6 @@ sub increment print $c $target; close $c; return $target; - } else { - return "Permission Denied"; } } @@ -84,8 +140,6 @@ sub decrement print $c $target; close $c; return $target; - } else { - return "Permission Denied"; } } @@ -108,8 +162,6 @@ sub set } } return $value; - } else { - return "Permission Denied"; } } @@ -135,9 +187,9 @@ Actions: = VALUE Set backlight to specific value. VALUE greater than 100 will be treated as absolute value. VALUE eqaul to or less than 100 will be treated as a percentage -++ Increment by 1% ++ Increment by 1% += VALUE Increment by VALUE percent --- Decrement by 1% +- Decrement by 1% -= VALUE Decrement by VALUE percent Actions corrected to 1% or 100% if over or under. All actions @@ -187,110 +239,94 @@ Only one \'\\' is removed per block. eg. my $current = get_current(); my (@output, $target, $silent, $notify); +my $operation_found = 0; if (scalar @ARGV) { - for (my $i=0;$i get_max()) { - $target = set(get_max()); - } elsif ($target > 100) { - $target = set($target); - } else { - $target = set( - int((get_max()*$target/100)+1) - ); - } - if ($target eq "Permission Denied") { - @output = $target; - } else { - @output = to_percent($target); - } - last; - } else { - @output = ("No value after $ARGV[$i]"); - last; - } - } elsif ($ARGV[$i] eq '%') { + while ($arg = shift) { + if ($arg eq '%') { push @output,int(get_current()/get_max()*100); - } elsif ($ARGV[$i] eq '^') { + } elsif ($arg eq '^') { push @output,get_max(); - } elsif ($ARGV[$i] eq '==') { + } elsif ($arg eq '==') { push @output,get_current(); - } elsif ($ARGV[$i] eq '--help') { + } elsif ($arg eq '--help') { help(); print " (see --HELP).\n\n"; exit(); - } elsif ($ARGV[$i] eq '--HELP') { + } elsif ($arg eq '--HELP') { help(); advanced(); exit(); - } elsif ($ARGV[$i] eq '--silent') { - $silent = 'TRUE'; - } elsif ($ARGV[$i] =~ /^--notify/) { - $notify = 'TRUE'; - if ($ARGV[$i] =~ /=[0-9]+$/) { - $duration = $ARGV[$i]; + } elsif ($arg eq '--silent') { + $silent = 1; + } elsif ($arg =~ /^--notify/) { + $notify = 1; + if ($arg =~ /=[0-9]+$/) { + $duration = $arg; $duration =~ s/.*=([0-9]+)/$1/; } else { - $duration = 200; + $duration = 1000; } + } elsif ($arg eq '+') { + unshift(@ARGV,1); + unshift(@ARGV,'+='); + } elsif ($arg =~ /^\+=/) { + my $offset; + if ($arg =~ m/^\+=(.+)$/) { + $offset = $1; + } else { + $offset = shift || die "+= without accompanying offset value\n"; + } + unless ($offset =~ /^\d+$/) { + die "+= is not a number ($offset)\n"; + } + for (my $j=0;$j<$offset;$j++) { + $target = increment(); + @output = to_percent($target); + } + $operation_found = 1; + } elsif ($arg eq '-') { + unshift(@ARGV,1); + unshift(@ARGV,'-='); + } elsif ($arg =~ /^-=/) { + my $offset; + if ($arg =~ m/^-=(.+)$/) { + $offset = $1; + } else { + $offset = shift || die "-= without accompanying offset value\n"; + } + unless ($offset =~ /^\d+$/) { + die "-= is not a number ($offset)\n"; + } + for (my $j=0;$j<$offset;$j++) { + $target = decrement(); + @output = to_percent($target); + } + $operation_found = 1; + } elsif ($arg =~ m/^=/) { + my $value; + if ($arg =~ m/^=(.+)$/) { + $target = $1; + } else { + $target = shift || die "= without accompanying absolute value\n"; + } + unless ($target =~ /^\d+$/) { + die "= is not a number ($target)\n"; + } + if ($target < 1) { + $target = set(get_min()); + } elsif ($target > get_max()) { + $target = set(get_max()); + } elsif ($target > 100) { + $target = set($target); + } else { + $target = set( + int((get_max()*$target/100)+1) + ); + } + @output = to_percent($target); + $operation_found = 1; } else { - my $add = $ARGV[$i]; - $add =~ s/\\//; - push @output,$add; + push(@output,$arg); } } } else { @@ -305,29 +341,53 @@ if (scalar @ARGV) { ); } - open(my $fh,'>',$last_file); print $fh get_current(); close($fh); +print $_."\n" foreach(@output); if ($silent) { exit(); } elsif ($notify) { - # Don't output anything if the value didn't change - if ($current == get_current()) { - exit(); - } - my $concat; + my $concat = ''; foreach (@output) { $concat .= $_; } - system "notify-send --urgency=normal -i " - . "/usr/share/icons/Papirus-Dark-Grey/48x48/status/" - . "notification-display-brightness.svg -t " - . $duration - . ' "' - . $concat - . '"'; + #use Desktop::Notify; + #my $notify = Desktop::Notify->new(); + use Gtk2::Notify -init, "Backlight"; + my $notification = Gtk2::Notify::new('Backlight', $concat, '', "notification-display-brightness"); + #my $notification = $notify->create( + #'timeout' => $duration, + #'summary' => "Brightness", + #'body' => $concat, + #'hints' => { + ##'urgency' => 'NOTIFY_URGENCY_LOW', + #'x-canonical-private-synchronous' => 'blc', + #'value' => (split('%',$concat))[0] || 0 + #} + #); + #$notification->show; + #exit; + + $notification->set_hint_string('x-canonical-private-synchronous','blc'); + $notification->set_urgency('NOTIFY_URGENCY_LOW'); + $notification->set_hint_int32('value',(split('%',$concat))[0]); + $notification->set_timeout($duration); + $notification->show(); + exit; + print "notify-send --urgency=normal" + . ' --icon="notification-display-brightness"' + . ' --hint=string:x-canonical-private-synchronous:blc' + . ' --expire-time=' . $duration + . ' "Backlight"' + . ' "' . $concat . " '" . join("','", @output) . "'\""; + system "notify-send --urgency=normal" + . ' --icon="notification-display-brightness"' + . ' --hint=string:x-canonical-private-synchronous:blc' + . ' --hint=int:value:' . (split('%',$concat))[0] + . ' --expire-time=' . $duration + . ' "' . $concat . "\""; exit(); } else { print foreach @output; From d06ed5266f047b28faac530e477de28c5e23a634 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 31 Dec 2021 11:57:58 -0500 Subject: [PATCH 046/110] Add fallback bg, fix missing args, hide waybar If no background arguement exists, use a fallback colour. If no scale or transform argument exists use 1 and 0. Toggle off waybar on start (I don't think this works properly) --- sway/displays.pl | 52 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index 8a86095..5ddf8d4 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -86,6 +86,7 @@ my %configs = ( 'y' => 0, 'rotate' => 0, 'waybar' => 'bottom', + 'fallback' => '#000000' } }, 'stacked-laptop' => { @@ -96,7 +97,8 @@ my %configs = ( 'x' => 960, 'y' => 0, 'rotate' => 0, - 'waybar' => 'bottom' + 'waybar' => 'bottom', + 'fallback' => '#000000' }, 'HP-1' => { 'on' => 1, @@ -105,7 +107,8 @@ my %configs = ( 'x' => 1920, 'y' => 1200, 'rotate' => 0, - 'waybar' => 'top' + 'waybar' => 'top', + 'fallback' => '#000000' }, 'HP-2' => { 'on' => 0 @@ -117,7 +120,8 @@ my %configs = ( 'x' => 0, 'y' => 1200, 'rotate' => 0, - 'waybar' => 'bottom' + 'waybar' => 'bottom', + 'fallback' => '#000000' } }, 'stacked' => { @@ -128,7 +132,8 @@ my %configs = ( 'x' => 960, 'y' => 0, 'rotate' => 0, - 'waybar' => 'bottom' + 'waybar' => 'bottom', + 'fallback' => '#000000' }, 'HP-1' => { 'on' => 1, @@ -137,7 +142,8 @@ my %configs = ( 'x' => 1920, 'y' => 1200, 'rotate' => 0, - 'waybar' => 'top' + 'waybar' => 'top', + 'fallback' => '#000000' }, 'HP-2' => { 'on' => 1, @@ -146,7 +152,8 @@ my %configs = ( 'x' => 0, 'y' => 1200, 'rotate' => 0, - 'waybar' => 'top' + 'waybar' => 'top', + 'fallback' => '#000000' }, 'eDP-1' => { 'on' => 0 @@ -160,7 +167,8 @@ my %configs = ( 'x' => 0, 'y' => 225, 'rotate' => 270, - 'waybar' => 'top' + 'waybar' => 'top', + 'fallback' => '#000000' }, 'Sam' => { 'on' => 1, @@ -169,7 +177,8 @@ my %configs = ( 'x' => 1080, 'y' => 0, 'rotate' => 90, - 'waybar' => 'top' + 'waybar' => 'top', + 'fallback' => '#000000' }, 'HP-2' => { 'on' => 1, @@ -178,7 +187,8 @@ my %configs = ( 'x' => 2280, 'y' => 225, 'rotate' => 90, - 'waybar' => 'top' + 'waybar' => 'top', + 'fallback' => '#000000' }, 'LVDS' => { 'on' => 0, @@ -199,7 +209,7 @@ if ($hostname eq "yoga.lan.john.me.tz") { # Disable display from other laptop ######################################################################## -if ($ENV{'SSH_AUTH_SOCK'} eq '/home/jpm/.ssh/ssh-agent.yoga.lan.john.me.tz.sock') { +if ($ENV{'SSH_AUTH_SOCK'} eq '/home/jpm/.ssh/ssh-agent.sock') { foreach my $layout (keys %configs) { delete($configs{$layout}{'LVDS'}); } @@ -383,10 +393,14 @@ foreach my $out (keys %$on) { # If additional options are provided, add them to command if (defined $on->{$out}->{scale}) { $cmd .= " scale $on->{$out}->{scale}"; - } + } else { + $cmd .= " scale 1"; + } if (defined $on->{$out}->{rotate}) { $cmd .= " transform $on->{$out}->{rotate}"; - } + } else { + $cmd .= " transform 0"; + } if (defined $on->{$out}->{x} && defined $on->{$out}->{y}) { $cmd .= " position $on->{$out}->{x} $on->{$out}->{y}"; } @@ -396,9 +410,20 @@ foreach my $out (keys %$on) { $cmd .= " mode $on->{$out}->{width}x" . "$on->{$out}->{height}"; } + if (defined $on->{$out}->{bg} && + -f $on->{$out}->{bg}) + { + $cmd .= " bg $on->{$out}->{bg} fit"; + if (defined $on->{$out}->{fallback}) { + $cmd .= " $on->{$out}->{fallback}"; + } + } elsif (defined $on->{$out}->{fallback}) { + $cmd .= " bg $on->{$out}->{fallback} solid_color"; + } # Sway returns status as JSON my $res_raw = `$cmd`; + print $res_raw . "\n"; my $res = $json->decode($res_raw)->[0]; # If failed, print to STDERR @@ -428,7 +453,6 @@ foreach my $out (keys %$on) { my $x = $on->{$out}->{width}; if (defined $on->{$out}->{scale}) { $x = sprintf("%.0d", $x / $on->{$out}->{scale}); - print "width: $x\n"; } $waybar =~ s/__WIDTH__/$x/; # If width is not set, comment that line out to use default @@ -457,5 +481,5 @@ unless ($pid) { print $fh $waybar; close $fh; my $waydisplay = $ENV{'WAYLAND_DISPLAY'} || 'wayland-0'; - `WAYLAND_DISPLAY=$waydisplay nohup waybar --config=$waybar_config >> waybar.log`; + `WAYLAND_DISPLAY=$waydisplay nohup waybar -b waybar0 --config=$waybar_config >> waybar.log; /home/jpm/scripts/waybar/toggle.sh invert`; } From b3e2e009611946dcf4f6cb04515352a8bab82d48 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:16:30 -0400 Subject: [PATCH 047/110] Sticky the pop-up terminal while present --- sway/popup-term.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/popup-term.pl b/sway/popup-term.pl index 5e70e4f..b13e8e4 100755 --- a/sway/popup-term.pl +++ b/sway/popup-term.pl @@ -72,8 +72,10 @@ if (!defined($term_id)) { print "Term not on current workspace, bringing it\n"; `swaymsg "[con_id=$term_id]" move workspace $workspace`; `swaymsg "[con_id=$term_id]" focus`; + `swaymsg "[con_id=$term_id]" sticky enable`; # Otherwise hide it from whereever it is } else { print "Term is on current workspace or lost, moving to $hidden\n"; + `swaymsg "[con_id=$term_id]" sticky disable`; `swaymsg "[con_id=$term_id]" move workspace $hidden`; } From c7cecdab75ec547546852d72d80edc7878702f05 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:18:33 -0400 Subject: [PATCH 048/110] Disable debugging from kbd backlight script --- thinkpad/kbd_backlight.pl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/thinkpad/kbd_backlight.pl b/thinkpad/kbd_backlight.pl index 2107247..fdb62cb 100755 --- a/thinkpad/kbd_backlight.pl +++ b/thinkpad/kbd_backlight.pl @@ -15,7 +15,6 @@ if (open(my $m, '<', $maxfile)) { print "Failed to read $maxfile\n"; exit; } -print STDERR "max = $max\n"; if (open(my $c, '<', $current)) { $now = readline($c); @@ -25,7 +24,6 @@ if (open(my $c, '<', $current)) { print "Failed to read $current\n"; exit; } -print STDERR "now = $now\n"; if (open(my $fh, '>', $current)) { $new = (($now+1) % ($max+1)); @@ -36,4 +34,4 @@ if (open(my $fh, '>', $current)) { print "Failed to write $current\n"; exit; } -print STDERR "new = $new\n"; +#print STDERR "$new\n"; From b8e84128e0da59eafa632dd4a5fd1751e5f90979 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:19:52 -0400 Subject: [PATCH 049/110] Fixed deprecated rofi theme option --- rofi/rofi-power-menu.sh | 4 ++-- rofi/rofi-send-to-kodi.sh | 2 +- rofi/rofi-ssh-menu.sh | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh index c574e02..336311d 100755 --- a/rofi/rofi-power-menu.sh +++ b/rofi/rofi-power-menu.sh @@ -10,9 +10,9 @@ else fi if [[ $WM == 'i3' ]]; then - res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -theme /home/jpm/.config/rofi/sidebar -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) + res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) else - res=$(echo "🔒 Lock|🖵 Toggle Displays|⚿ Yubico Authenticator|↻ Reload Sway|↻ Reload Waybar|↩ Logout|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -theme /home/jpm/.config/rofi/sidebar -no-lazy-grab -auto-select -no-fullscreen) + res=$(echo "🔒 Lock|🖵 Toggle Displays|⚿ Yubico Authenticator|↻ Reload Sway|↻ Reload Waybar|↩ Logout|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -theme /home/jpm/.config/rofi/sidebar.rasi -no-lazy-grab -auto-select -no-fullscreen) fi if [ "$res" == "🔒 Lock" ]; then diff --git a/rofi/rofi-send-to-kodi.sh b/rofi/rofi-send-to-kodi.sh index 412af0d..2ff08c0 100755 --- a/rofi/rofi-send-to-kodi.sh +++ b/rofi/rofi-send-to-kodi.sh @@ -1,7 +1,7 @@ #!/bin/bash INPUT="$(rofi -dmenu -i -p 'Kodi:' "" -columns 1 -rows 7 -width 32 -l 1 \ - -theme /home/jpm/.config/rofi/sidebar -hide-scrollbar -eh 1 -location \ + -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location \ 0 -padding 12 -opacity 100)" /home/jpm/scripts/send-to-kodi.sh $INPUT 2>&1 /dev/null diff --git a/rofi/rofi-ssh-menu.sh b/rofi/rofi-ssh-menu.sh index 3e578f1..ae237d9 100755 --- a/rofi/rofi-ssh-menu.sh +++ b/rofi/rofi-ssh-menu.sh @@ -2,7 +2,8 @@ res=$(echo "john.me.tz|root@john.me.tz|t470s.lan.john.me.tz|shb.ng|\ kipary.fastnet.ch|media.lan.john.me.tz|pipcam0.lan.john.me.tz|\ -therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz|AndroidUSB" | \ +therm.lan.john.me.tz|hud.lan.john.me.tz|vm.lan.john.me.tz|mac.lan.john.me.tz|light.lan.john.me.tz|\ +AndroidUSB" | \ rofi -sep "|" -dmenu -i -p 'P ' "" -columns 1 -rows 1 -width 45 -l 1 -config \ /home/jpm/.config/rofi/config.rasi -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location 0 -yoffset 0 \ -padding 12 -opacity 100 -auto-select -no-fullscreen) @@ -30,6 +31,8 @@ elif [ $res = "therm.lan.john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs t' elif [ $res = "vm.lan.john.me.tz" ]; then /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs v' +elif [ $res = "light.lan.john.me.tz" ]; then + /usr/bin/urxvt -e /bin/bash -c '/home/jpm/scripts/sshs light' elif [ $res = "mac.lan.john.me.tz" ]; then /usr/bin/gvncviewer 192.168.2.10 >> /home/jpm/macos elif [ $res = "AndroidUSB" ]; then From 32e58ff147d6bd11a8cd1b834a00a98956986fbc Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:23:29 -0400 Subject: [PATCH 050/110] Change terminal application to maintain floating windows --- waybar/waybar-cpu.sh | 2 +- waybar/waybar-nm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/waybar/waybar-cpu.sh b/waybar/waybar-cpu.sh index a38a684..9346057 100755 --- a/waybar/waybar-cpu.sh +++ b/waybar/waybar-cpu.sh @@ -3,5 +3,5 @@ if [ "$(pgrep -c htop)" -gt 0 ]; then pkill htop else - /usr/bin/xterm -e htop + /usr/bin/uxterm -e htop fi diff --git a/waybar/waybar-nm.sh b/waybar/waybar-nm.sh index 54d5c94..d65f57f 100755 --- a/waybar/waybar-nm.sh +++ b/waybar/waybar-nm.sh @@ -5,5 +5,5 @@ RUNNING=$(pgrep nmtui) if [ "$RUNNING" ]; then kill $RUNNING 2&>1 /dev/null else - /usr/bin/xterm -e '/usr/bin/nmtui' + /usr/bin/uxterm -e '/usr/bin/nmtui' fi From c74d63c57772881895c167f7208cbe1d0483064a Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:24:18 -0400 Subject: [PATCH 051/110] Disable gtk2 notifications Dependency resolution has become a nightmare. Need to rewrite with a better supported library. --- thinkpad/blc.pl | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/thinkpad/blc.pl b/thinkpad/blc.pl index 07f912b..0514b47 100755 --- a/thinkpad/blc.pl +++ b/thinkpad/blc.pl @@ -353,22 +353,9 @@ if ($silent) { foreach (@output) { $concat .= $_; } - #use Desktop::Notify; - #my $notify = Desktop::Notify->new(); +=pod use Gtk2::Notify -init, "Backlight"; my $notification = Gtk2::Notify::new('Backlight', $concat, '', "notification-display-brightness"); - #my $notification = $notify->create( - #'timeout' => $duration, - #'summary' => "Brightness", - #'body' => $concat, - #'hints' => { - ##'urgency' => 'NOTIFY_URGENCY_LOW', - #'x-canonical-private-synchronous' => 'blc', - #'value' => (split('%',$concat))[0] || 0 - #} - #); - #$notification->show; - #exit; $notification->set_hint_string('x-canonical-private-synchronous','blc'); $notification->set_urgency('NOTIFY_URGENCY_LOW'); @@ -388,6 +375,8 @@ if ($silent) { . ' --hint=int:value:' . (split('%',$concat))[0] . ' --expire-time=' . $duration . ' "' . $concat . "\""; +=cut + exit(); } else { print foreach @output; From b0ec5cdafbcb8d0fb0341933f220fc5337f3ce7e Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:25:29 -0400 Subject: [PATCH 052/110] Add TV to configurations --- sway/displays.pl | 55 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index 5ddf8d4..46a96a1 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -57,7 +57,8 @@ my %outputs = ( #'3CQ4342S6W' => 'HP-1', '0x00000101' => 'HP-1', '3CQ3310Q1Q' => 'HP-2', - '0x00000000' => 'LVDS' + '0x00000000' => 'LVDS', + '0x00000101' => 'TV', ); ######################################################################## @@ -68,6 +69,38 @@ my %outputs = ( # Second-level keys are the display friendly-names, above # Third-level are the actual settings for that display my %configs = ( + 'TV' => { + 'HP-1' => { + 'on' => 0 + }, + 'HP-2' => { + 'on' => 0 + }, + 'Sam' => { + 'on' => 0 + }, + 'TV' => { + 'on' => 1, + 'width' => 3840, + 'height' => 2160, + 'x' => 0, + 'y' => 0, + 'rotate' => 0, + 'scale' => 1.333333333, + 'waybar' => 'top', + 'fallback' => '#000000' + }, + 'eDP-1' => { + 'on' => 1, + 'width' => 1920, + 'height' => 1080, + 'x' => 3079, + 'y' => 0, + 'rotate' => 0, + 'waybar' => 'bottom', + 'fallback' => '#000000' + } + }, 'detached' => { 'HP-1' => { 'on' => 0 @@ -78,6 +111,9 @@ my %configs = ( 'Sam' => { 'on' => 0 }, + 'TV' => { + 'on' => 0 + }, 'eDP-1' => { 'on' => 1, 'width' => 1920, @@ -113,6 +149,9 @@ my %configs = ( 'HP-2' => { 'on' => 0 }, + 'TV' => { + 'on' => 0 + }, 'eDP-1' => { 'on' => 1, 'width' => 1920, @@ -155,6 +194,9 @@ my %configs = ( 'waybar' => 'top', 'fallback' => '#000000' }, + 'TV' => { + 'on' => 0 + }, 'eDP-1' => { 'on' => 0 } @@ -190,7 +232,10 @@ my %configs = ( 'waybar' => 'top', 'fallback' => '#000000' }, - 'LVDS' => { + 'TV' => { + 'on' => 0 + }, + 'eDP-1' => { 'on' => 0, } } @@ -447,14 +492,14 @@ foreach my $out (keys %$on) { $waybar .= $template; # Replace basic preferences - $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/; - $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/; + $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/gg; + $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/gg; if (defined $on->{$out}->{width}) { my $x = $on->{$out}->{width}; if (defined $on->{$out}->{scale}) { $x = sprintf("%.0d", $x / $on->{$out}->{scale}); } - $waybar =~ s/__WIDTH__/$x/; + $waybar =~ s/__WIDTH__/$x/gg; # If width is not set, comment that line out to use default } else { $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg; From b74c0f0fafa8d10c15105679f7da181f650d3c49 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:26:56 -0400 Subject: [PATCH 053/110] Add lock functions to idle script --- sway/idle.sh | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sway/idle.sh b/sway/idle.sh index 5fc8a38..c93e922 100755 --- a/sway/idle.sh +++ b/sway/idle.sh @@ -4,14 +4,13 @@ BLFILE="/home/jpm/.config/blc.last" OPFILE="/home/jpm/.config/active_outputs" if [ -z $1 ]; then - echo "Missing argument: run, warn, sleep or" \ - " wake" + echo "Missing argument: start, warn, lock, unlock, sleep, wake, or resume" elif [ $1 == "start" ]; then swayidle -w timeout 270 "/home/jpm/scripts/sway/idle.sh warn" \ resume "/home/jpm/scripts/sway/idle.sh resume" \ timeout 300 "/home/jpm/scripts/sway/idle.sh sleep" \ resume "/home/jpm/scripts/sway/idle.sh wake" \ - before-sleep "/usr/bin/swaylock -c 323232" + before-sleep "/usr/bin/swaylock -c 000000" elif [ $1 == "warn" ]; then # Store current brightness echo $(/home/jpm/scripts/thinkpad/blc.pl %) > $BLFILE @@ -19,12 +18,19 @@ elif [ $1 == "warn" ]; then /home/jpm/scripts/thinkpad/blc.pl = 1 # Warning notifications /home/jpm/scripts/sway/idlecountdown.sh +elif [ $1 == "lock" ]; then + echo $(/home/jpm/scripts/thinkpad/blc.pl %) > $BLFILE + /home/jpm/scripts/thinkpad/blc.pl = 1 + ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t \ + 'screen -S irssi -X stuff "/nick jpmAFK^M"' +elif [ $1 == "unlock" ]; then + /home/jpm/scripts/thinkpad/blc.pl = `cat $BLFILE` elif [ $1 == "sleep" ]; then # Change nick to AFK ssh jpm@john.me.tz -i /home/jpm/.ssh/no_pass -t \ 'screen -S irssi -X stuff "/nick jpmAFK^M"' # Turn off monitor - for i in `cat $OPFILE`; do swaymsg "output $i dpms off"; done + #for i in `cat $OPFILE`; do swaymsg "output $i dpms off"; done elif [ $1 == "wake" ]; then # Kill additional counters that might have been started /home/jpm/scripts/sway/idle.sh resume @@ -32,12 +38,13 @@ elif [ $1 == "wake" ]; then /home/jpm/scripts/sway/displays.pl #for i in `cat $OPFILE`; do swaymsg "output $i dpms on"; done # Lock screen - swaylock -c 323232 + swaylock -c 000000 # Restore brightness level /home/jpm/scripts/thinkpad/blc.pl = $(cat $BLFILE) elif [ $1 == "resume" ]; then # Kill warning - for i in `pgrep idlecountdown`; do kill $i; done + for i in `pkill idlecountdown`; do kill $i; done + /home/jpm/scripts/thinkpad/blc.pl = $(cat $BLFILE) else - echo "Invalid argument: run, sleep or wake" + echo "Invalid argument: start, warn, lock, unlock, sleep, wake, or resume" fi From 402ce7fefacef771cd9909d5a643422afb4db250 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:34:12 -0400 Subject: [PATCH 054/110] Remove debugging. Test brightness effect (oled) --- sway/gammastep.pl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sway/gammastep.pl b/sway/gammastep.pl index 61e791f..22b1f58 100755 --- a/sway/gammastep.pl +++ b/sway/gammastep.pl @@ -17,7 +17,7 @@ unless ($pid) { open STDOUT, '>>/dev/null'; open STDERR, '>>/dev/null'; - `gammastep -l $lat_lon`; + `gammastep -l $lat_lon -b 1:0.7`; } sub fetch_lat_lon @@ -30,13 +30,10 @@ sub fetch_lat_lon my $raw = $ua->get($location)->content(); if (defined $raw) { - print($raw."\n"); my $decoded = $json->decode($raw); if (defined $decoded->{lat} && defined $decoded->{lon}) { return "$decoded->{lat}:$decoded->{lon}"; } - print $decoded->{lat}; - } sleep 5; return fetch_lat_lon($ua, $json, $location); From 274d9cc75b672416e23e1423274b9a2e0e77e79a Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:34:54 -0400 Subject: [PATCH 055/110] Switch to TV as docked configuration --- sway/toggle_outputs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/toggle_outputs.sh b/sway/toggle_outputs.sh index 5df74c0..c677991 100755 --- a/sway/toggle_outputs.sh +++ b/sway/toggle_outputs.sh @@ -3,7 +3,7 @@ CURRENT=`cat /home/jpm/.config/last_display` if [ "$CURRENT" == "detached" ]; then - /home/jpm/scripts/sway/displays.pl stacked + /home/jpm/scripts/sway/displays.pl TV else /home/jpm/scripts/sway/displays.pl detached fi From 7876519667b8d2de7a9d91493bfb96b0e964873e Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:36:00 -0400 Subject: [PATCH 056/110] Improve output for bar --- thinkpad/pow.pl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/thinkpad/pow.pl b/thinkpad/pow.pl index c49fd2b..57ac9eb 100755 --- a/thinkpad/pow.pl +++ b/thinkpad/pow.pl @@ -96,9 +96,8 @@ if ($bar) { use JSON::XS; my $json = JSON::XS->new(); my $powref = $json->decode($output); - my $icon; my $class = 'discharging'; - $output = '{"text": "' . $powref->{Total}->{Percentage} . '% '; + $output = '{"text": "'; if ($powref->{AC}->{Status} eq "Plugged-In") { $class = 'charging'; $output .= ""; @@ -115,7 +114,7 @@ if ($bar) { } else { $output .= ""; } - $output .= '", "tooltip": "' . $class . '", "class": "' . $class . '"}'; + $output .= $powref->{Total}->{Percentage} . '%", "tooltip": "' . $class . '", "class": "' . $class . '"}'; } elsif ($pretty) { use JSON::XS; my $json = JSON::XS->new(); From 7119ff819c088db48c0570df06e24ad850f9384d Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 19 Apr 2022 00:37:30 -0400 Subject: [PATCH 057/110] Add waybar function for apt Can fetch the current number of available package updates, then allow installation by clicking. --- waybar/waybar-apt.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 waybar/waybar-apt.sh diff --git a/waybar/waybar-apt.sh b/waybar/waybar-apt.sh new file mode 100755 index 0000000..961da92 --- /dev/null +++ b/waybar/waybar-apt.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +if [ "$1" == 'bar' ]; then + if [ ! -e ${HOME}/.spool/apt-upgradeable ]; then + sudo apt update >/dev/null 2>/dev/null + COUNT=`apt list --upgradable 2> /dev/null | wc -l` + let COUNT-- + echo $COUNT > /home/jpm/.spool/apt-upgradeable + else + COUNT=`cat ${HOME}/.spool/apt-upgradeable` + fi + if [ $COUNT -eq 0 ]; then + echo '{"text": "🗹", "tooltip": "Up-to-date", "class": "up-to-date"}' + else + echo '{"text": "⭳ '$COUNT'", "tooltip": "'$COUNT' updates available (click to download)", "class": "updateable"}' + fi +elif [ "$SUDO_USER" != '' ]; then + echo "Don't run with sudo. Run normally, but with a sudoer user" +elif [ $UID -eq 0 ]; then + echo "Don't run as root. Run normally, but with a sudoer user" +elif [ "$1" == 'upgrade' ]; then + /usr/bin/uxterm -e "sudo apt-get update && sudo apt-get full-upgrade -y && sudo apt-get autoremove -y && sudo apt-get clean -y && exit" + COUNT=`apt list --upgradable 2> /dev/null | wc -l` + let COUNT-- + echo $COUNT > /home/jpm/.spool/apt-upgradeable +elif [ "$1" == 'update' ]; then + sudo apt update >/dev/null 2>/dev/null + COUNT=`apt list --upgradable 2> /dev/null | wc -l` + let COUNT-- + echo $COUNT > /home/jpm/.spool/apt-upgradeable +else + echo "Missing argument: update, upgrade" +fi From cd362eea6f9d53a89d801bb4c87ba35269c28778 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 26 May 2022 12:08:29 -0400 Subject: [PATCH 058/110] waybar-pkg wrapper for apt and rpm-ostree move waybar-apt.sh to waybar-debian.sh and add waybar-fedora-silverblue.sh waybar-pkg checks the OS from /etc/os-release then forwards argument to the correct script --- waybar/{waybar-apt.sh => waybar-debian.sh} | 2 +- waybar/waybar-fedora-silverblue.sh | 38 ++++++++++++++++++++++ waybar/waybar-pkg.sh | 10 ++++++ 3 files changed, 49 insertions(+), 1 deletion(-) rename waybar/{waybar-apt.sh => waybar-debian.sh} (90%) create mode 100755 waybar/waybar-fedora-silverblue.sh create mode 100755 waybar/waybar-pkg.sh diff --git a/waybar/waybar-apt.sh b/waybar/waybar-debian.sh similarity index 90% rename from waybar/waybar-apt.sh rename to waybar/waybar-debian.sh index 961da92..e224a13 100755 --- a/waybar/waybar-apt.sh +++ b/waybar/waybar-debian.sh @@ -12,7 +12,7 @@ if [ "$1" == 'bar' ]; then if [ $COUNT -eq 0 ]; then echo '{"text": "🗹", "tooltip": "Up-to-date", "class": "up-to-date"}' else - echo '{"text": "⭳ '$COUNT'", "tooltip": "'$COUNT' updates available (click to download)", "class": "updateable"}' + echo '{"text": "⭳'$COUNT'", "tooltip": "'$COUNT' updates available (click to download)", "class": "updateable"}' fi elif [ "$SUDO_USER" != '' ]; then echo "Don't run with sudo. Run normally, but with a sudoer user" diff --git a/waybar/waybar-fedora-silverblue.sh b/waybar/waybar-fedora-silverblue.sh new file mode 100755 index 0000000..029c419 --- /dev/null +++ b/waybar/waybar-fedora-silverblue.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +COUNT=0 +function count() { + RESULTS="`rpm-ostree upgrade --check 2> /dev/null | grep 'rpm-md repo' | cut -d: -f3`;" + COUNT=0 + for i in $RESULTS; do + i=`echo $i | sed 's/;//'` + let COUNT=$COUNT+$i + done +} + +if [ "$1" == 'bar' ]; then + if [ ! -e ${HOME}/.spool/ostree-upgradeable ]; then + count + echo $COUNT > /home/jpm/.spool/ostree-upgradeable + else + COUNT=`cat ${HOME}/.spool/ostree-upgradeable` + fi + if [ $COUNT -eq 0 ]; then + echo '{"text": "🗹", "tooltip": "Up-to-date", "class": "up-to-date"}' + else + echo '{"text": "⭳'$COUNT'", "tooltip": "'$COUNT' updates available (click to download)", "class": "updateable"}' + fi +elif [ "$SUDO_USER" != '' ]; then + echo "Don't run with sudo. Run normally, but with a sudoer user" +elif [ $UID -eq 0 ]; then + echo "Don't run as root. Run normally, but with a sudoer user" +elif [ "$1" == 'upgrade' ]; then + /usr/bin/uxterm -e "rpm-ostree upgrade" + count + echo $COUNT > /home/jpm/.spool/ostree-upgradeable +elif [ "$1" == 'update' ]; then + count + echo $COUNT > /home/jpm/.spool/ostree-upgradeable +else + echo "Missing argument: update, upgrade, bar" +fi diff --git a/waybar/waybar-pkg.sh b/waybar/waybar-pkg.sh new file mode 100755 index 0000000..e7dabc5 --- /dev/null +++ b/waybar/waybar-pkg.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Get OS "ID" (lowercase name) and "VARIANT_ID" +ID="`grep '^ID=' /etc/os-release | cut -d= -f2`-`grep 'VARIANT_ID=' /etc/os-release | cut -d= -f2`" + +# Trim if no VARIANT exists (eg. 'debian') +ID=`echo $ID | sed -e 's/\-$//'` + +# Run appropriate script from same path as this one +eval `echo $0 $1| sed -e "s/pkg/${ID}/"` From 5c3a10ce76040057e9feba880783137058db7a7f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 6 Jun 2022 13:56:59 -0400 Subject: [PATCH 059/110] Cleanup and update paths --- sway/displays.pl | 68 ++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index 46a96a1..e3b0f66 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -28,20 +28,18 @@ # "output": __OUTPUT__ # "position": __POSITION__ # "width": __WIDTH__ (optional) -my $waybar_template = "$ENV{'HOME'}/.config/waybar/config.template"; +my $waybar_template = "$ENV{'HOME'}/.dotfiles/waybar/config.template"; -#my $swaysock = "/home/jpm/.config/sway-ipc.sock"; -my $swaysock = `ls /run/user/1000/sway-ipc.1000*`; -chomp($swaysock); +my $swaysock = $ENV{'SWAYSOCK'} || $ENV{'HOME'} . "/.spool/sway-ipc.sock"; # Path to actual config file generated from template my $waybar_config = "$ENV{'HOME'}/.config/waybar/config"; # File to log and recover last used layout name -my $last = "$ENV{'HOME'}/.config/last_display"; +my $last = "$ENV{'HOME'}/.spool/last_display"; # File to log active outputs (used by swayidle, and to attempt to restore -my $active_outputs = "$ENV{'HOME'}/.config/active_outputs"; +my $active_outputs = "$ENV{'HOME'}/.spool/active_outputs"; ######################################################################## # Display Serials and Names @@ -88,7 +86,7 @@ my %configs = ( 'rotate' => 0, 'scale' => 1.333333333, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'eDP-1' => { 'on' => 1, @@ -98,7 +96,7 @@ my %configs = ( 'y' => 0, 'rotate' => 0, 'waybar' => 'bottom', - 'fallback' => '#000000' + 'fallback' => '#282828' } }, 'detached' => { @@ -122,7 +120,7 @@ my %configs = ( 'y' => 0, 'rotate' => 0, 'waybar' => 'bottom', - 'fallback' => '#000000' + 'fallback' => '#282828' } }, 'stacked-laptop' => { @@ -134,7 +132,7 @@ my %configs = ( 'y' => 0, 'rotate' => 0, 'waybar' => 'bottom', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'HP-1' => { 'on' => 1, @@ -144,7 +142,7 @@ my %configs = ( 'y' => 1200, 'rotate' => 0, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'HP-2' => { 'on' => 0 @@ -160,7 +158,7 @@ my %configs = ( 'y' => 1200, 'rotate' => 0, 'waybar' => 'bottom', - 'fallback' => '#000000' + 'fallback' => '#282828' } }, 'stacked' => { @@ -172,7 +170,7 @@ my %configs = ( 'y' => 0, 'rotate' => 0, 'waybar' => 'bottom', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'HP-1' => { 'on' => 1, @@ -182,7 +180,7 @@ my %configs = ( 'y' => 1200, 'rotate' => 0, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'HP-2' => { 'on' => 1, @@ -192,7 +190,7 @@ my %configs = ( 'y' => 1200, 'rotate' => 0, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'TV' => { 'on' => 0 @@ -210,7 +208,7 @@ my %configs = ( 'y' => 225, 'rotate' => 270, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'Sam' => { 'on' => 1, @@ -220,7 +218,7 @@ my %configs = ( 'y' => 0, 'rotate' => 90, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'HP-2' => { 'on' => 1, @@ -230,7 +228,7 @@ my %configs = ( 'y' => 225, 'rotate' => 90, 'waybar' => 'top', - 'fallback' => '#000000' + 'fallback' => '#282828' }, 'TV' => { 'on' => 0 @@ -312,11 +310,12 @@ if (!defined($configs{$config})) { } # Write config that is to be used so that it can be recovered as default -open(my $fh, '>', $last) || - print STDERR "Config name cannot be written to $last\n"; -print $fh $config; -close($fh); - +if (open(my $fh, '>', $last)) { + print $fh $config; + close($fh); +} else { + print STDERR "Config name cannot be logged to: $last\n"; +} # Fetch connected displays use JSON::XS; @@ -468,7 +467,7 @@ foreach my $out (keys %$on) { # Sway returns status as JSON my $res_raw = `$cmd`; - print $res_raw . "\n"; + #print $res_raw . "\n"; my $res = $json->decode($res_raw)->[0]; # If failed, print to STDERR @@ -508,9 +507,13 @@ foreach my $out (keys %$on) { } } -open($fh, '>', $active_outputs); -print $fh join(' ', @active); -close($fh); +# Log active outputs for recovery after crash/reboot +if (open(my $fh, '>', $active_outputs)) { + print $fh join(' ', @active); + close($fh); +} else { + print STDERR "Cannot write active outputs to: $active_outputs\n"; +} # Restore array formatting $waybar = '[' . $waybar . ']'; @@ -522,9 +525,12 @@ unless ($pid) { open STDOUT, '>>/dev/null'; open STDERR, '>>/dev/null'; # Write config to a temporary file - open ($fh, '>', $waybar_config); - print $fh $waybar; - close $fh; + if (open (my $fh, '>', $waybar_config)) { + print $fh $waybar; + close $fh; + } else { + die "Failed to write configuration file: $waybar_config\n"; + } my $waydisplay = $ENV{'WAYLAND_DISPLAY'} || 'wayland-0'; - `WAYLAND_DISPLAY=$waydisplay nohup waybar -b waybar0 --config=$waybar_config >> waybar.log; /home/jpm/scripts/waybar/toggle.sh invert`; + `WAYLAND_DISPLAY=$waydisplay nohup waybar -b waybar0 --config=$waybar_config >> $ENV{'HOME'}/.waybar.log`; } From 82b536a8900b0c443412ba916d0a01f1158e1aff Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 6 Jun 2022 13:58:30 -0400 Subject: [PATCH 060/110] Disable notification timeout --- waybar/waybar-disk.sh | 2 +- waybar/waybar-mem.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/waybar/waybar-disk.sh b/waybar/waybar-disk.sh index 9800f5e..3c94bc8 100755 --- a/waybar/waybar-disk.sh +++ b/waybar/waybar-disk.sh @@ -1,6 +1,6 @@ #!/bin/bash -notify-send Disks \ +notify-send -t 0 Disks \ "$(lsblk -o NAME,SIZE,FSUSE%,MOUNTPOINT | grep -vP '^loop' | \ sed 's/MOUNTPOINT/MOUNT/' | sed -e 's/│ └─/+---/' | \ sed -e 's/ └─/+---/' | sed -e 's/├─/+-/' | sed -e 's/└─/+-/' | \ diff --git a/waybar/waybar-mem.sh b/waybar/waybar-mem.sh index 02cf10a..7827b15 100755 --- a/waybar/waybar-mem.sh +++ b/waybar/waybar-mem.sh @@ -1,5 +1,5 @@ #!/bin/bash -notify-send 'Memory Usage' "`free -h | \ +notify-send -t 0 'Memory Usage' "`free -h | \ awk '{printf(\"%6s %6s %6s %6s\n\", $1, $2, $3, $4)}' | \ sed -r 's/(.*) shared$/ \1/'`" From bf19e6c0d2cdf6488d4c3998dec38267a2c712e5 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 6 Jun 2022 13:59:08 -0400 Subject: [PATCH 061/110] Update paths --- sway/startsway.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sway/startsway.sh b/sway/startsway.sh index e4998f2..a39fb54 100755 --- a/sway/startsway.sh +++ b/sway/startsway.sh @@ -1,5 +1,4 @@ #!/bin/bash - -rm /home/jpm/.swaylog -echo sway > /home/jpm/.config/last_login_gui -exec sway 2> /home/jpm/.swaylog +rm $HOME/.swaylog +echo sway > $HOME/.spool/last_login_gui +exec SWAYSOCK="$HOME/.spool/sway-ipc.sock" sway --debug 2>> $HOME/.swaylog >> $HOME/.swaylog From 0f0a1c9011c21b39681ad5dc593fd3d59a6a0546 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 7 Jun 2022 08:05:45 -0400 Subject: [PATCH 062/110] Socket Path --- sway/startsway.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sway/startsway.sh b/sway/startsway.sh index a39fb54..607dd5e 100755 --- a/sway/startsway.sh +++ b/sway/startsway.sh @@ -1,4 +1,6 @@ #!/bin/bash rm $HOME/.swaylog echo sway > $HOME/.spool/last_login_gui -exec SWAYSOCK="$HOME/.spool/sway-ipc.sock" sway --debug 2>> $HOME/.swaylog >> $HOME/.swaylog +export SWAYSOCK="$HOME/.spool/sway-ipc.sock" +sway --debug 2>> $HOME/.swaylog >> $HOME/.swaylog +export SWAYSOCK=`sway --get-socketpath` From 8842d7a3b0b3504ad426a5524071cac905585efb Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 28 Jun 2022 15:27:25 -0400 Subject: [PATCH 063/110] Int comparison typo --- thinkpad/pow.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/thinkpad/pow.pl b/thinkpad/pow.pl index 57ac9eb..3c7b0fb 100755 --- a/thinkpad/pow.pl +++ b/thinkpad/pow.pl @@ -101,15 +101,15 @@ if ($bar) { if ($powref->{AC}->{Status} eq "Plugged-In") { $class = 'charging'; $output .= ""; - } elsif ($powref->{Total}->{Percentage} le 10) { + } elsif ($powref->{Total}->{Percentage} <= 10) { $class = 'critical'; $output .= ""; - } elsif ($powref->{Total}->{Percentage} le 35) { + } elsif ($powref->{Total}->{Percentage} <= 35) { $class = 'low'; $output .= ""; - } elsif ($powref->{Total}->{Percentage} le 60) { + } elsif ($powref->{Total}->{Percentage} <= 60) { $output .= ""; - } elsif ($powref->{Total}->{Percentage} le 85) { + } elsif ($powref->{Total}->{Percentage} <= 85) { $output .= ""; } else { $output .= ""; From dcbb22bf8ab3151884720dd3d89f839a7744d81f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 20 Jul 2022 19:45:18 -0400 Subject: [PATCH 064/110] Simple weather bar applet --- waybar/waybar-weather.pl | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100755 waybar/waybar-weather.pl diff --git a/waybar/waybar-weather.pl b/waybar/waybar-weather.pl new file mode 100755 index 0000000..2f5efcd --- /dev/null +++ b/waybar/waybar-weather.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +my $cmd = 'bar'; +if (defined($ARGV[0])) { + $cmd = $ARGV[0]; +} + +my $url = "https://john.me.tz/weather/weather.json"; + +my %icons = ( + '04d' => "☁", +); +use LWP::UserAgent; +my $ua = LWP::UserAgent->new(); + +my $ret = $ua->get($url); +unless (defined($ret->{_rc}) && $ret->{_rc} == 200) { + die "Failed to fetch $url"; +} + +use JSON::XS; +my $json = JSON::XS->new(); + +my $ref = $json->decode($ret->{_content}); + +if ($cmd eq 'bar') { + my $temp = $ref->{current}->{temp} - 273.15; + my $icon = $ref->{current}->{weather}->[0]->{icon}; + + printf("%s%.1f%s", $icons{$icon}, ${temp}, "°C"); +} elsif ($cmd eq 'notify') { + `notify-send weather TODO`; +} else { + die "Invalid command\n"; +} From 8c1eddbf83684b8e7883750a0131c0ff760915bc Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 20 Jul 2022 23:11:59 -0400 Subject: [PATCH 065/110] Reboot prompt for updates Experimenting with swanag stuff. Check if reboot is required, nag to reboot, include installed packages in details. --- waybar/waybar-debian.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/waybar/waybar-debian.sh b/waybar/waybar-debian.sh index e224a13..b32fef3 100755 --- a/waybar/waybar-debian.sh +++ b/waybar/waybar-debian.sh @@ -23,6 +23,9 @@ elif [ "$1" == 'upgrade' ]; then COUNT=`apt list --upgradable 2> /dev/null | wc -l` let COUNT-- echo $COUNT > /home/jpm/.spool/apt-upgradeable + if [ -e /var/run/reboot-required ]; then + cat /var/log/apt/history.log | tr "\n" "%" | sed -e 's/.*\(Start-Date\)/\1/g' | tr "%" "\n" | swaynag --config=${HOME}/.dotfiles/sway/swaynag --edge=bottom --message="New packages require restart" --button="Restart Now" "sudo systemctl reboot" --dismiss-button="Later" --detailed-message --detailed-button "Show/Hide Upgrade Details" + fi elif [ "$1" == 'update' ]; then sudo apt update >/dev/null 2>/dev/null COUNT=`apt list --upgradable 2> /dev/null | wc -l` From f69be11cc6c790d4398f544a15134946e903d064 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 20 Jul 2022 23:34:02 -0400 Subject: [PATCH 066/110] Testing wofi with alt-tab Functional, but needs to be styled --- wofi/wofi-alt-tab.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100755 wofi/wofi-alt-tab.sh diff --git a/wofi/wofi-alt-tab.sh b/wofi/wofi-alt-tab.sh new file mode 100755 index 0000000..1bfa6cc --- /dev/null +++ b/wofi/wofi-alt-tab.sh @@ -0,0 +1,13 @@ +#!/bin/bash +swaymsg -t get_tree | + + jq -r '.nodes[].nodes[] | if .nodes then [recurse(.nodes[])] else [] end + .floating_nodes | .[] | select(.nodes==[]) | if .app_id then ((.app_id | tostring) + " -- " + .name) else .name end' | + grep -v '__i3_scratch' | + sed -e 's/\([^\-]\)\- *[^\-]*$/\1/' | + +sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | + +wofi -I --show dmenu | { + read -r id name + swaymsg "[con_id=$id]" focus +} From 57b2e765401a6581e46d9ad93b4b92a8c92f2f2f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Wed, 20 Jul 2022 23:34:39 -0400 Subject: [PATCH 067/110] Update wofi-alt-tab.sh formatting --- wofi/wofi-alt-tab.sh | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/wofi/wofi-alt-tab.sh b/wofi/wofi-alt-tab.sh index 1bfa6cc..d087523 100755 --- a/wofi/wofi-alt-tab.sh +++ b/wofi/wofi-alt-tab.sh @@ -4,10 +4,8 @@ swaymsg -t get_tree | jq -r '.nodes[].nodes[] | if .nodes then [recurse(.nodes[])] else [] end + .floating_nodes | .[] | select(.nodes==[]) | if .app_id then ((.app_id | tostring) + " -- " + .name) else .name end' | grep -v '__i3_scratch' | sed -e 's/\([^\-]\)\- *[^\-]*$/\1/' | - -sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | - -wofi -I --show dmenu | { - read -r id name - swaymsg "[con_id=$id]" focus -} + sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | + wofi -I --show dmenu | { + read -r id name + swaymsg "[con_id=$id]" focus + } From bb7a12a8b46d59bcca758c32aa38c896ea2b02f4 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 21 Jul 2022 17:15:21 -0400 Subject: [PATCH 068/110] Switch to 'model' instead of 'serial', clean display list --- sway/displays.pl | 282 ++++++++++++++--------------------------------- 1 file changed, 84 insertions(+), 198 deletions(-) diff --git a/sway/displays.pl b/sway/displays.pl index e3b0f66..f9051f0 100755 --- a/sway/displays.pl +++ b/sway/displays.pl @@ -45,18 +45,13 @@ my $active_outputs = "$ENV{'HOME'}/.spool/active_outputs"; # Display Serials and Names ######################################################################## -# Hash to match display Serial with a friendly name. -# You can get the serial from (quoted with *): -# $ swaymsg -t get_outputs -# Output eDP-1 'Unknown 0x057D *0x00000000*' +# Hash to match display model name to internal name +# You can get the model from (quoted with *): +# $ swaymsg -t get_outputs --raw my %outputs = ( - #'0x00000101' => 'Sam', - 'HTNCB00059' => 'Sam', - #'3CQ4342S6W' => 'HP-1', - '0x00000101' => 'HP-1', - '3CQ3310Q1Q' => 'HP-2', - '0x00000000' => 'LVDS', - '0x00000101' => 'TV', + 'LG TV SSCR2' => 'TV', + 'Paperlike253' => 'eInk', + '0x4140' => 'yoga' ); ######################################################################## @@ -67,14 +62,76 @@ my %outputs = ( # Second-level keys are the display friendly-names, above # Third-level are the actual settings for that display my %configs = ( + 'Both' => { + 'yoga' => { + 'on' => 0 + }, + 'eInk' => { + 'on' => 1, + 'width' => 3200, + 'height' => 1800, + 'x' => 0, + 'y' => 0, + 'rotate' => 90, + 'scale' => 2, + 'waybar' => 'top', + 'fallback' => '#fefefe', + }, + 'TV' => { + 'on' => 1, + 'width' => 3840, + 'height' => 2160, + 'x' => 900, + 'y' => 0, + 'rotate' => 0, + 'scale' => 1.33333, + 'waybar' => 'top', + 'fallback' => '#010101', + 'bg' => "$ENV{HOME}/wallpapers/wallpaper.png" + }, + }, + 'detached' => { + 'yoga' => { + 'on' => 1, + 'width' => 2560, + 'height' => 1440, + 'x' => 0, + 'y' => 0, + 'rotate' => 0, + 'scale' => 1.33333, + 'waybar' => 'bottom', + 'fallback' => '#010101', + 'bg' => "$ENV{HOME}/wallpapers/wallpaper.png" + }, + 'eInk' => { + 'on' => 0 + }, + 'TV' => { + 'on' => 0 + } + }, + 'eInk' => { + 'yoga' => { + 'on' => 0 + }, + 'eInk' => { + 'on' => 1, + 'width' => 3840, + 'height' => 2160, + 'x' => 0, + 'y' => 0, + 'rotate' => 0, + 'scale' => 1.33333, + 'waybar' => 'top', + 'fallback' => '#010101', + 'bg' => "$ENV{HOME}/wallpapers/wallpaper.png" + }, + 'TV' => { + 'on' => 0 + }, + }, 'TV' => { - 'HP-1' => { - 'on' => 0 - }, - 'HP-2' => { - 'on' => 0 - }, - 'Sam' => { + 'yoga' => { 'on' => 0 }, 'TV' => { @@ -84,185 +141,14 @@ my %configs = ( 'x' => 0, 'y' => 0, 'rotate' => 0, - 'scale' => 1.333333333, + 'scale' => 1.33333, 'waybar' => 'top', - 'fallback' => '#282828' + 'fallback' => '#010101', + 'bg' => "$ENV{HOME}/wallpapers/wallpaper.png" }, - 'eDP-1' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 3079, - 'y' => 0, - 'rotate' => 0, - 'waybar' => 'bottom', - 'fallback' => '#282828' - } - }, - 'detached' => { - 'HP-1' => { - 'on' => 0 - }, - 'HP-2' => { - 'on' => 0 - }, - 'Sam' => { - 'on' => 0 - }, - 'TV' => { - 'on' => 0 - }, - 'eDP-1' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 0, - 'y' => 0, - 'rotate' => 0, - 'waybar' => 'bottom', - 'fallback' => '#282828' - } - }, - 'stacked-laptop' => { - 'Sam' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1200, - 'x' => 960, - 'y' => 0, - 'rotate' => 0, - 'waybar' => 'bottom', - 'fallback' => '#282828' - }, - 'HP-1' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 1920, - 'y' => 1200, - 'rotate' => 0, - 'waybar' => 'top', - 'fallback' => '#282828' - }, - 'HP-2' => { - 'on' => 0 - }, - 'TV' => { - 'on' => 0 - }, - 'eDP-1' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 0, - 'y' => 1200, - 'rotate' => 0, - 'waybar' => 'bottom', - 'fallback' => '#282828' - } - }, - 'stacked' => { - 'Sam' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1200, - 'x' => 960, - 'y' => 0, - 'rotate' => 0, - 'waybar' => 'bottom', - 'fallback' => '#282828' - }, - 'HP-1' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 1920, - 'y' => 1200, - 'rotate' => 0, - 'waybar' => 'top', - 'fallback' => '#282828' - }, - 'HP-2' => { - 'on' => 1, - 'width' => 1920, - 'height' => 1080, - 'x' => 0, - 'y' => 1200, - 'rotate' => 0, - 'waybar' => 'top', - 'fallback' => '#282828' - }, - 'TV' => { - 'on' => 0 - }, - 'eDP-1' => { - 'on' => 0 - } - }, - 'sidebyside' => { - 'HP-1' => { - 'on' => 1, - 'width' => 1080, - 'height' => 1920, - 'x' => 0, - 'y' => 225, - 'rotate' => 270, - 'waybar' => 'top', - 'fallback' => '#282828' - }, - 'Sam' => { - 'on' => 1, - 'width' => 1200, - 'height' => 1920, - 'x' => 1080, - 'y' => 0, - 'rotate' => 90, - 'waybar' => 'top', - 'fallback' => '#282828' - }, - 'HP-2' => { - 'on' => 1, - 'width' => 1080, - 'height' => 1920, - 'x' => 2280, - 'y' => 225, - 'rotate' => 90, - 'waybar' => 'top', - 'fallback' => '#282828' - }, - 'TV' => { - 'on' => 0 - }, - 'eDP-1' => { - 'on' => 0, - } } ); -my $hostname = `hostname`; -chomp($hostname); -if ($hostname eq "yoga.lan.john.me.tz") { - $configs{'detached'}->{'eDP-1'}->{'width'} = 2560; - $configs{'detached'}->{'eDP-1'}->{'height'} = 1440; - $configs{'detached'}->{'eDP-1'}->{'scale'} = 1.333333; -} - - -######################################################################## -# Disable display from other laptop -######################################################################## - -if ($ENV{'SSH_AUTH_SOCK'} eq '/home/jpm/.ssh/ssh-agent.sock') { - foreach my $layout (keys %configs) { - delete($configs{$layout}{'LVDS'}); - } - $outputs{'0x00000000'} = 'eDP-1'; -} else { - foreach my $layout (keys %configs) { - delete($configs{$layout}{'eDP-1'}); - } -} - ######################################################################## # Program (do not edit below) ######################################################################## @@ -330,19 +216,19 @@ my @off; for (my $i = 0; $i < scalar(@$displays); $i++) { # If a display is found without any settings print error and turn it off - unless (defined $configs{$config}{$outputs{$displays->[$i]->{serial}}}){ + unless (defined $configs{$config}{$outputs{$displays->[$i]->{model}}}){ print STDERR "Output $displays->[$i]->{name} (" - . $displays->[$i]->{serial} + . $displays->[$i]->{model} . ") found without defined function. Disabling.\n"; push @off, $displays->[$i]->{name}; next; } # If display is enabled, copy all of the desired settings - if ($configs{$config}{$outputs{$displays->[$i]->{serial}}}{on}) { - $on->{$outputs{$displays->[$i]->{serial}}} = - $configs{$config}{$outputs{$displays->[$i]->{serial}}}; - $on->{$outputs{$displays->[$i]->{serial}}}{output} = + if ($configs{$config}{$outputs{$displays->[$i]->{model}}}{on}) { + $on->{$outputs{$displays->[$i]->{model}}} = + $configs{$config}{$outputs{$displays->[$i]->{model}}}; + $on->{$outputs{$displays->[$i]->{model}}}{output} = $displays->[$i]->{name}; # Otherwise simply list it for disabling } else { From 31fc3ceff3fa5753b3feb1aefb9fbc9375fb5e40 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 23 Jul 2022 01:12:03 -0400 Subject: [PATCH 069/110] Wallpaper rotation script --- sway/wallpaper.pl | 292 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100755 sway/wallpaper.pl diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl new file mode 100755 index 0000000..0cc9f6b --- /dev/null +++ b/sway/wallpaper.pl @@ -0,0 +1,292 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use lib "$ENV{HOME}/perl5/lib/perl5"; + +our $debug = 1; # For testing, will output configuration and errors if true + +use AnyEvent::Sway; +our $s = AnyEvent::Sway->new(); + +our $o = $s->get_outputs->recv(); +die "No outputs detected.\n" unless (scalar(@$o) > 1); + +sub usage() +{ + print("$0 [output(s)] [-d|--daemon]\n +Sets a wallpaper by cropping an appropriate sized section of a larger image.\n +All arguments other than the below are assumed to be output names, as defined +in my sway/displays.pl script. If no outputs are provided, all available that +are currently enabled will be set.\n +--path= Path to wallpaper directory. +-p Default: $ENV{HOME}/wallpapers\n +--daemon=N Configures the wallpaper to be periodically rotated for all +-d N of the given outputs. N indicates the number of seconds between + each rotation, if provided (default: 300).\n +--help This menu +-h\n"); + exit(0); +} + +$SIG{USR1} = sub { + # TODO: Update the timeout method so that the daemon will simply run the job as a function. + # when SIGUSR1 is received, force the alarm to expire immediately in order to rotate the image without delay. + print "This should rotate the image, but it doesn't yet"; +}; + +$SIG{TERM} = sub { + clean(); + exit(0); +}; + +$SIG{INT} = sub { + clean(); + exit(0); +}; + +sub clean +{ + my $pidfile = "/var/run/$ENV{HOME}-wallpaper.pid"; + if (-e $pidfile) { + open (my $fh, '<', $pidfile); + my $p = <$fh>; + chomp $p; + kill($p); + unlink($pidfile); + } +} + +sub choose_image +{ + my $path = shift; + + my @w = glob("$path/*"); + return undef unless (scalar(@w)); + + my @i; + foreach (@w) { + if (-d "$path/$_") { + next; + } + if ($_ =~ m/\.(png|jpg)$/) { + push(@i,$_); + } + } + + return $i[rand(scalar(@i))] || return undef; +} + +sub get_size +{ + my $target = shift; + foreach my $output (@$o) { + if ($output->{'name'} eq $target) { + return ( + #$output->{'current_mode'}->{'width'}, + #$output->{'current_mode'}->{'height'} + $output->{'rect'}->{'width'}, + $output->{'rect'}->{'height'} + ); + } + } + return undef; +} + +sub crop +{ + my $image = shift; + my $ow = shift; + my $oh = shift; + + my $cropped = $image; + $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#; + + use Image::Magick; + my $im = Image::Magick->new(); + + $im->Read($image); + my ($iw, $ih) = $im->Get("columns", "rows"); + + # Return full size if it is smaller in either dimension then the output + if ($iw < $ow || $ih < $oh) { + print "Not cropping $image because it is too small\n"; + $cropped =~ s#-cropped\.([^\.]+)$#\.$1#; + use File::Copy; + File::Copy::copy($image,$cropped); + return $cropped if (-e $cropped); + return undef; + } + + print "Image size: $iw $ih\n"; + print "output size: $ow $oh\n"; + + my ($x, $y); + $x = int(rand($iw-$ow)); + $y = int(rand($ih-$oh)); + + print "Cropping $image ${ow}x${oh}+${x}+${y}\n"; + my $err = $im->Crop(geometry=>"${ow}x${oh}+${x}+${y}"); + die "$err" if ($err); + print "Writing $cropped\n"; + $err = $im->Write($cropped); + die "$err" if ($err); + return $cropped if ( -e $cropped ); +} + +sub get_active +{ + my @targets; + foreach (@$o) { + push (@targets, $_->{name}); + } + return @targets; +} + +sub set_background +{ + my $target = shift || return "No target or image provided"; + my $cropped = shift || return "No image provided"; + # TODO get fallback from javascript + my $cmd = "output $target background $cropped fill #000000"; + print "Running $cmd\n"; + my $ret = $s->message(0,$cmd)->recv; + if ($ret->[0]->{success}) { + print "Success!\n"; + return undef; + } + return "Failed to run Sway IPC command '$cmd'"; +} + +my @targets; +my $daemon = 0; +my $delay = 300; +my $crop = 1; +my $path; + +while (my $arg = shift(@ARGV)) { + if ($arg eq '-h' || $arg eq '--help') { + usage(); + } elsif ($arg =~ m/^\-\-path=?(.+)$/) { + die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); + $path = $1; + } elsif ($arg eq '-p') { + die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); + $path = shift(@ARGV); + } elsif ($arg =~ m/^\-\-daemon=?(.+)$/) { + die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); + $delay = $1; + $daemon = 1; + } elsif ($arg eq '-d') { + die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); + if ($ARGV[0] =~ m/^\d+$/) { + $delay = shift(@ARGV); + } + $daemon = 1; + } elsif ($arg eq '--nocrop' || $arg eq '-') { + die "Redundant argument '$arg'. No-crop already set.\n" unless ($crop); + } else { + push(@targets,$arg); + } +} + +die "Invalid rotation delay: $delay" unless ($delay =~ m/^\d+$/); + +if ($path) { + die "Invalid wallpaper path '$path'. Not a directory." unless (-d $path); +} else { + $path = "$ENV{HOME}/wallpapers"; +} + +if (scalar(@targets)) { + my @kept; + foreach my $t (@targets) { + my $hit = 0; + foreach (@$o) { + if ($_->{name} eq $t) { + push(@kept, $t); + $hit++; + last; + } + } + print STDERR "Requested output '$t' not found\n" unless ($hit); + } + die "None of the requested outputs are active" unless (scalar(@kept)); + @targets = @kept; +} + +if ($daemon) { + my $p = fork(); + if ($p) { + my $pidfile = "/var/run/$ENV{HOME}-wallpaper.pid"; + open(my $fh, ">", $pidfile) || die "Failed to open pidfile: $pidfile"; + print $fh "Daemonized as PID: $p\n" || die "Failed to write pid ($p) to pidfile $pidfile"; + close($fh); + exit(0); + } +} + +if ($debug) { + print "Initial configuration:\n"; + print " Targets: ( " . ( join(" ",@targets) || "All active" ) . " )\n"; + print " Daemon: $daemon\n"; + print " Path: $path\n"; +} + +my @e; +do { + my @err; + # Local copy of targets so that it will re-check active every time + my @t = @targets; + unless (scalar(@t)) { + @t = get_active(); + push(@err, "No target outputs") unless (scalar(@t)); + } + foreach my $a (@t) { + my $image = choose_image($path); + if (defined($image)) { + if ( -r "$image" ) { + print "selected $image\n"; + my $cropped; + if ($crop) { + if ($debug) { + print "Cropping image for '$a' using '$image'\n"; + } + my ($ow, $oh) = get_size($a); + $cropped = crop($image, $ow, $oh); + unless ($cropped) { + push(@err, "Failed to generate cropped image") unless ($cropped); + next; + } + } else { + $cropped = $image; + } + my $e = set_background($a,$cropped); + push(@err, $e) if (defined($e)); + if ($crop) { + print "Deleting $cropped\n"; + #unlink($cropped) || push(@err, "Failed to delete $cropped after setting: $!"); + } + } else { + push(@err, "$a: Unable to read image $image"); + } + } else { + push(@err, "$a: Unable to select image from $path"); + } + } + if ($debug && $daemon) { + print STDERR join("\n",@err); + sleep($delay); + } else { + @e = @err; + } +} while ($daemon); + +if (scalar(@e)) { + die "Failure while not running as daemon:\n" . + join("\n",@e); +} + +exit(0); + From 640dd8d2d927563d418e628139b5673f3ba08c3f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 23 Jul 2022 01:32:23 -0400 Subject: [PATCH 070/110] Minor bugs Cropping should be avoided if the image is the same size also, not just if it is smaller. I was using a minimum of 2 outputs while testing on my desktop. Revert that to 1. Remove trailing tabs. --- sway/wallpaper.pl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index 0cc9f6b..f013c21 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -11,7 +11,7 @@ use AnyEvent::Sway; our $s = AnyEvent::Sway->new(); our $o = $s->get_outputs->recv(); -die "No outputs detected.\n" unless (scalar(@$o) > 1); +die "No outputs detected.\n" unless (scalar(@$o)); sub usage() { @@ -74,10 +74,10 @@ sub choose_image push(@i,$_); } } - + return $i[rand(scalar(@i))] || return undef; } - + sub get_size { my $target = shift; @@ -102,15 +102,15 @@ sub crop my $cropped = $image; $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#; - + use Image::Magick; my $im = Image::Magick->new(); - + $im->Read($image); my ($iw, $ih) = $im->Get("columns", "rows"); # Return full size if it is smaller in either dimension then the output - if ($iw < $ow || $ih < $oh) { + if ($iw <= $ow || $ih <= $oh) { print "Not cropping $image because it is too small\n"; $cropped =~ s#-cropped\.([^\.]+)$#\.$1#; use File::Copy; @@ -121,11 +121,11 @@ sub crop print "Image size: $iw $ih\n"; print "output size: $ow $oh\n"; - + my ($x, $y); $x = int(rand($iw-$ow)); $y = int(rand($ih-$oh)); - + print "Cropping $image ${ow}x${oh}+${x}+${y}\n"; my $err = $im->Crop(geometry=>"${ow}x${oh}+${x}+${y}"); die "$err" if ($err); From ab015142387cb2ae06b667ab97a2590b8d80acc3 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 23 Jul 2022 03:43:34 -0400 Subject: [PATCH 071/110] Implement signals Minimum viable product. TERM closes gracefully, KILL just removes PID, and USR1 rotates immediately and restarts timer. Other changes: - Whitespace - Implemented using lazy, excessive use of global variables. This needs to be improved. - Comment blocks --- sway/wallpaper.pl | 446 +++++++++++++++++++++++++--------------------- 1 file changed, 244 insertions(+), 202 deletions(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index f013c21..eec013b 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -2,10 +2,14 @@ use strict; use warnings; +use POSIX; use lib "$ENV{HOME}/perl5/lib/perl5"; our $debug = 1; # For testing, will output configuration and errors if true +our %settings; +our @e; +our $pidfile = "/tmp/$ENV{USER}-wallpaper.pid"; use AnyEvent::Sway; our $s = AnyEvent::Sway->new(); @@ -15,7 +19,7 @@ die "No outputs detected.\n" unless (scalar(@$o)); sub usage() { - print("$0 [output(s)] [-d|--daemon]\n + print("$0 [output(s)] [-d|--daemon]\n Sets a wallpaper by cropping an appropriate sized section of a larger image.\n All arguments other than the below are assumed to be output names, as defined in my sway/displays.pl script. If no outputs are provided, all available that @@ -24,268 +28,306 @@ are currently enabled will be set.\n -p Default: $ENV{HOME}/wallpapers\n --daemon=N Configures the wallpaper to be periodically rotated for all -d N of the given outputs. N indicates the number of seconds between - each rotation, if provided (default: 300).\n + each rotation, if provided (default: 300).\n --help This menu -h\n"); - exit(0); + exit(0); } +# SIGUSR reset the timer, force immediate reload, continue looping $SIG{USR1} = sub { - # TODO: Update the timeout method so that the daemon will simply run the job as a function. - # when SIGUSR1 is received, force the alarm to expire immediately in order to rotate the image without delay. - print "This should rotate the image, but it doesn't yet"; + alarm 0; + run(%settings); }; +# SIGTERM reset the timer, clean pid, and allow for the main loop to finish run $SIG{TERM} = sub { - clean(); - exit(0); + alarm 0; + clean(); + $settings{daemon} = 0; }; -$SIG{INT} = sub { - clean(); - exit(0); +# SIGKILL clean pid then exit immediately +$SIG{KILL} = sub { + clean(); + exit(0); }; sub clean { - my $pidfile = "/var/run/$ENV{HOME}-wallpaper.pid"; - if (-e $pidfile) { - open (my $fh, '<', $pidfile); - my $p = <$fh>; - chomp $p; - kill($p); - unlink($pidfile); - } + if (-e $pidfile) { + open (my $fh, '<', $pidfile); + my $p = <$fh>; + close($fh); + chomp $p; + kill($p); + unlink($pidfile); + } } sub choose_image { - my $path = shift; + my @w = glob("$settings{path}/*"); + return undef unless (scalar(@w)); - my @w = glob("$path/*"); - return undef unless (scalar(@w)); + my @i; + foreach (@w) { + if (-d "$settings{path}/$_") { + next; + } + if ($_ =~ m/\.(png|jpg)$/) { + push(@i,$_); + } + } - my @i; - foreach (@w) { - if (-d "$path/$_") { - next; - } - if ($_ =~ m/\.(png|jpg)$/) { - push(@i,$_); - } - } - - return $i[rand(scalar(@i))] || return undef; + return $i[rand(scalar(@i))] || return undef; } sub get_size { - my $target = shift; - foreach my $output (@$o) { - if ($output->{'name'} eq $target) { - return ( - #$output->{'current_mode'}->{'width'}, - #$output->{'current_mode'}->{'height'} - $output->{'rect'}->{'width'}, - $output->{'rect'}->{'height'} - ); - } - } - return undef; + my $target = shift; + foreach my $output (@$o) { + if ($output->{'name'} eq $target) { + return ( + #$output->{'current_mode'}->{'width'}, + #$output->{'current_mode'}->{'height'} + $output->{'rect'}->{'width'}, + $output->{'rect'}->{'height'} + ); + } + } + return undef; } sub crop { - my $image = shift; - my $ow = shift; - my $oh = shift; + my $image = shift; + my $ow = shift; + my $oh = shift; - my $cropped = $image; - $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#; + my $cropped = $image; + $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#; - use Image::Magick; - my $im = Image::Magick->new(); + use Image::Magick; + my $im = Image::Magick->new(); - $im->Read($image); - my ($iw, $ih) = $im->Get("columns", "rows"); + $im->Read($image); + my ($iw, $ih) = $im->Get("columns", "rows"); - # Return full size if it is smaller in either dimension then the output - if ($iw <= $ow || $ih <= $oh) { - print "Not cropping $image because it is too small\n"; - $cropped =~ s#-cropped\.([^\.]+)$#\.$1#; - use File::Copy; - File::Copy::copy($image,$cropped); - return $cropped if (-e $cropped); - return undef; - } + # Return full size if it is smaller in either dimension then the output + if ($iw <= $ow || $ih <= $oh) { + print "Not cropping $image because it is too small\n"; + $cropped =~ s#-cropped\.([^\.]+)$#\.$1#; + use File::Copy; + File::Copy::copy($image,$cropped); + return $cropped if (-e $cropped); + return undef; + } - print "Image size: $iw $ih\n"; - print "output size: $ow $oh\n"; + print "Image size: $iw $ih\n"; + print "output size: $ow $oh\n"; - my ($x, $y); - $x = int(rand($iw-$ow)); - $y = int(rand($ih-$oh)); + my ($x, $y); + $x = int(rand($iw-$ow)); + $y = int(rand($ih-$oh)); - print "Cropping $image ${ow}x${oh}+${x}+${y}\n"; - my $err = $im->Crop(geometry=>"${ow}x${oh}+${x}+${y}"); - die "$err" if ($err); - print "Writing $cropped\n"; - $err = $im->Write($cropped); - die "$err" if ($err); - return $cropped if ( -e $cropped ); + print "Cropping $image ${ow}x${oh}+${x}+${y}\n"; + my $err = $im->Crop(geometry=>"${ow}x${oh}+${x}+${y}"); + die "$err" if ($err); + print "Writing $cropped\n"; + $err = $im->Write($cropped); + die "$err" if ($err); + return $cropped if ( -e $cropped ); } sub get_active { - my @targets; - foreach (@$o) { - push (@targets, $_->{name}); - } - return @targets; + my @targets; + foreach (@$o) { + push (@targets, $_->{name}); + } + return @targets; } sub set_background { - my $target = shift || return "No target or image provided"; - my $cropped = shift || return "No image provided"; - # TODO get fallback from javascript - my $cmd = "output $target background $cropped fill #000000"; - print "Running $cmd\n"; - my $ret = $s->message(0,$cmd)->recv; - if ($ret->[0]->{success}) { - print "Success!\n"; - return undef; - } - return "Failed to run Sway IPC command '$cmd'"; + my $target = shift || return "No target or image provided"; + my $cropped = shift || return "No image provided"; + # TODO get fallback from javascript + my $cmd = "output $target background $cropped fill #000000"; + print "Running $cmd\n"; + my $ret = $s->message(0,$cmd)->recv; + if ($ret->[0]->{success}) { + print "Success!\n"; + return undef; + } + return "Failed to run Sway IPC command '$cmd'"; } +sub run +{ + my @err; + # Local copy of targets so that it will re-check active every time + my @t = $settings{targets} if (defined($settings{targets})); + unless (scalar(@t)) { + @t = get_active(); + push(@err, "No target outputs") unless (scalar(@t)); + } + foreach my $a (@t) { + my $image = choose_image($settings{path}); + if (defined($image)) { + if ( -r "$image" ) { + print "selected $image\n"; + my $cropped; + if ($settings{crop}) { + if ($settings{debug}) { + print "Cropping image for '$a' using '$image'\n"; + } + my ($ow, $oh) = get_size($a); + $cropped = crop($image, $ow, $oh); + unless ($cropped) { + push(@err, "Failed to generate cropped image") unless ($cropped); + next; + } + } else { + $cropped = $image; + } + my $e = set_background($a,$cropped); + push(@err, $e) if (defined($e)); + if ($settings{crop}) { + print "Deleting $cropped\n"; + #unlink($cropped) || push(@err, "Failed to delete $cropped after setting: $!"); + } + } else { + push(@err, "$a: Unable to read image $image"); + } + } else { + push(@err, "$a: Unable to select image from $settings{path}"); + } + } + if ($settings{debug} && $settings{daemon}) { + print STDERR join("\n",@err); + } else { + @e = @err; + } +} + +################################################################################ +# Collect arguments +################################################################################ my @targets; -my $daemon = 0; -my $delay = 300; -my $crop = 1; +my $daemon; +my $delay; +my $crop; my $path; - while (my $arg = shift(@ARGV)) { - if ($arg eq '-h' || $arg eq '--help') { - usage(); - } elsif ($arg =~ m/^\-\-path=?(.+)$/) { - die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); - $path = $1; - } elsif ($arg eq '-p') { - die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); - $path = shift(@ARGV); - } elsif ($arg =~ m/^\-\-daemon=?(.+)$/) { - die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); - $delay = $1; - $daemon = 1; - } elsif ($arg eq '-d') { - die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); - if ($ARGV[0] =~ m/^\d+$/) { - $delay = shift(@ARGV); - } - $daemon = 1; - } elsif ($arg eq '--nocrop' || $arg eq '-') { - die "Redundant argument '$arg'. No-crop already set.\n" unless ($crop); - } else { - push(@targets,$arg); - } + if ($arg eq '-h' || $arg eq '--help') { + usage(); + } elsif ($arg =~ m/^\-\-path=?(.+)$/) { + die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); + $path = $1; + } elsif ($arg eq '-p') { + die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); + $path = shift(@ARGV); + } elsif ($arg =~ m/^\-\-daemon=?(.+)$/) { + die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); + $delay = $1; + $daemon = 1; + } elsif ($arg eq '-d') { + die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); + if ($ARGV[0] =~ m/^\d+$/) { + $delay = shift(@ARGV); + } + $daemon = 1; + } elsif ($arg eq '--nocrop' || $arg eq '-') { + die "Redundant argument '$arg'. No-crop already set.\n" unless ($crop); + } else { + push(@targets,$arg); + } } -die "Invalid rotation delay: $delay" unless ($delay =~ m/^\d+$/); +################################################################################ +# Validate arguments +################################################################################ -if ($path) { - die "Invalid wallpaper path '$path'. Not a directory." unless (-d $path); -} else { - $path = "$ENV{HOME}/wallpapers"; -} +die "Invalid rotation delay: $delay" if (defined($delay) && $delay !~ m/^\d+$/); + +die "Invalid wallpaper path '$path'. Not a directory." if (defined($path) && !-d $path); if (scalar(@targets)) { - my @kept; - foreach my $t (@targets) { - my $hit = 0; - foreach (@$o) { - if ($_->{name} eq $t) { - push(@kept, $t); - $hit++; - last; - } - } - print STDERR "Requested output '$t' not found\n" unless ($hit); - } - die "None of the requested outputs are active" unless (scalar(@kept)); - @targets = @kept; + my @kept; + foreach my $t (@targets) { + my $hit = 0; + foreach (@$o) { + if ($_->{name} eq $t) { + push(@kept, $t); + $hit++; + last; + } + } + print STDERR "Requested output '$t' not found\n" unless ($hit); + } + die "None of the requested outputs are active" unless (scalar(@kept)); + @targets = @kept; } -if ($daemon) { - my $p = fork(); - if ($p) { - my $pidfile = "/var/run/$ENV{HOME}-wallpaper.pid"; - open(my $fh, ">", $pidfile) || die "Failed to open pidfile: $pidfile"; - print $fh "Daemonized as PID: $p\n" || die "Failed to write pid ($p) to pidfile $pidfile"; - close($fh); - exit(0); - } +$settings{targets} = @targets || undef; +$settings{daemon} = $daemon || 0; +$settings{path} = $path || "$ENV{HOME}/wallpapers"; +$settings{crop} = $crop || 1; +$settings{delay} = $delay || 300; +$settings{debug} = $debug || 0; + +################################################################################ +# For if daemonized +################################################################################ + +if ($settings{daemon}) { + my $p = fork(); + if ($p) { + if (open(my $fh, ">", $pidfile)) { + print $fh "$p" || die "Failed to write pid ($p) to pidfile $pidfile"; + close($fh); + } else { + print "Failed to open pidfile: $pidfile: $!\n"; + } + exit(0); + } + #setpgrp; + #setsid; + umask 0; + # TODO: configure systemD logging } -if ($debug) { - print "Initial configuration:\n"; - print " Targets: ( " . ( join(" ",@targets) || "All active" ) . " )\n"; - print " Daemon: $daemon\n"; - print " Path: $path\n"; -} +################################################################################ +# Main +################################################################################ -my @e; do { - my @err; - # Local copy of targets so that it will re-check active every time - my @t = @targets; - unless (scalar(@t)) { - @t = get_active(); - push(@err, "No target outputs") unless (scalar(@t)); - } - foreach my $a (@t) { - my $image = choose_image($path); - if (defined($image)) { - if ( -r "$image" ) { - print "selected $image\n"; - my $cropped; - if ($crop) { - if ($debug) { - print "Cropping image for '$a' using '$image'\n"; - } - my ($ow, $oh) = get_size($a); - $cropped = crop($image, $ow, $oh); - unless ($cropped) { - push(@err, "Failed to generate cropped image") unless ($cropped); - next; - } - } else { - $cropped = $image; - } - my $e = set_background($a,$cropped); - push(@err, $e) if (defined($e)); - if ($crop) { - print "Deleting $cropped\n"; - #unlink($cropped) || push(@err, "Failed to delete $cropped after setting: $!"); - } - } else { - push(@err, "$a: Unable to read image $image"); - } - } else { - push(@err, "$a: Unable to select image from $path"); - } - } - if ($debug && $daemon) { - print STDERR join("\n",@err); - sleep($delay); - } else { - @e = @err; - } -} while ($daemon); + run(%settings); + if ($settings{daemon}) { + my $normal = "reload wallpaper"; + eval { + $SIG{ALRM} = sub { print "$normal\n" }; + alarm $settings{delay}; + POSIX::pause(); + alarm 0; + }; + if ($@ && $@ !~ quotemeta($normal)) { + if ($settings{debug}) { + print $normal; + } + } + } +} while ($settings{daemon}); + +################################################################################ +# If we made it to here, it was not daemonized. Output errors and exit +################################################################################ if (scalar(@e)) { - die "Failure while not running as daemon:\n" . - join("\n",@e); + die "Failure while not running as daemon:\n" . + join("\n",@e); } exit(0); From 2a331db20bbbb02db3d0e72e0bcecca11b98249e Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 23 Jul 2022 03:58:11 -0400 Subject: [PATCH 072/110] Update usage and add some TODO comments --- sway/wallpaper.pl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index eec013b..9a39915 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -1,5 +1,10 @@ #!/usr/bin/env perl +# TODO: configure systemD logging +# TODO: refactor sloppy use of global variables +# TODO: clean up debugging output +# TODO: license, etc. + use strict; use warnings; use POSIX; @@ -29,8 +34,12 @@ are currently enabled will be set.\n --daemon=N Configures the wallpaper to be periodically rotated for all -d N of the given outputs. N indicates the number of seconds between each rotation, if provided (default: 300).\n +--nocrop Don't crop a selection from the image. Instead, pass the whole +-n image to swaybg and let it handle the scaling\n --help This menu --h\n"); +-h\n +You can send SIGUSR1 to force the daemon to reload immediately. Rotation timer +will be reset.\n"); exit(0); } @@ -296,7 +305,6 @@ if ($settings{daemon}) { #setpgrp; #setsid; umask 0; - # TODO: configure systemD logging } ################################################################################ @@ -331,4 +339,3 @@ if (scalar(@e)) { } exit(0); - From c47bb3d4c60148c7d8179139c9b9479de510f038 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 23 Jul 2022 03:59:03 -0400 Subject: [PATCH 073/110] Pureblack lockscreen --- rofi/rofi-power-menu.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rofi/rofi-power-menu.sh b/rofi/rofi-power-menu.sh index 336311d..9676a57 100755 --- a/rofi/rofi-power-menu.sh +++ b/rofi/rofi-power-menu.sh @@ -16,7 +16,7 @@ else fi if [ "$res" == "🔒 Lock" ]; then - ${WM}lock -c 1D2021 + ${WM}lock -c 000000 elif [ "$res" == "↩ Logout" ]; then # Prevent auto-login rm /home/jpm/.config/last_login_gui From a864b85df1726bc14fc1d2505709b69e7954ddbe Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 25 Jul 2022 17:03:18 -0400 Subject: [PATCH 074/110] Refactor, add SystemD Journaling --- sway/wallpaper.pl | 428 +++++++++++++++++++++++++++++----------------- 1 file changed, 272 insertions(+), 156 deletions(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index 9a39915..175a639 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -1,29 +1,32 @@ #!/usr/bin/env perl -# TODO: configure systemD logging -# TODO: refactor sloppy use of global variables -# TODO: clean up debugging output +# TODO: add option to allow recursive sub-directories (in choose_image()) # TODO: license, etc. use strict; use warnings; use POSIX; +use File::Copy; use lib "$ENV{HOME}/perl5/lib/perl5"; +$ENV{PWD} = '/tmp' unless (defined($ENV{PWD})); + +use constant ERROR => { + LOG_EMERG => 8, + LOG_ALERT => 7, + LOG_CRIT => 6, + LOG_ERR => 5, + LOG_WARNING => 4, + LOG_NOTICE => 3, + LOG_INFO => 2, + LOG_DEBUG => 1 +}; -our $debug = 1; # For testing, will output configuration and errors if true -our %settings; our @e; -our $pidfile = "/tmp/$ENV{USER}-wallpaper.pid"; - -use AnyEvent::Sway; -our $s = AnyEvent::Sway->new(); - -our $o = $s->get_outputs->recv(); -die "No outputs detected.\n" unless (scalar(@$o)); sub usage() { + my $self = shift; print("$0 [output(s)] [-d|--daemon]\n Sets a wallpaper by cropping an appropriate sized section of a larger image.\n All arguments other than the below are assumed to be output names, as defined @@ -36,6 +39,9 @@ are currently enabled will be set.\n each rotation, if provided (default: 300).\n --nocrop Don't crop a selection from the image. Instead, pass the whole -n image to swaybg and let it handle the scaling\n +--verbose=N Define minimum log level. Counting from 1: LOG_DEBUG, LOG_INFO, +-v N LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT, LOG_ALERT, LOG_EMERG + Default: 5; If provided without a value for N then all (1). --help This menu -h\n You can send SIGUSR1 to force the daemon to reload immediately. Rotation timer @@ -43,45 +49,136 @@ will be reset.\n"); exit(0); } +sub new +{ + my ($class, %args) = @_; + + use AnyEvent::Sway; + $args{ipc} = AnyEvent::Sway->new(); + use Image::Magick; + $args{im} = Image::Magick->new(); + $args{error} = (); + + $args{pidfile} = "/tmp/$ENV{USER}-wallpaper.pid"; + + return bless { %args }; +} + +my $wp = new("Wallpapers"); + +if (-e $wp->{pidfile}) { + if (-r $wp->{pidfile}) { + if (open(my $fh, '<', $wp->{pidfile})) { + my $pid = <$fh>; + chomp($pid); + use Proc::ProcessTable; + my $pt = Proc::ProcessTable->new(); + foreach my $p ( @{ $pt->table() } ) { + if ($p->{pid} eq $pid) { + my $name = $0; + $name =~ s/$ENV{PWD}//; + if ($p->{'cmndline'} =~ m#$name#) { + $wp->do_log("LOG_CRIT", "Another process is already running with PID: $pid (running and listed in $wp->{pidfile})"); + # Die locally because do_log will remove pidfile that this iteration does not belong to + exit(1); + } else { + $wp->do_log("LOG_CRIT", "Found matching $pid with different cmdline: $p->{cmndline} (not $0)",1); + # PID in pidfile doesn't look like it is another wallpaper + unlink($wp->{pidfile}); + last; + } + return $p->{'pid'}; + } + } + } else { + $wp->do_log("LOG_CRIT", "Pidfile $wp->{pidfile} exists, but cannot be opened. Assuming it is running already."); + # Die locally because do_log will remove pidfile that this iteration does not belong to + exit(1); + } + } else { + $wp->do_log("LOG_CRIT", "Pidfile $wp->{pidfile} exists, but is not readable. Assuming it is running already."); + # Die locally because do_log will remove pidfile that this iteration does not belong to + exit(1); + } +} + # SIGUSR reset the timer, force immediate reload, continue looping $SIG{USR1} = sub { alarm 0; - run(%settings); + $wp->do_log("LOG_INFO", "Reloading due to SIGUSR1"); }; # SIGTERM reset the timer, clean pid, and allow for the main loop to finish run $SIG{TERM} = sub { - alarm 0; - clean(); - $settings{daemon} = 0; + $wp->do_log("LOG_INFO", "Going down clean due to SIGTERM"); + clean($wp); + $wp->{daemon} = 0; }; # SIGKILL clean pid then exit immediately $SIG{KILL} = sub { - clean(); + $wp->do_log("LOG_INFO", "Hard kill with SIGKILL, attempting to remove pidfile"); + clean($wp); exit(0); }; +# simply returns the array of hashes provided by swaymsg +sub get_outputs +{ + my $self = shift; + my $o = $self->{ipc}->get_outputs->recv() || $self->do_log('LOG_WARNING',"Failed to query 'get_outputs'"); + die "No outputs detected.\n" unless (scalar(@$o) > 0); + return $o; +} + +# returns the same as above but with the 'name' as a hash key for easier lookup +sub get_active +{ + my $self = shift; + if (defined($self->{outputs}) && scalar($self->{outputs})) { + my %active = (); + foreach my $o (@{$self->{outputs}}) { + my $name; + my %details; + next unless ($o->{active}); + $active{$o->{name}} = (); + foreach (keys(%$o)) { + $active{$o->{name}}->{$_} = $o->{$_} unless ($_ eq 'name'); + } + } + $self->do_log('LOG_WARNING',"No outputs detected.") unless (scalar(keys(%active))); + return \%active; + } else { + print "You haven't initialized get_outputs"; + $self->do_log('LOG_WARNING',"Output list not defined yet. Try 'get_outputs()' first"); + return \{}; + } +} + sub clean { - if (-e $pidfile) { - open (my $fh, '<', $pidfile); + my $self = shift; + if (-e $self->{pidfile}) { + open (my $fh, '<', $self->{pidfile}); my $p = <$fh>; close($fh); chomp $p; kill($p); - unlink($pidfile); + unlink($self->{pidfile}); } } sub choose_image { - my @w = glob("$settings{path}/*"); + my $self = shift; + my @w = glob($self->{'path'}."/*"); return undef unless (scalar(@w)); + $self->do_log("LOG_DEBUG", "Found ".scalar(@w)." files in $self->{path}"); my @i; foreach (@w) { - if (-d "$settings{path}/$_") { + if (-d $_) { + $self->do_log("LOG_DEBUG", "Ignoring sub-directory $_"); next; } if ($_ =~ m/\.(png|jpg)$/) { @@ -92,24 +189,9 @@ sub choose_image return $i[rand(scalar(@i))] || return undef; } -sub get_size -{ - my $target = shift; - foreach my $output (@$o) { - if ($output->{'name'} eq $target) { - return ( - #$output->{'current_mode'}->{'width'}, - #$output->{'current_mode'}->{'height'} - $output->{'rect'}->{'width'}, - $output->{'rect'}->{'height'} - ); - } - } - return undef; -} - sub crop { + my $self = shift; my $image = shift; my $ow = shift; my $oh = shift; @@ -117,25 +199,21 @@ sub crop my $cropped = $image; $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#; + #$image = "/tmp/Pharma-out.png.jpg"; use Image::Magick; my $im = Image::Magick->new(); - - $im->Read($image); + die "$image is not readable" unless (-r $image); + my $ret = $im->Read($image); + return 0 if ($ret); my ($iw, $ih) = $im->Get("columns", "rows"); + $self->do_log("LOG_DEBUG", "Image has dimensions ${iw}x${ih}"); # Return full size if it is smaller in either dimension then the output if ($iw <= $ow || $ih <= $oh) { - print "Not cropping $image because it is too small\n"; - $cropped =~ s#-cropped\.([^\.]+)$#\.$1#; - use File::Copy; - File::Copy::copy($image,$cropped); - return $cropped if (-e $cropped); + $self->do_log("LOG_DEBUG", "Not cropping because ${iw}x${ih} is smaller or equal to the output (${ow}x${oh}) in at least 1 dimension."); return undef; } - print "Image size: $iw $ih\n"; - print "output size: $ow $oh\n"; - my ($x, $y); $x = int(rand($iw-$ow)); $y = int(rand($ih-$oh)); @@ -149,75 +227,118 @@ sub crop return $cropped if ( -e $cropped ); } -sub get_active -{ - my @targets; - foreach (@$o) { - push (@targets, $_->{name}); - } - return @targets; -} - sub set_background { + my $self = shift; my $target = shift || return "No target or image provided"; my $cropped = shift || return "No image provided"; # TODO get fallback from javascript my $cmd = "output $target background $cropped fill #000000"; - print "Running $cmd\n"; - my $ret = $s->message(0,$cmd)->recv; + $self->do_log("LOG_DEBUG", "Running $cmd\n"); + my $ret = $self->{ipc}->message(0,$cmd)->recv; if ($ret->[0]->{success}) { - print "Success!\n"; + $self->do_log("LOG_DEBUG", "Success!"); return undef; } return "Failed to run Sway IPC command '$cmd'"; } -sub run +sub do_log { - my @err; - # Local copy of targets so that it will re-check active every time - my @t = $settings{targets} if (defined($settings{targets})); - unless (scalar(@t)) { - @t = get_active(); - push(@err, "No target outputs") unless (scalar(@t)); - } - foreach my $a (@t) { - my $image = choose_image($settings{path}); - if (defined($image)) { - if ( -r "$image" ) { - print "selected $image\n"; - my $cropped; - if ($settings{crop}) { - if ($settings{debug}) { - print "Cropping image for '$a' using '$image'\n"; - } - my ($ow, $oh) = get_size($a); - $cropped = crop($image, $ow, $oh); - unless ($cropped) { - push(@err, "Failed to generate cropped image") unless ($cropped); - next; - } - } else { - $cropped = $image; - } - my $e = set_background($a,$cropped); - push(@err, $e) if (defined($e)); - if ($settings{crop}) { - print "Deleting $cropped\n"; - #unlink($cropped) || push(@err, "Failed to delete $cropped after setting: $!"); - } - } else { - push(@err, "$a: Unable to read image $image"); - } - } else { - push(@err, "$a: Unable to select image from $settings{path}"); + my $self = shift; + my $level = shift; + my $msg = shift; + my $die = shift || 0; + my $min = $self->{verbose} || 5; + + if ($self->{daemon}) { + use Log::Journald qw(send); + send( + PRIORITY => ERROR->{$level}, + MESSAGE => $msg, + PERL_PACKAGE => 'Sway Wallpapers' + ) || warn "Could not send log ($level $msg): $!"; + if ($die) { + $msg = '(FATAL) ' . $msg; + exit(1); + } + } else { + if (ERROR->{$level} >= $min) { + printf("%11s %s\n", $level, $msg); } } - if ($settings{debug} && $settings{daemon}) { - print STDERR join("\n",@err); - } else { - @e = @err; + if ($die) { + $self->clean(); + exit(1); + } +} + +sub run +{ + my $self = shift; + $self->do_log("LOG_DEBUG", "Fetching outputs from IPC"); + $self->{outputs} = $self->get_outputs(); + # Local copy of targets so that it will re-check active every time + my @t = @{$self->{targets}} if (scalar(@{$self->{targets}})); + $self->do_log("LOG_DEBUG", "Removing inactive ouputs"); + my $active = $self->get_active(); + # If specific targets were not defined, use all active + unless (scalar(@t)) { + @t = keys(%$active); + push(@{$self->{error}}, "No target outputs") unless (scalar(@t)); + } + $self->do_log("LOG_DEBUG", "Looping desired ouputs"); + foreach my $target (@t) { + $self->do_log("LOG_DEBUG", "Ensuring that desired output is active"); + unless (defined($active->{$target})) { + $self->do_log('LOG_DEBUG', "Target $target is not an active output"); + next; + } + $self->do_log("LOG_DEBUG", "Selecting image for $target"); + my $image = $self->choose_image(); + if (defined($image)) { + $self->do_log('LOG_DEBUG', "Selected $image"); + if ( -r "$image" ) { + my $cropped; + if ($self->{crop}) { + $self->do_log('LOG_DEBUG',"Cropping image for '$target' using '$image'"); + $cropped = $self->crop( + $image, + $active->{$target}->{rect}->{width}, + $active->{$target}->{rect}->{height} + ); + if ($cropped) { + } else { + # Create a tmp copy since it will be deleted later + # If PWD is the wallpaper path, make the tmp in /tmp + if ($self->{path} eq $ENV{PWD}) { + $cropped = $image; + $cropped =~ s%$ENV{PWD}%/tmp%; + # Else make the tmp in PWD + } else { + $cropped = '/'.$image; + $cropped =~ s%.*/([^/+])%$ENV{PWD}/$1%; + } + $self->do_log('LOG_DEBUG',"Creating copy of original: $cropped"); + File::Copy::copy($image,$cropped) || $self->do_log('LOG_WARNING',"Failed to copy to $cropped: $!"); + } + } else { + $self->do_log('LOG_DEBUG', "Cropping is disabled"); + $cropped = $image; + } + $self->set_background($target,$cropped); + if ($self->{crop}) { + $self->do_log('LOG_DEBUG', "Deleting $cropped"); + # Give swaybg a second, otherwise the file will be missing before it ends + sleep(1); + unlink($cropped) || $self->do_log("LOG_WARNING", "Failed to delete $cropped after setting: $!"); + } + } else { + $self->do_log("LOG_WARNING", "Failed to read $image"); + } + } else { + $self->do_log("LOG_WARNING", "Failed to select image from $self->{path}"); + } } } @@ -229,27 +350,39 @@ my $daemon; my $delay; my $crop; my $path; +my $verbose; while (my $arg = shift(@ARGV)) { if ($arg eq '-h' || $arg eq '--help') { - usage(); + $wp->usage(); } elsif ($arg =~ m/^\-\-path=?(.+)$/) { die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); $path = $1; } elsif ($arg eq '-p') { die "Redundant argument '$arg'. Wallpaper path already set.\n" if ($path); $path = shift(@ARGV); - } elsif ($arg =~ m/^\-\-daemon=?(.+)$/) { + } elsif ($arg =~ m/^\-\-daemon=?(.+)?$/) { die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); - $delay = $1; + $delay = $1 || 300; $daemon = 1; } elsif ($arg eq '-d') { die "Redundant argument '$arg'. Daemon mode already set.\n" if ($daemon); - if ($ARGV[0] =~ m/^\d+$/) { + if (scalar(@ARGV) && $ARGV[0] =~ m/^\d+$/) { $delay = shift(@ARGV); } $daemon = 1; - } elsif ($arg eq '--nocrop' || $arg eq '-') { - die "Redundant argument '$arg'. No-crop already set.\n" unless ($crop); + } elsif ($arg eq '--nocrop' || $arg eq '-n') { + die "Redundant argument '$arg'. No-crop already set.\n" if (defined($crop)); + $crop = 0; + } elsif ($arg =~ m/^\-\-verbose=?(.+)?$/) { + die "Redundant argument '$arg'. Verbosity already set.\n" if ($verbose); + $verbose = $1 || 1; + } elsif ($arg eq '-p') { + die "Redundant argument '$arg'. Verbosity already set.\n" if ($verbose); + if (scalar(@ARGV) && $ARGV[0] =~ m/^\d$/) { + $verbose = shift(@ARGV); + } + } elsif ($arg =~ m/^-/) { + die "Unrecognized argument: $arg\n"; } else { push(@targets,$arg); } @@ -259,51 +392,41 @@ while (my $arg = shift(@ARGV)) { # Validate arguments ################################################################################ +$wp->do_log("LOG_DEBUG", "Validating arguments"); die "Invalid rotation delay: $delay" if (defined($delay) && $delay !~ m/^\d+$/); - die "Invalid wallpaper path '$path'. Not a directory." if (defined($path) && !-d $path); +die "Invalid verbosity level: '$verbose'\n" if (defined($verbose) && $verbose =~ m/^[1-8]$/); -if (scalar(@targets)) { - my @kept; - foreach my $t (@targets) { - my $hit = 0; - foreach (@$o) { - if ($_->{name} eq $t) { - push(@kept, $t); - $hit++; - last; - } - } - print STDERR "Requested output '$t' not found\n" unless ($hit); - } - die "None of the requested outputs are active" unless (scalar(@kept)); - @targets = @kept; -} - -$settings{targets} = @targets || undef; -$settings{daemon} = $daemon || 0; -$settings{path} = $path || "$ENV{HOME}/wallpapers"; -$settings{crop} = $crop || 1; -$settings{delay} = $delay || 300; -$settings{debug} = $debug || 0; +$wp->do_log("LOG_DEBUG", "Configuring object"); +$wp->{targets} = \@targets || undef; +$wp->{daemon} = $daemon || 0; +$wp->{path} = $path || "$ENV{HOME}/wallpapers"; +$wp->{crop} = $crop || 1; +$wp->{delay} = $delay || 300; +$wp->{verbose} = $verbose || 0; +$wp->{error} = []; ################################################################################ -# For if daemonized +# Fork if daemonized ################################################################################ -if ($settings{daemon}) { +if ($wp->{daemon}) { + $wp->do_log("LOG_DEBUG", "Forking daemon"); my $p = fork(); if ($p) { - if (open(my $fh, ">", $pidfile)) { - print $fh "$p" || die "Failed to write pid ($p) to pidfile $pidfile"; + $wp->do_log("LOG_DEBUG", "Writing PID ($p) to pidfile ($wp->{pidfile})"); + if (open(my $fh, ">", $wp->{pidfile})) { + print $fh "$p" || die "Failed to write pid ($p) to pidfile ".$wp->{pidfile}; close($fh); } else { - print "Failed to open pidfile: $pidfile: $!\n"; + print "Failed to open pidfile ".$wp->{pidfile}.": $!\n"; } + # Short delay necessary for SystemD to find PID + sleep(1); exit(0); } - #setpgrp; - #setsid; + $wp->do_log("LOG_DEBUG", "Daemon running"); + setpgrp(0, 0); umask 0; } @@ -311,31 +434,24 @@ if ($settings{daemon}) { # Main ################################################################################ +my $first = 1; do { - run(%settings); - if ($settings{daemon}) { + $wp->do_log("LOG_INFO", "Reloading wallpaper") unless ($first); + $wp->run(); + if ($wp->{daemon}) { my $normal = "reload wallpaper"; eval { - $SIG{ALRM} = sub { print "$normal\n" }; - alarm $settings{delay}; + $SIG{ALRM} = sub { return "$normal" }; + alarm $wp->{delay}; POSIX::pause(); alarm 0; }; - if ($@ && $@ !~ quotemeta($normal)) { - if ($settings{debug}) { - print $normal; - } - } + $wp->do_log("LOG_WARNING", "Reload failed: $@") if ($@ && $@ !~ quotemeta($normal)); } -} while ($settings{daemon}); + $first = 0 if ($first); +} while ($wp->{daemon}); -################################################################################ # If we made it to here, it was not daemonized. Output errors and exit -################################################################################ - -if (scalar(@e)) { - die "Failure while not running as daemon:\n" . - join("\n",@e); -} +$wp->do_log("LOG_DEBUG", "Finishing") unless ($wp->{daemon}); exit(0); From f1f94b6df4e76be460f19ac0c6b6357e5cde5984 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 25 Jul 2022 18:43:35 -0400 Subject: [PATCH 075/110] Systemd Unit for wallpaper.pl --- sway/wallpapers.service | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 sway/wallpapers.service diff --git a/sway/wallpapers.service b/sway/wallpapers.service new file mode 100644 index 0000000..734272a --- /dev/null +++ b/sway/wallpapers.service @@ -0,0 +1,12 @@ +[Unit] +Description=Rotate through cropped wallpapers for %u + +[Service] +Type=forking +PIDFile=/tmp/%u-wallpaper.pid +WorkingDirectory=/tmp +ExecStart=/var/home/%u/scripts/sway/wallpaper.pl -d --path=/home/jpm/wallpapers +Restart=always + +[Install] +WantedBy=graphical.target From aa70b984c32259168a951b9d74f8f7d9070f8774 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 25 Jul 2022 22:27:47 -0400 Subject: [PATCH 076/110] Add recursive enumeration of images cleaned up some comments and one typo in ARG parsing --- sway/wallpaper.pl | 51 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index 175a639..39953fe 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -42,6 +42,8 @@ are currently enabled will be set.\n --verbose=N Define minimum log level. Counting from 1: LOG_DEBUG, LOG_INFO, -v N LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT, LOG_ALERT, LOG_EMERG Default: 5; If provided without a value for N then all (1). +--recursive=N Enumerate images recursively through directories in the path. +-r N N indicates the directory depth, unlimited if no N is provided. --help This menu -h\n You can send SIGUSR1 to force the daemon to reload immediately. Rotation timer @@ -168,14 +170,41 @@ sub clean } } +sub dig_dirs +{ + my $self = shift; + my $paths_ref = shift; + my $path = shift; + my $depth = shift || 0; + unless (-e $path) { + return(undef); + } + if ($path =~ m/\/\.\.?$/) { + return; + } + foreach (glob("$path/*"), glob("$path/.*")) { + if ($path =~ m/\/\.\.?$/) { + next(); + } elsif (-l $_) { + push(@$paths_ref, $_); + } elsif (-d $_ && ($self->{recursive} == '-1' || $depth < $self->{recursive})) { + $self->dig_dirs($paths_ref,$_,$depth+1); + } else { + push(@$paths_ref, $_); + } + } +} + sub choose_image { my $self = shift; - my @w = glob($self->{'path'}."/*"); - return undef unless (scalar(@w)); - $self->do_log("LOG_DEBUG", "Found ".scalar(@w)." files in $self->{path}"); my @i; + my $depth = 0; + my @w; + $self->dig_dirs(\@w,$self->{path}); + return undef unless (scalar(@w)); + $self->do_log("LOG_DEBUG", "Found ".scalar(@w)." files in $self->{path} up to depth $self->{recursive}"); foreach (@w) { if (-d $_) { $self->do_log("LOG_DEBUG", "Ignoring sub-directory $_"); @@ -218,10 +247,8 @@ sub crop $x = int(rand($iw-$ow)); $y = int(rand($ih-$oh)); - print "Cropping $image ${ow}x${oh}+${x}+${y}\n"; my $err = $im->Crop(geometry=>"${ow}x${oh}+${x}+${y}"); die "$err" if ($err); - print "Writing $cropped\n"; $err = $im->Write($cropped); die "$err" if ($err); return $cropped if ( -e $cropped ); @@ -351,6 +378,7 @@ my $delay; my $crop; my $path; my $verbose; +my $recursive = 0; while (my $arg = shift(@ARGV)) { if ($arg eq '-h' || $arg eq '--help') { $wp->usage(); @@ -376,11 +404,21 @@ while (my $arg = shift(@ARGV)) { } elsif ($arg =~ m/^\-\-verbose=?(.+)?$/) { die "Redundant argument '$arg'. Verbosity already set.\n" if ($verbose); $verbose = $1 || 1; - } elsif ($arg eq '-p') { + } elsif ($arg eq '-v') { die "Redundant argument '$arg'. Verbosity already set.\n" if ($verbose); if (scalar(@ARGV) && $ARGV[0] =~ m/^\d$/) { $verbose = shift(@ARGV); } + } elsif ($arg =~ m/^\-\-recursive=?(.+)?$/) { + die "Redundant argument '$arg'. Recursive search already set.\n" unless ($recursive == 0); + $recursive = $1 || -1; + } elsif ($arg eq '-r') { + die "Redundant argument '$arg'. Recursive search already set.\n" unless ($recursive == 0); + if (scalar(@ARGV) && $ARGV[0] =~ m/^\d+$/) { + $recursive = shift(@ARGV); + } else { + $recursive = -1; + } } elsif ($arg =~ m/^-/) { die "Unrecognized argument: $arg\n"; } else { @@ -404,6 +442,7 @@ $wp->{path} = $path || "$ENV{HOME}/wallpapers"; $wp->{crop} = $crop || 1; $wp->{delay} = $delay || 300; $wp->{verbose} = $verbose || 0; +$wp->{recursive}= $recursive; $wp->{error} = []; ################################################################################ From 58c03333a7cea493f0453062acb3e470c42a4496 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 23 Aug 2022 11:58:00 -0600 Subject: [PATCH 077/110] Update --bar formatting --- thinkpad/pow.pl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/thinkpad/pow.pl b/thinkpad/pow.pl index 3c7b0fb..7ffdce6 100755 --- a/thinkpad/pow.pl +++ b/thinkpad/pow.pl @@ -97,7 +97,7 @@ if ($bar) { my $json = JSON::XS->new(); my $powref = $json->decode($output); my $class = 'discharging'; - $output = '{"text": "'; + $output = ''; if ($powref->{AC}->{Status} eq "Plugged-In") { $class = 'charging'; $output .= ""; @@ -114,7 +114,13 @@ if ($bar) { } else { $output .= ""; } - $output .= $powref->{Total}->{Percentage} . '%", "tooltip": "' . $class . '", "class": "' . $class . '"}'; + $output = '{' + . '"text":"' . $output . '\u200a' . $powref->{Total}->{Percentage} . '%",' + . '"icon":"' . $output . '",' + . '"percentage":"' . $powref->{Total}->{Percentage} . '",' + . '"tooltip":"' . $class . '",' + . '"class":"' . $class . '"' + . '}'; } elsif ($pretty) { use JSON::XS; my $json = JSON::XS->new(); From 2c4ef97a1b033c67a3183f047c803ac384622863 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Tue, 23 Aug 2022 11:59:45 -0600 Subject: [PATCH 078/110] Force GLES2 Update defaulted to Vulkan which isn't working --- sway/startsway.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/startsway.sh b/sway/startsway.sh index 607dd5e..bbcc398 100755 --- a/sway/startsway.sh +++ b/sway/startsway.sh @@ -2,5 +2,6 @@ rm $HOME/.swaylog echo sway > $HOME/.spool/last_login_gui export SWAYSOCK="$HOME/.spool/sway-ipc.sock" -sway --debug 2>> $HOME/.swaylog >> $HOME/.swaylog +#WLR_RENDERER=vulkan sway --debug 2>> $HOME/.swaylog >> $HOME/.swaylog +WLR_RENDERER=gles2 sway --debug 2>> $HOME/.swaylog >> $HOME/.swaylog export SWAYSOCK=`sway --get-socketpath` From 156ff9221d49204c40af4ce1a1f1ec4353e0fb64 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 25 Aug 2022 23:05:14 -0600 Subject: [PATCH 079/110] Gammastep waybar --- sway/gammastep.pl | 2 +- waybar/waybar-gammastep.sh | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100755 waybar/waybar-gammastep.sh diff --git a/sway/gammastep.pl b/sway/gammastep.pl index 22b1f58..3d6e80f 100755 --- a/sway/gammastep.pl +++ b/sway/gammastep.pl @@ -17,7 +17,7 @@ unless ($pid) { open STDOUT, '>>/dev/null'; open STDERR, '>>/dev/null'; - `gammastep -l $lat_lon -b 1:0.7`; + `gammastep -l $lat_lon -b 0.7:0.3`; } sub fetch_lat_lon diff --git a/waybar/waybar-gammastep.sh b/waybar/waybar-gammastep.sh new file mode 100755 index 0000000..5d0c16b --- /dev/null +++ b/waybar/waybar-gammastep.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +RUNNING=$(pgrep gammastep) + +if [[ $1 == 'toggle' ]]; then + echo "toggling" + if [ "$RUNNING" ]; then + kill -9 $RUNNING 2&>1 /dev/null + else + $HOME/scripts/sway/gammastep.pl + fi + RUNNING=$(pgrep gammastep) +fi + + +if [ "$RUNNING" ]; then + echo '{"text":"ɣ","icon":"ɣ","tooltip":"Disable Gammastep","class":"enabled"}' +else + echo '{"text":"ɣ","icon":"ɣ","tooltip":"Enable Gammastep","class":"disabled"}' +fi From 3d6195bbcb620f43ca506362411c7c4cf5ac0619 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 2 Sep 2022 22:47:44 -0600 Subject: [PATCH 080/110] Enhance kdb_backlight with sleep/restore function --- thinkpad/kbd_backlight.pl | 88 +++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/thinkpad/kbd_backlight.pl b/thinkpad/kbd_backlight.pl index fdb62cb..0a4a852 100755 --- a/thinkpad/kbd_backlight.pl +++ b/thinkpad/kbd_backlight.pl @@ -3,35 +3,71 @@ use strict; use warnings; -my $maxfile = "/sys/class/leds/tpacpi\:\:kbd_backlight/max_brightness"; -my $current = "/sys/class/leds/tpacpi\:\:kbd_backlight/brightness"; +our $maxfile = "/sys/class/leds/tpacpi\:\:kbd_backlight/max_brightness"; +our $current = "/sys/class/leds/tpacpi\:\:kbd_backlight/brightness"; +our $sleepfile = "$ENV{HOME}/.spool/kbd_sleep"; -my ($max, $now, $new); -if (open(my $m, '<', $maxfile)) { - $max = readline($m); - chomp $max; - close($m); -} else { - print "Failed to read $maxfile\n"; - exit; +sub readFile +{ + my $file = shift; + my $ret; + if (open(my $fh, '<', $file)) { + $ret = readline($fh); + chomp $ret; + close($fh); + } else { + die "Failed to read $file: $?\n"; + } + return $ret; } -if (open(my $c, '<', $current)) { - $now = readline($c); - chomp $now; - close($c); -} else { - print "Failed to read $current\n"; - exit; + +sub writeFile +{ + my ($file, $value) = @_; + if (open(my $fh, '>', $file)) { + print $fh $value; + close($fh); + } else { + die "Failed to write $current\n"; + } } -if (open(my $fh, '>', $current)) { - $new = (($now+1) % ($max+1)); - chomp $new; - print $fh $new; - close($fh); -} else { - print "Failed to write $current\n"; - exit; +sub sleepFile +{ + my $now = readFile($current); + writeFile($sleepfile,$now); + writeFile($current,0); } -#print STDERR "$new\n"; + +sub restoreFile +{ + unless (-e $sleepfile) { + die "Missing '$sleepfile'. Must not have slept prior to restore.\n" + } + my $value = readFile($sleepfile); + writeFile($current,$value); + unlink($sleepfile); +} + +sub rotateFile +{ + my $max = readFile($maxfile); + my $now = readFile($current); + my $new = (($now+1) % ($max+1)); + writeFile($current,$new); +} + +if (defined($ARGV[0])) { + if ($ARGV[0] eq 'sleep') { + sleepFile(); + exit(0); + } elsif ($ARGV[0] eq 'restore') { + restoreFile(); + exit(0); + } elsif ($ARGV[0] ne 'rotate') { + die "Invalid mode '".$ARGV[0]."'. 'rotate', 'sleep', or 'restore'\n"; + } +} + +rotateFile(); From c62109d2637c11a058259f44cf5398797ef6e0c3 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 2 Sep 2022 23:05:44 -0600 Subject: [PATCH 081/110] Inverted logic for log level validationd --- sway/wallpaper.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index 39953fe..f1c2efd 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -433,7 +433,7 @@ while (my $arg = shift(@ARGV)) { $wp->do_log("LOG_DEBUG", "Validating arguments"); die "Invalid rotation delay: $delay" if (defined($delay) && $delay !~ m/^\d+$/); die "Invalid wallpaper path '$path'. Not a directory." if (defined($path) && !-d $path); -die "Invalid verbosity level: '$verbose'\n" if (defined($verbose) && $verbose =~ m/^[1-8]$/); +die "Invalid verbosity level: '$verbose'\n" if (defined($verbose) && $verbose !~ m/^[1-8]$/); $wp->do_log("LOG_DEBUG", "Configuring object"); $wp->{targets} = \@targets || undef; From 05d692d9368e6e6d4357cec55852d56009f9d803 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 15:16:05 -0400 Subject: [PATCH 082/110] Increase delay to give more time before deletion --- sway/wallpaper.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index f1c2efd..5aabc79 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -357,7 +357,7 @@ sub run if ($self->{crop}) { $self->do_log('LOG_DEBUG', "Deleting $cropped"); # Give swaybg a second, otherwise the file will be missing before it ends - sleep(1); + sleep(2); unlink($cropped) || $self->do_log("LOG_WARNING", "Failed to delete $cropped after setting: $!"); } } else { From 8dcbcb5fe5eae1e5a44e531999857fe0bbdb41d3 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 15:17:02 -0400 Subject: [PATCH 083/110] Prevent fork. Limits to one PID --- sway/gammastep.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/gammastep.pl b/sway/gammastep.pl index 3d6e80f..69878af 100755 --- a/sway/gammastep.pl +++ b/sway/gammastep.pl @@ -17,7 +17,7 @@ unless ($pid) { open STDOUT, '>>/dev/null'; open STDERR, '>>/dev/null'; - `gammastep -l $lat_lon -b 0.7:0.3`; + exec "exec gammastep -l $lat_lon -b 0.7:0.3"; } sub fetch_lat_lon From 9c5b60d42fab310d85014a9e30e51f38e80e4a8d Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 15:17:28 -0400 Subject: [PATCH 084/110] Track PID --- sway/gammastep.pl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sway/gammastep.pl b/sway/gammastep.pl index 69878af..7a84a37 100755 --- a/sway/gammastep.pl +++ b/sway/gammastep.pl @@ -13,6 +13,13 @@ my $lat_lon = fetch_lat_lon($location); my $pid = fork; unless ($pid) { + open(my $fh, ">", $ENV{HOME}."/.spool/gammastep.pid"); + print $fh $$; + close($fh); + open($fh, ">", $ENV{HOME}."/.spool/gammastep.status"); + print $fh 1; + close($fh); + open STDIN, '/dev/null'; open STDOUT, '>>/dev/null'; open STDERR, '>>/dev/null'; From 675ba63687ce4962d1007dccfe64467b413bda75 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 15:21:13 -0400 Subject: [PATCH 085/110] Whitespace --- thinkpad/blc.pl | 106 ++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/thinkpad/blc.pl b/thinkpad/blc.pl index 0514b47..d9ba621 100755 --- a/thinkpad/blc.pl +++ b/thinkpad/blc.pl @@ -11,7 +11,7 @@ # # to output like: # 1000/10000 = 10% -# +# # Create a new array of hashes to classify the ARGV elements, eg: # $0 + "+%c" -= 10 +=4 =1 =100 "+%p" # [ @@ -106,7 +106,7 @@ sub get_min sub writable { if (! -w $cur_file) { - die "You don't have permission to write $cur_file\n"; + die "You don't have permission to write $cur_file\n"; } return 1; } @@ -241,7 +241,7 @@ my (@output, $target, $silent, $notify); my $operation_found = 0; if (scalar @ARGV) { - while ($arg = shift) { + while ($arg = shift) { if ($arg eq '%') { push @output,int(get_current()/get_max()*100); } elsif ($arg eq '^') { @@ -266,52 +266,52 @@ if (scalar @ARGV) { } else { $duration = 1000; } - } elsif ($arg eq '+') { - unshift(@ARGV,1); - unshift(@ARGV,'+='); + } elsif ($arg eq '+') { + unshift(@ARGV,1); + unshift(@ARGV,'+='); } elsif ($arg =~ /^\+=/) { - my $offset; - if ($arg =~ m/^\+=(.+)$/) { - $offset = $1; - } else { - $offset = shift || die "+= without accompanying offset value\n"; - } - unless ($offset =~ /^\d+$/) { - die "+= is not a number ($offset)\n"; - } + my $offset; + if ($arg =~ m/^\+=(.+)$/) { + $offset = $1; + } else { + $offset = shift || die "+= without accompanying offset value\n"; + } + unless ($offset =~ /^\d+$/) { + die "+= is not a number ($offset)\n"; + } for (my $j=0;$j<$offset;$j++) { $target = increment(); - @output = to_percent($target); + @output = to_percent($target); } $operation_found = 1; - } elsif ($arg eq '-') { - unshift(@ARGV,1); - unshift(@ARGV,'-='); + } elsif ($arg eq '-') { + unshift(@ARGV,1); + unshift(@ARGV,'-='); } elsif ($arg =~ /^-=/) { - my $offset; - if ($arg =~ m/^-=(.+)$/) { - $offset = $1; - } else { - $offset = shift || die "-= without accompanying offset value\n"; - } - unless ($offset =~ /^\d+$/) { - die "-= is not a number ($offset)\n"; - } + my $offset; + if ($arg =~ m/^-=(.+)$/) { + $offset = $1; + } else { + $offset = shift || die "-= without accompanying offset value\n"; + } + unless ($offset =~ /^\d+$/) { + die "-= is not a number ($offset)\n"; + } for (my $j=0;$j<$offset;$j++) { $target = decrement(); - @output = to_percent($target); + @output = to_percent($target); } $operation_found = 1; } elsif ($arg =~ m/^=/) { - my $value; - if ($arg =~ m/^=(.+)$/) { - $target = $1; - } else { - $target = shift || die "= without accompanying absolute value\n"; - } - unless ($target =~ /^\d+$/) { - die "= is not a number ($target)\n"; - } + my $value; + if ($arg =~ m/^=(.+)$/) { + $target = $1; + } else { + $target = shift || die "= without accompanying absolute value\n"; + } + unless ($target =~ /^\d+$/) { + die "= is not a number ($target)\n"; + } if ($target < 1) { $target = set(get_min()); } elsif ($target > get_max()) { @@ -326,7 +326,7 @@ if (scalar @ARGV) { @output = to_percent($target); $operation_found = 1; } else { - push(@output,$arg); + push(@output,$arg); } } } else { @@ -336,7 +336,7 @@ if (scalar @ARGV) { . '","Current":"' . get_current() . '","Percentage","' - . int(get_current()/get_max()*100) + . int(get_current()/get_max()*100) . '%"}}' ); } @@ -354,26 +354,26 @@ if ($silent) { $concat .= $_; } =pod - use Gtk2::Notify -init, "Backlight"; - my $notification = Gtk2::Notify::new('Backlight', $concat, '', "notification-display-brightness"); + use Gtk2::Notify -init, "Backlight"; + my $notification = Gtk2::Notify::new('Backlight', $concat, '', "notification-display-brightness"); - $notification->set_hint_string('x-canonical-private-synchronous','blc'); - $notification->set_urgency('NOTIFY_URGENCY_LOW'); - $notification->set_hint_int32('value',(split('%',$concat))[0]); - $notification->set_timeout($duration); - $notification->show(); - exit; + $notification->set_hint_string('x-canonical-private-synchronous','blc'); + $notification->set_urgency('NOTIFY_URGENCY_LOW'); + $notification->set_hint_int32('value',(split('%',$concat))[0]); + $notification->set_timeout($duration); + $notification->show(); + exit; print "notify-send --urgency=normal" . ' --icon="notification-display-brightness"' - . ' --hint=string:x-canonical-private-synchronous:blc' + . ' --hint=string:x-canonical-private-synchronous:blc' . ' --expire-time=' . $duration - . ' "Backlight"' + . ' "Backlight"' . ' "' . $concat . " '" . join("','", @output) . "'\""; system "notify-send --urgency=normal" . ' --icon="notification-display-brightness"' - . ' --hint=string:x-canonical-private-synchronous:blc' - . ' --hint=int:value:' . (split('%',$concat))[0] - . ' --expire-time=' . $duration + . ' --hint=string:x-canonical-private-synchronous:blc' + . ' --hint=int:value:' . (split('%',$concat))[0] + . ' --expire-time=' . $duration . ' "' . $concat . "\""; =cut From 508e3f0516581b06c04e5dc3123db79cb4e713d6 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 15:22:18 -0400 Subject: [PATCH 086/110] Track backlight brightness better to allow reverting (by screensaver, etc.) --- thinkpad/blc.pl | 52 +++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/thinkpad/blc.pl b/thinkpad/blc.pl index d9ba621..d0fb906 100755 --- a/thinkpad/blc.pl +++ b/thinkpad/blc.pl @@ -66,13 +66,13 @@ # Files containing current and max brightness values my $cur_file = "/sys/class/backlight/intel_backlight/brightness"; my $max_file = "/sys/class/backlight/intel_backlight/max_brightness"; -my $last_file = "/home/jpm/.config/blc.last"; +my $cur_log = $ENV{HOME}."/.spool/blc.current"; +my $last_log = $ENV{HOME}."/.spool/blc.last"; sub to_percent { my $value = shift; - $value = int($value/get_max()*100); - return $value . '%'; + return int($value/get_max()*100); } sub get_offset @@ -108,7 +108,26 @@ sub writable if (! -w $cur_file) { die "You don't have permission to write $cur_file\n"; } - return 1; + return 1; +} + +sub logger +{ + my ($current, $target) = @_; + open(my $fh,'>',$last_log); + print $fh to_percent($current); + close($fh); + open($fh,'>',$cur_log); + print $fh to_percent($target); + close($fh); +} + +sub writef +{ + my $target = shift; + open(my $fh,'>',$cur_file); + print $fh $target; + close($fh); } sub increment @@ -120,9 +139,6 @@ sub increment if ($target > $max) { $target = $max; } - open(my $c,'>',"$cur_file"); - print $c $target; - close $c; return $target; } } @@ -136,9 +152,7 @@ sub decrement if ($target < $min) { $target = $min; } - open(my $c,'>',"$cur_file"); - print $c $target; - close $c; + set($target); return $target; } } @@ -147,18 +161,15 @@ sub set { my $value = shift; if (writable()) { - $current = get_current(); + my $current = get_current(); + logger($current,$value); if ($value > $current) { for (my $i=$current;$i<=$value;$i++) { - open(my $c,'>',"$cur_file"); - print $c $i; - close $c; + writef($i); } } else { for (my $i=$current;$i>=$value;$i--) { - open(my $c,'>',"$cur_file"); - print $c $i; - close $c; + writef($i); } } return $value; @@ -243,7 +254,7 @@ my $operation_found = 0; if (scalar @ARGV) { while ($arg = shift) { if ($arg eq '%') { - push @output,int(get_current()/get_max()*100); + push @output,to_percent(get_current); } elsif ($arg eq '^') { push @output,get_max(); } elsif ($arg eq '==') { @@ -341,11 +352,6 @@ if (scalar @ARGV) { ); } -open(my $fh,'>',$last_file); -print $fh get_current(); -close($fh); - -print $_."\n" foreach(@output); if ($silent) { exit(); } elsif ($notify) { From 88b4b41772d8956fbb87d0d85781323d8e128c8c Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 16:05:40 -0400 Subject: [PATCH 087/110] Emoji picker Slightly modified from https://github.com/dln/wofi-emoji in order to always use wl-clip and use custom wofi style.css --- wofi/wofi-emoji | 1853 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1853 insertions(+) create mode 100755 wofi/wofi-emoji diff --git a/wofi/wofi-emoji b/wofi/wofi-emoji new file mode 100755 index 0000000..0248dc6 --- /dev/null +++ b/wofi/wofi-emoji @@ -0,0 +1,1853 @@ +#!/bin/bash +sed '1,/^### DATA ###$/d' $0 | wofi --show dmenu -i -s $HOME/.dotfiles/wofi/style.css | cut -d ' ' -f 1 | tr -d '\n' | wl-copy --primary +exit +### DATA ### +😀 grinning face face smile happy joy :D grin +😃 grinning face with big eyes face happy joy haha :D :) smile funny +😄 grinning face with smiling eyes face happy joy funny haha laugh like :D :) smile +😁 beaming face with smiling eyes face happy smile joy kawaii +😆 grinning squinting face happy joy lol satisfied haha face glad XD laugh +😅 grinning face with sweat face hot happy laugh sweat smile relief +🤣 rolling on the floor laughing face rolling floor laughing lol haha rofl +😂 face with tears of joy face cry tears weep happy happytears haha +🙂 slightly smiling face face smile +🙃 upside down face face flipped silly smile +😉 winking face face happy mischievous secret ;) smile eye +😊 smiling face with smiling eyes face smile happy flushed crush embarrassed shy joy +😇 smiling face with halo face angel heaven halo +🥰 smiling face with hearts face love like affection valentines infatuation crush hearts adore +😍 smiling face with heart eyes face love like affection valentines infatuation crush heart +🤩 star struck face smile starry eyes grinning +😘 face blowing a kiss face love like affection valentines infatuation kiss +😗 kissing face love like face 3 valentines infatuation kiss +☺️ smiling face face blush massage happiness +😚 kissing face with closed eyes face love like affection valentines infatuation kiss +😙 kissing face with smiling eyes face affection valentines infatuation kiss +😋 face savoring food happy joy tongue smile face silly yummy nom delicious savouring +😛 face with tongue face prank childish playful mischievous smile tongue +😜 winking face with tongue face prank childish playful mischievous smile wink tongue +🤪 zany face face goofy crazy +😝 squinting face with tongue face prank playful mischievous smile tongue +🤑 money mouth face face rich dollar money +🤗 hugging face face smile hug +🤭 face with hand over mouth face whoops shock surprise +🤫 shushing face face quiet shhh +🤔 thinking face face hmmm think consider +🤐 zipper mouth face face sealed zipper secret +🤨 face with raised eyebrow face distrust scepticism disapproval disbelief surprise +😐 neutral face indifference meh :| neutral +😑 expressionless face face indifferent - - meh deadpan +😶 face without mouth face hellokitty +😏 smirking face face smile mean prank smug sarcasm +😒 unamused face indifference bored straight face serious sarcasm unimpressed skeptical dubious side eye +🙄 face with rolling eyes face eyeroll frustrated +😬 grimacing face face grimace teeth +🤥 lying face face lie pinocchio +😌 relieved face face relaxed phew massage happiness +😔 pensive face face sad depressed upset +😪 sleepy face face tired rest nap +🤤 drooling face face +😴 sleeping face face tired sleepy night zzz +😷 face with medical mask face sick ill disease +🤒 face with thermometer sick temperature thermometer cold fever +🤕 face with head bandage injured clumsy bandage hurt +🤢 nauseated face face vomit gross green sick throw up ill +🤮 face vomiting face sick +🤧 sneezing face face gesundheit sneeze sick allergy +🥵 hot face face feverish heat red sweating +🥶 cold face face blue freezing frozen frostbite icicles +🥴 woozy face face dizzy intoxicated tipsy wavy +😵 dizzy face spent unconscious xox dizzy +🤯 exploding head face shocked mind blown +🤠 cowboy hat face face cowgirl hat +🥳 partying face face celebration woohoo +😎 smiling face with sunglasses face cool smile summer beach sunglass +🤓 nerd face face nerdy geek dork +🧐 face with monocle face stuffy wealthy +😕 confused face face indifference huh weird hmmm :/ +😟 worried face face concern nervous :( +🙁 slightly frowning face face frowning disappointed sad upset +☹️ frowning face face sad upset frown +😮 face with open mouth face surprise impressed wow whoa :O +😯 hushed face face woo shh +😲 astonished face face xox surprised poisoned +😳 flushed face face blush shy flattered +🥺 pleading face face begging mercy +😦 frowning face with open mouth face aw what +😧 anguished face face stunned nervous +😨 fearful face face scared terrified nervous oops huh +😰 anxious face with sweat face nervous sweat +😥 sad but relieved face face phew sweat nervous +😢 crying face face tears sad depressed upset :'( +😭 loudly crying face face cry tears sad upset depressed +😱 face screaming in fear face munch scared omg +😖 confounded face face confused sick unwell oops :S +😣 persevering face face sick no upset oops +😞 disappointed face face sad upset depressed :( +😓 downcast face with sweat face hot sad tired exercise +😩 weary face face tired sleepy sad frustrated upset +😫 tired face sick whine upset frustrated +🥱 yawning face tired sleepy +😤 face with steam from nose face gas phew proud pride +😡 pouting face angry mad hate despise +😠 angry face mad face annoyed frustrated +🤬 face with symbols on mouth face swearing cursing cussing profanity expletive +😈 smiling face with horns devil horns +👿 angry face with horns devil angry horns +💀 skull dead skeleton creepy death +☠️ skull and crossbones poison danger deadly scary death pirate evil +💩 pile of poo hankey shitface fail turd shit +🤡 clown face face +👹 ogre monster red mask halloween scary creepy devil demon japanese ogre +👺 goblin red evil mask monster scary creepy japanese goblin +👻 ghost halloween spooky scary +👽 alien UFO paul weird outer space +👾 alien monster game arcade play +🤖 robot computer machine bot +😺 grinning cat animal cats happy smile +😸 grinning cat with smiling eyes animal cats smile +😹 cat with tears of joy animal cats haha happy tears +😻 smiling cat with heart eyes animal love like affection cats valentines heart +😼 cat with wry smile animal cats smirk +😽 kissing cat animal cats kiss +🙀 weary cat animal cats munch scared scream +😿 crying cat animal tears weep sad cats upset cry +😾 pouting cat animal cats +🙈 see no evil monkey monkey animal nature haha +🙉 hear no evil monkey animal monkey nature +🙊 speak no evil monkey monkey animal nature omg +💋 kiss mark face lips love like affection valentines +💌 love letter email like affection envelope valentines +💘 heart with arrow love like heart affection valentines +💝 heart with ribbon love valentines +💖 sparkling heart love like affection valentines +💗 growing heart like love affection valentines pink +💓 beating heart love like affection valentines pink heart +💞 revolving hearts love like affection valentines +💕 two hearts love like affection valentines heart +💟 heart decoration purple-square love like +❣️ heart exclamation decoration love +💔 broken heart sad sorry break heart heartbreak +❤️ red heart love like valentines +🧡 orange heart love like affection valentines +💛 yellow heart love like affection valentines +💚 green heart love like affection valentines +💙 blue heart love like affection valentines +💜 purple heart love like affection valentines +🤎 brown heart coffee +🖤 black heart evil +🤍 white heart pure +💯 hundred points score perfect numbers century exam quiz test pass hundred +💢 anger symbol angry mad +💥 collision bomb explode explosion collision blown +💫 dizzy star sparkle shoot magic +💦 sweat droplets water drip oops +💨 dashing away wind air fast shoo fart smoke puff +🕳️ hole embarrassing +💣 bomb boom explode explosion terrorism +💬 speech balloon bubble words message talk chatting +👁️‍🗨️ eye in speech bubble info +🗨️ left speech bubble words message talk chatting +🗯️ right anger bubble caption speech thinking mad +💭 thought balloon bubble cloud speech thinking dream +💤 zzz sleepy tired dream +👋 waving hand hands gesture goodbye solong farewell hello hi palm +🤚 raised back of hand fingers raised backhand +🖐️ hand with fingers splayed hand fingers palm +✋ raised hand fingers stop highfive palm ban +🖖 vulcan salute hand fingers spock star trek +👌 ok hand fingers limbs perfect ok okay +🤏 pinching hand tiny small size +✌️ victory hand fingers ohyeah hand peace victory two +🤞 crossed fingers good lucky +🤟 love you gesture hand fingers gesture +🤘 sign of the horns hand fingers evil eye sign of horns rock on +🤙 call me hand hands gesture shaka +👈 backhand index pointing left direction fingers hand left +👉 backhand index pointing right fingers hand direction right +👆 backhand index pointing up fingers hand direction up +🖕 middle finger hand fingers rude middle flipping +👇 backhand index pointing down fingers hand direction down +☝️ index pointing up hand fingers direction up +👍 thumbs up thumbsup yes awesome good agree accept cool hand like +1 +👎 thumbs down thumbsdown no dislike hand -1 +✊ raised fist fingers hand grasp +👊 oncoming fist angry violence fist hit attack hand +🤛 left facing fist hand fistbump +🤜 right facing fist hand fistbump +👏 clapping hands hands praise applause congrats yay +🙌 raising hands gesture hooray yea celebration hands +👐 open hands fingers butterfly hands open +🤲 palms up together hands gesture cupped prayer +🤝 handshake agreement shake +🙏 folded hands please hope wish namaste highfive pray +✍️ writing hand lower left ballpoint pen stationery write compose +💅 nail polish beauty manicure finger fashion nail +🤳 selfie camera phone +💪 flexed biceps arm flex hand summer strong biceps +🦾 mechanical arm accessibility +🦿 mechanical leg accessibility +🦵 leg kick limb +🦶 foot kick stomp +👂 ear face hear sound listen +🦻 ear with hearing aid accessibility +👃 nose smell sniff +🧠 brain smart intelligent +🦷 tooth teeth dentist +🦴 bone skeleton +👀 eyes look watch stalk peek see +👁️ eye face look see watch stare +👅 tongue mouth playful +👄 mouth mouth kiss +👶 baby child boy girl toddler +🧒 child gender-neutral young +👦 boy man male guy teenager +👧 girl female woman teenager +🧑 person gender-neutral person +👱 person blond hair hairstyle +👨 man mustache father dad guy classy sir moustache +🧔 man beard person bewhiskered +👨‍🦰 man red hair hairstyle +👨‍🦱 man curly hair hairstyle +👨‍🦳 man white hair old elder +👨‍🦲 man bald hairless +👩 woman female girls lady +👩‍🦰 woman red hair hairstyle +🧑‍🦰 person red hair hairstyle +👩‍🦱 woman curly hair hairstyle +🧑‍🦱 person curly hair hairstyle +👩‍🦳 woman white hair old elder +🧑‍🦳 person white hair elder old +👩‍🦲 woman bald hairless +🧑‍🦲 person bald hairless +👱‍♀️ woman blond hair woman female girl blonde person +👱‍♂️ man blond hair man male boy blonde guy person +🧓 older person human elder senior gender-neutral +👴 old man human male men old elder senior +👵 old woman human female women lady old elder senior +🙍 person frowning worried +🙍‍♂️ man frowning male boy man sad depressed discouraged unhappy +🙍‍♀️ woman frowning female girl woman sad depressed discouraged unhappy +🙎 person pouting upset +🙎‍♂️ man pouting male boy man +🙎‍♀️ woman pouting female girl woman +🙅 person gesturing no decline +🙅‍♂️ man gesturing no male boy man nope +🙅‍♀️ woman gesturing no female girl woman nope +🙆 person gesturing ok agree +🙆‍♂️ man gesturing ok men boy male blue human man +🙆‍♀️ woman gesturing ok women girl female pink human woman +💁 person tipping hand information +💁‍♂️ man tipping hand male boy man human information +💁‍♀️ woman tipping hand female girl woman human information +🙋 person raising hand question +🙋‍♂️ man raising hand male boy man +🙋‍♀️ woman raising hand female girl woman +🧏 deaf person accessibility +🧏‍♂️ deaf man accessibility +🧏‍♀️ deaf woman accessibility +🙇 person bowing respectiful +🙇‍♂️ man bowing man male boy +🙇‍♀️ woman bowing woman female girl +🤦 person facepalming disappointed +🤦‍♂️ man facepalming man male boy disbelief +🤦‍♀️ woman facepalming woman female girl disbelief +🤷 person shrugging regardless +🤷‍♂️ man shrugging man male boy confused indifferent doubt +🤷‍♀️ woman shrugging woman female girl confused indifferent doubt +🧑‍⚕️ health worker hospital +👨‍⚕️ man health worker doctor nurse therapist healthcare man human +👩‍⚕️ woman health worker doctor nurse therapist healthcare woman human +🧑‍🎓 student learn +👨‍🎓 man student graduate man human +👩‍🎓 woman student graduate woman human +🧑‍🏫 teacher professor +👨‍🏫 man teacher instructor professor man human +👩‍🏫 woman teacher instructor professor woman human +🧑‍⚖️ judge law +👨‍⚖️ man judge justice court man human +👩‍⚖️ woman judge justice court woman human +🧑‍🌾 farmer crops +👨‍🌾 man farmer rancher gardener man human +👩‍🌾 woman farmer rancher gardener woman human +🧑‍🍳 cook food kitchen culinary +👨‍🍳 man cook chef man human +👩‍🍳 woman cook chef woman human +🧑‍🔧 mechanic worker technician +👨‍🔧 man mechanic plumber man human wrench +👩‍🔧 woman mechanic plumber woman human wrench +🧑‍🏭 factory worker labor +👨‍🏭 man factory worker assembly industrial man human +👩‍🏭 woman factory worker assembly industrial woman human +🧑‍💼 office worker business +👨‍💼 man office worker business manager man human +👩‍💼 woman office worker business manager woman human +🧑‍🔬 scientist chemistry +👨‍🔬 man scientist biologist chemist engineer physicist man human +👩‍🔬 woman scientist biologist chemist engineer physicist woman human +🧑‍💻 technologist computer +👨‍💻 man technologist coder developer engineer programmer software man human laptop computer +👩‍💻 woman technologist coder developer engineer programmer software woman human laptop computer +🧑‍🎤 singer song artist performer +👨‍🎤 man singer rockstar entertainer man human +👩‍🎤 woman singer rockstar entertainer woman human +🧑‍🎨 artist painting draw creativity +👨‍🎨 man artist painter man human +👩‍🎨 woman artist painter woman human +🧑‍✈️ pilot fly plane airplane +👨‍✈️ man pilot aviator plane man human +👩‍✈️ woman pilot aviator plane woman human +🧑‍🚀 astronaut outerspace +👨‍🚀 man astronaut space rocket man human +👩‍🚀 woman astronaut space rocket woman human +🧑‍🚒 firefighter fire +👨‍🚒 man firefighter fireman man human +👩‍🚒 woman firefighter fireman woman human +👮 police officer cop +👮‍♂️ man police officer man police law legal enforcement arrest 911 +👮‍♀️ woman police officer woman police law legal enforcement arrest 911 female +🕵️ detective human spy detective +🕵️‍♂️ man detective crime +🕵️‍♀️ woman detective human spy detective female woman +💂 guard protect +💂‍♂️ man guard uk gb british male guy royal +💂‍♀️ woman guard uk gb british female royal woman +👷 construction worker labor build +👷‍♂️ man construction worker male human wip guy build construction worker labor +👷‍♀️ woman construction worker female human wip build construction worker labor woman +🤴 prince boy man male crown royal king +👸 princess girl woman female blond crown royal queen +👳 person wearing turban headdress +👳‍♂️ man wearing turban male indian hinduism arabs +👳‍♀️ woman wearing turban female indian hinduism arabs woman +👲 man with skullcap male boy chinese +🧕 woman with headscarf female hijab mantilla tichel +🤵 man in tuxedo couple marriage wedding groom +👰 bride with veil couple marriage wedding woman bride +🤰 pregnant woman baby +🤱 breast feeding nursing baby +👼 baby angel heaven wings halo +🎅 santa claus festival man male xmas father christmas +🤶 mrs claus woman female xmas mother christmas +🦸 superhero marvel +🦸‍♂️ man superhero man male good hero superpowers +🦸‍♀️ woman superhero woman female good heroine superpowers +🦹 supervillain marvel +🦹‍♂️ man supervillain man male evil bad criminal hero superpowers +🦹‍♀️ woman supervillain woman female evil bad criminal heroine superpowers +🧙 mage magic +🧙‍♂️ man mage man male mage sorcerer +🧙‍♀️ woman mage woman female mage witch +🧚 fairy wings magical +🧚‍♂️ man fairy man male +🧚‍♀️ woman fairy woman female +🧛 vampire blood twilight +🧛‍♂️ man vampire man male dracula +🧛‍♀️ woman vampire woman female +🧜 merperson sea +🧜‍♂️ merman man male triton +🧜‍♀️ mermaid woman female merwoman ariel +🧝 elf magical +🧝‍♂️ man elf man male +🧝‍♀️ woman elf woman female +🧞 genie magical wishes +🧞‍♂️ man genie man male +🧞‍♀️ woman genie woman female +🧟 zombie dead +🧟‍♂️ man zombie man male dracula undead walking dead +🧟‍♀️ woman zombie woman female undead walking dead +💆 person getting massage relax +💆‍♂️ man getting massage male boy man head +💆‍♀️ woman getting massage female girl woman head +💇 person getting haircut hairstyle +💇‍♂️ man getting haircut male boy man +💇‍♀️ woman getting haircut female girl woman +🚶 person walking move +🚶‍♂️ man walking human feet steps +🚶‍♀️ woman walking human feet steps woman female +🧍 person standing still +🧍‍♂️ man standing still +🧍‍♀️ woman standing still +🧎 person kneeling pray respectful +🧎‍♂️ man kneeling pray respectful +🧎‍♀️ woman kneeling respectful pray +🧑‍🦯 person with probing cane blind +👨‍🦯 man with probing cane blind +👩‍🦯 woman with probing cane blind +🧑‍🦼 person in motorized wheelchair disability accessibility +👨‍🦼 man in motorized wheelchair disability accessibility +👩‍🦼 woman in motorized wheelchair disability accessibility +🧑‍🦽 person in manual wheelchair disability accessibility +👨‍🦽 man in manual wheelchair disability accessibility +👩‍🦽 woman in manual wheelchair disability accessibility +🏃 person running move +🏃‍♂️ man running man walking exercise race running +🏃‍♀️ woman running woman walking exercise race running female +💃 woman dancing female girl woman fun +🕺 man dancing male boy fun dancer +🕴️ man in suit levitating suit business levitate hover jump +👯 people with bunny ears perform costume +👯‍♂️ men with bunny ears male bunny men boys +👯‍♀️ women with bunny ears female bunny women girls +🧖 person in steamy room relax spa +🧖‍♂️ man in steamy room male man spa steamroom sauna +🧖‍♀️ woman in steamy room female woman spa steamroom sauna +🧗 person climbing sport +🧗‍♂️ man climbing sports hobby man male rock +🧗‍♀️ woman climbing sports hobby woman female rock +🤺 person fencing sports fencing sword +🏇 horse racing animal betting competition gambling luck +⛷️ skier sports winter snow +🏂 snowboarder sports winter +🏌️ person golfing sports business +🏌️‍♂️ man golfing sport +🏌️‍♀️ woman golfing sports business woman female +🏄 person surfing sport sea +🏄‍♂️ man surfing sports ocean sea summer beach +🏄‍♀️ woman surfing sports ocean sea summer beach woman female +🚣 person rowing boat sport move +🚣‍♂️ man rowing boat sports hobby water ship +🚣‍♀️ woman rowing boat sports hobby water ship woman female +🏊 person swimming sport pool +🏊‍♂️ man swimming sports exercise human athlete water summer +🏊‍♀️ woman swimming sports exercise human athlete water summer woman female +⛹️ person bouncing ball sports human +⛹️‍♂️ man bouncing ball sport +⛹️‍♀️ woman bouncing ball sports human woman female +🏋️ person lifting weights sports training exercise +🏋️‍♂️ man lifting weights sport +🏋️‍♀️ woman lifting weights sports training exercise woman female +🚴 person biking sport move +🚴‍♂️ man biking sports bike exercise hipster +🚴‍♀️ woman biking sports bike exercise hipster woman female +🚵 person mountain biking sport move +🚵‍♂️ man mountain biking transportation sports human race bike +🚵‍♀️ woman mountain biking transportation sports human race bike woman female +🤸 person cartwheeling sport gymnastic +🤸‍♂️ man cartwheeling gymnastics +🤸‍♀️ woman cartwheeling gymnastics +🤼 people wrestling sport +🤼‍♂️ men wrestling sports wrestlers +🤼‍♀️ women wrestling sports wrestlers +🤽 person playing water polo sport +🤽‍♂️ man playing water polo sports pool +🤽‍♀️ woman playing water polo sports pool +🤾 person playing handball sport +🤾‍♂️ man playing handball sports +🤾‍♀️ woman playing handball sports +🤹 person juggling performance balance +🤹‍♂️ man juggling juggle balance skill multitask +🤹‍♀️ woman juggling juggle balance skill multitask +🧘 person in lotus position meditate +🧘‍♂️ man in lotus position man male meditation yoga serenity zen mindfulness +🧘‍♀️ woman in lotus position woman female meditation yoga serenity zen mindfulness +🛀 person taking bath clean shower bathroom +🛌 person in bed bed rest +🧑‍🤝‍🧑 people holding hands friendship +👭 women holding hands pair friendship couple love like female people human +👫 woman and man holding hands pair people human love date dating like affection valentines marriage +👬 men holding hands pair couple love like bromance friendship people human +💏 kiss pair valentines love like dating marriage +👩‍❤️‍💋‍👨 kiss woman man love +👨‍❤️‍💋‍👨 kiss man man pair valentines love like dating marriage +👩‍❤️‍💋‍👩 kiss woman woman pair valentines love like dating marriage +💑 couple with heart pair love like affection human dating valentines marriage +👩‍❤️‍👨 couple with heart woman man love +👨‍❤️‍👨 couple with heart man man pair love like affection human dating valentines marriage +👩‍❤️‍👩 couple with heart woman woman pair love like affection human dating valentines marriage +👪 family home parents child mom dad father mother people human +👨‍👩‍👦 family man woman boy love +👨‍👩‍👧 family man woman girl home parents people human child +👨‍👩‍👧‍👦 family man woman girl boy home parents people human children +👨‍👩‍👦‍👦 family man woman boy boy home parents people human children +👨‍👩‍👧‍👧 family man woman girl girl home parents people human children +👨‍👨‍👦 family man man boy home parents people human children +👨‍👨‍👧 family man man girl home parents people human children +👨‍👨‍👧‍👦 family man man girl boy home parents people human children +👨‍👨‍👦‍👦 family man man boy boy home parents people human children +👨‍👨‍👧‍👧 family man man girl girl home parents people human children +👩‍👩‍👦 family woman woman boy home parents people human children +👩‍👩‍👧 family woman woman girl home parents people human children +👩‍👩‍👧‍👦 family woman woman girl boy home parents people human children +👩‍👩‍👦‍👦 family woman woman boy boy home parents people human children +👩‍👩‍👧‍👧 family woman woman girl girl home parents people human children +👨‍👦 family man boy home parent people human child +👨‍👦‍👦 family man boy boy home parent people human children +👨‍👧 family man girl home parent people human child +👨‍👧‍👦 family man girl boy home parent people human children +👨‍👧‍👧 family man girl girl home parent people human children +👩‍👦 family woman boy home parent people human child +👩‍👦‍👦 family woman boy boy home parent people human children +👩‍👧 family woman girl home parent people human child +👩‍👧‍👦 family woman girl boy home parent people human children +👩‍👧‍👧 family woman girl girl home parent people human children +🗣️ speaking head user person human sing say talk +👤 bust in silhouette user person human +👥 busts in silhouette user person human group team +👣 footprints feet tracking walking beach +🐵 monkey face animal nature circus +🐒 monkey animal nature banana circus +🦍 gorilla animal nature circus +🦧 orangutan animal +🐶 dog face animal friend nature woof puppy pet faithful +🐕 dog animal nature friend doge pet faithful +🦮 guide dog animal blind +🐕‍🦺 service dog blind animal +🐩 poodle dog animal 101 nature pet +🐺 wolf animal nature wild +🦊 fox animal nature face +🦝 raccoon animal nature +🐱 cat face animal meow nature pet kitten +🐈 cat animal meow pet cats +🦁 lion animal nature +🐯 tiger face animal cat danger wild nature roar +🐅 tiger animal nature roar +🐆 leopard animal nature +🐴 horse face animal brown nature +🐎 horse animal gamble luck +🦄 unicorn animal nature mystical +🦓 zebra animal nature stripes safari +🦌 deer animal nature horns venison +🐮 cow face beef ox animal nature moo milk +🐂 ox animal cow beef +🐃 water buffalo animal nature ox cow +🐄 cow beef ox animal nature moo milk +🐷 pig face animal oink nature +🐖 pig animal nature +🐗 boar animal nature +🐽 pig nose animal oink +🐏 ram animal sheep nature +🐑 ewe animal nature wool shipit +🐐 goat animal nature +🐪 camel animal hot desert hump +🐫 two hump camel animal nature hot desert hump +🦙 llama animal nature alpaca +🦒 giraffe animal nature spots safari +🐘 elephant animal nature nose th circus +🦏 rhinoceros animal nature horn +🦛 hippopotamus animal nature +🐭 mouse face animal nature cheese wedge rodent +🐁 mouse animal nature rodent +🐀 rat animal mouse rodent +🐹 hamster animal nature +🐰 rabbit face animal nature pet spring magic bunny +🐇 rabbit animal nature pet magic spring +🐿️ chipmunk animal nature rodent squirrel +🦔 hedgehog animal nature spiny +🦇 bat animal nature blind vampire +🐻 bear animal nature wild +🐨 koala animal nature +🐼 panda animal nature panda +🦥 sloth animal +🦦 otter animal +🦨 skunk animal +🦘 kangaroo animal nature australia joey hop marsupial +🦡 badger animal nature honey +🐾 paw prints animal tracking footprints dog cat pet feet +🦃 turkey animal bird +🐔 chicken animal cluck nature bird +🐓 rooster animal nature chicken +🐣 hatching chick animal chicken egg born baby bird +🐤 baby chick animal chicken bird +🐥 front facing baby chick animal chicken baby bird +🐦 bird animal nature fly tweet spring +🐧 penguin animal nature +🕊️ dove animal bird +🦅 eagle animal nature bird +🦆 duck animal nature bird mallard +🦢 swan animal nature bird +🦉 owl animal nature bird hoot +🦩 flamingo animal +🦚 peacock animal nature peahen bird +🦜 parrot animal nature bird pirate talk +🐸 frog animal nature croak toad +🐊 crocodile animal nature reptile lizard alligator +🐢 turtle animal slow nature tortoise +🦎 lizard animal nature reptile +🐍 snake animal evil nature hiss python +🐲 dragon face animal myth nature chinese green +🐉 dragon animal myth nature chinese green +🦕 sauropod animal nature dinosaur brachiosaurus brontosaurus diplodocus extinct +🦖 t rex animal nature dinosaur tyrannosaurus extinct +🐳 spouting whale animal nature sea ocean +🐋 whale animal nature sea ocean +🐬 dolphin animal nature fish sea ocean flipper fins beach +🐟 fish animal food nature +🐠 tropical fish animal swim ocean beach nemo +🐡 blowfish animal nature food sea ocean +🦈 shark animal nature fish sea ocean jaws fins beach +🐙 octopus animal creature ocean sea nature beach +🐚 spiral shell nature sea beach +🐌 snail slow animal shell +🦋 butterfly animal insect nature caterpillar +🐛 bug animal insect nature worm +🐜 ant animal insect nature bug +🐝 honeybee animal insect nature bug spring honey +🐞 lady beetle animal insect nature ladybug +🦗 cricket animal cricket chirp +🕷️ spider animal arachnid +🕸️ spider web animal insect arachnid silk +🦂 scorpion animal arachnid +🦟 mosquito animal nature insect malaria +🦠 microbe amoeba bacteria germs virus +💐 bouquet flowers nature spring +🌸 cherry blossom nature plant spring flower +💮 white flower japanese spring +🏵️ rosette flower decoration military +🌹 rose flowers valentines love spring +🥀 wilted flower plant nature flower +🌺 hibiscus plant vegetable flowers beach +🌻 sunflower nature plant fall +🌼 blossom nature flowers yellow +🌷 tulip flowers plant nature summer spring +🌱 seedling plant nature grass lawn spring +🌲 evergreen tree plant nature +🌳 deciduous tree plant nature +🌴 palm tree plant vegetable nature summer beach mojito tropical +🌵 cactus vegetable plant nature +🌾 sheaf of rice nature plant +🌿 herb vegetable plant medicine weed grass lawn +☘️ shamrock vegetable plant nature irish clover +🍀 four leaf clover vegetable plant nature lucky irish +🍁 maple leaf nature plant vegetable ca fall +🍂 fallen leaf nature plant vegetable leaves +🍃 leaf fluttering in wind nature plant tree vegetable grass lawn spring +🍇 grapes fruit food wine +🍈 melon fruit nature food +🍉 watermelon fruit food picnic summer +🍊 tangerine food fruit nature orange +🍋 lemon fruit nature +🍌 banana fruit food monkey +🍍 pineapple fruit nature food +🥭 mango fruit food tropical +🍎 red apple fruit mac school +🍏 green apple fruit nature +🍐 pear fruit nature food +🍑 peach fruit nature food +🍒 cherries food fruit +🍓 strawberry fruit food nature +🥝 kiwi fruit fruit food +🍅 tomato fruit vegetable nature food +🥥 coconut fruit nature food palm +🥑 avocado fruit food +🍆 eggplant vegetable nature food aubergine +🥔 potato food tuber vegatable starch +🥕 carrot vegetable food orange +🌽 ear of corn food vegetable plant +🌶️ hot pepper food spicy chilli chili +🥒 cucumber fruit food pickle +🥬 leafy green food vegetable plant bok choy cabbage kale lettuce +🥦 broccoli fruit food vegetable +🧄 garlic food spice cook +🧅 onion cook food spice +🍄 mushroom plant vegetable +🥜 peanuts food nut +🌰 chestnut food squirrel +🍞 bread food wheat breakfast toast +🥐 croissant food bread french +🥖 baguette bread food bread french +🥨 pretzel food bread twisted +🥯 bagel food bread bakery schmear +🥞 pancakes food breakfast flapjacks hotcakes +🧇 waffle food breakfast +🧀 cheese wedge food chadder +🍖 meat on bone good food drumstick +🍗 poultry leg food meat drumstick bird chicken turkey +🥩 cut of meat food cow meat cut chop lambchop porkchop +🥓 bacon food breakfast pork pig meat +🍔 hamburger meat fast food beef cheeseburger mcdonalds burger king +🍟 french fries chips snack fast food +🍕 pizza food party +🌭 hot dog food frankfurter +🥪 sandwich food lunch bread +🌮 taco food mexican +🌯 burrito food mexican +🥙 stuffed flatbread food flatbread stuffed gyro +🧆 falafel food +🥚 egg food chicken breakfast +🍳 cooking food breakfast kitchen egg +🥘 shallow pan of food food cooking casserole paella +🍲 pot of food food meat soup +🥣 bowl with spoon food breakfast cereal oatmeal porridge +🥗 green salad food healthy lettuce +🍿 popcorn food movie theater films snack +🧈 butter food cook +🧂 salt condiment shaker +🥫 canned food food soup +🍱 bento box food japanese box +🍘 rice cracker food japanese +🍙 rice ball food japanese +🍚 cooked rice food china asian +🍛 curry rice food spicy hot indian +🍜 steaming bowl food japanese noodle chopsticks +🍝 spaghetti food italian noodle +🍠 roasted sweet potato food nature +🍢 oden food japanese +🍣 sushi food fish japanese rice +🍤 fried shrimp food animal appetizer summer +🍥 fish cake with swirl food japan sea beach narutomaki pink swirl kamaboko surimi ramen +🥮 moon cake food autumn +🍡 dango food dessert sweet japanese barbecue meat +🥟 dumpling food empanada pierogi potsticker +🥠 fortune cookie food prophecy +🥡 takeout box food leftovers +🦀 crab animal crustacean +🦞 lobster animal nature bisque claws seafood +🦐 shrimp animal ocean nature seafood +🦑 squid animal nature ocean sea +🦪 oyster food +🍦 soft ice cream food hot dessert summer +🍧 shaved ice hot dessert summer +🍨 ice cream food hot dessert +🍩 doughnut food dessert snack sweet donut +🍪 cookie food snack oreo chocolate sweet dessert +🎂 birthday cake food dessert cake +🍰 shortcake food dessert +🧁 cupcake food dessert bakery sweet +🥧 pie food dessert pastry +🍫 chocolate bar food snack dessert sweet +🍬 candy snack dessert sweet lolly +🍭 lollipop food snack candy sweet +🍮 custard dessert food +🍯 honey pot bees sweet kitchen +🍼 baby bottle food container milk +🥛 glass of milk beverage drink cow +☕ hot beverage beverage caffeine latte espresso coffee +🍵 teacup without handle drink bowl breakfast green british +🍶 sake wine drink drunk beverage japanese alcohol booze +🍾 bottle with popping cork drink wine bottle celebration +🍷 wine glass drink beverage drunk alcohol booze +🍸 cocktail glass drink drunk alcohol beverage booze mojito +🍹 tropical drink beverage cocktail summer beach alcohol booze mojito +🍺 beer mug relax beverage drink drunk party pub summer alcohol booze +🍻 clinking beer mugs relax beverage drink drunk party pub summer alcohol booze +🥂 clinking glasses beverage drink party alcohol celebrate cheers wine champagne toast +🥃 tumbler glass drink beverage drunk alcohol liquor booze bourbon scotch whisky glass shot +🥤 cup with straw drink soda +🧃 beverage box drink +🧉 mate drink tea beverage +🧊 ice water cold +🥢 chopsticks food +🍽️ fork and knife with plate food eat meal lunch dinner restaurant +🍴 fork and knife cutlery kitchen +🥄 spoon cutlery kitchen tableware +🔪 kitchen knife knife blade cutlery kitchen weapon +🏺 amphora vase jar +🌍 globe showing europe africa globe world international +🌎 globe showing americas globe world USA international +🌏 globe showing asia australia globe world east international +🌐 globe with meridians earth international world internet interweb i18n +🗺️ world map location direction +🗾 map of japan nation country japanese asia +🧭 compass magnetic navigation orienteering +🏔️ snow capped mountain photo nature environment winter cold +⛰️ mountain photo nature environment +🌋 volcano photo nature disaster +🗻 mount fuji photo mountain nature japanese +🏕️ camping photo outdoors tent +🏖️ beach with umbrella weather summer sunny sand mojito +🏜️ desert photo warm saharah +🏝️ desert island photo tropical mojito +🏞️ national park photo environment nature +🏟️ stadium photo place sports concert venue +🏛️ classical building art culture history +🏗️ building construction wip working progress +🧱 brick bricks +🏘️ houses buildings photo +🏚️ derelict house abandon evict broken building +🏠 house building home +🏡 house with garden home plant nature +🏢 office building building bureau work +🏣 japanese post office building envelope communication +🏤 post office building email +🏥 hospital building health surgery doctor +🏦 bank building money sales cash business enterprise +🏨 hotel building accomodation checkin +🏩 love hotel like affection dating +🏪 convenience store building shopping groceries +🏫 school building student education learn teach +🏬 department store building shopping mall +🏭 factory building industry pollution smoke +🏯 japanese castle photo building +🏰 castle building royalty history +💒 wedding love like affection couple marriage bride groom +🗼 tokyo tower photo japanese +🗽 statue of liberty american newyork +⛪ church building religion christ +🕌 mosque islam worship minaret +🛕 hindu temple religion +🕍 synagogue judaism worship temple jewish +⛩️ shinto shrine temple japan kyoto +🕋 kaaba mecca mosque islam +⛲ fountain photo summer water fresh +⛺ tent photo camping outdoors +🌁 foggy photo mountain +🌃 night with stars evening city downtown +🏙️ cityscape photo night life urban +🌄 sunrise over mountains view vacation photo +🌅 sunrise morning view vacation photo +🌆 cityscape at dusk photo evening sky buildings +🌇 sunset photo good morning dawn +🌉 bridge at night photo sanfrancisco +♨️ hot springs bath warm relax +🎠 carousel horse photo carnival +🎡 ferris wheel photo carnival londoneye +🎢 roller coaster carnival playground photo fun +💈 barber pole hair salon style +🎪 circus tent festival carnival party +🚂 locomotive transportation vehicle train +🚃 railway car transportation vehicle +🚄 high speed train transportation vehicle +🚅 bullet train transportation vehicle speed fast public travel +🚆 train transportation vehicle +🚇 metro transportation blue-square mrt underground tube +🚈 light rail transportation vehicle +🚉 station transportation vehicle public +🚊 tram transportation vehicle +🚝 monorail transportation vehicle +🚞 mountain railway transportation vehicle +🚋 tram car transportation vehicle carriage public travel +🚌 bus car vehicle transportation +🚍 oncoming bus vehicle transportation +🚎 trolleybus bart transportation vehicle +🚐 minibus vehicle car transportation +🚑 ambulance health 911 hospital +🚒 fire engine transportation cars vehicle +🚓 police car vehicle cars transportation law legal enforcement +🚔 oncoming police car vehicle law legal enforcement 911 +🚕 taxi uber vehicle cars transportation +🚖 oncoming taxi vehicle cars uber +🚗 automobile red transportation vehicle +🚘 oncoming automobile car vehicle transportation +🚙 sport utility vehicle transportation vehicle +🚚 delivery truck cars transportation +🚛 articulated lorry vehicle cars transportation express +🚜 tractor vehicle car farming agriculture +🏎️ racing car sports race fast formula f1 +🏍️ motorcycle race sports fast +🛵 motor scooter vehicle vespa sasha +🦽 manual wheelchair accessibility +🦼 motorized wheelchair accessibility +🛺 auto rickshaw move transportation +🚲 bicycle sports bicycle exercise hipster +🛴 kick scooter vehicle kick razor +🛹 skateboard board +🚏 bus stop transportation wait +🛣️ motorway road cupertino interstate highway +🛤️ railway track train transportation +🛢️ oil drum barrell +⛽ fuel pump gas station petroleum +🚨 police car light police ambulance 911 emergency alert error pinged law legal +🚥 horizontal traffic light transportation signal +🚦 vertical traffic light transportation driving +🛑 stop sign stop +🚧 construction wip progress caution warning +⚓ anchor ship ferry sea boat +⛵ sailboat ship summer transportation water sailing +🛶 canoe boat paddle water ship +🚤 speedboat ship transportation vehicle summer +🛳️ passenger ship yacht cruise ferry +⛴️ ferry boat ship yacht +🛥️ motor boat ship +🚢 ship transportation titanic deploy +✈️ airplane vehicle transportation flight fly +🛩️ small airplane flight transportation fly vehicle +🛫 airplane departure airport flight landing +🛬 airplane arrival airport flight boarding +🪂 parachute fly glide +💺 seat sit airplane transport bus flight fly +🚁 helicopter transportation vehicle fly +🚟 suspension railway vehicle transportation +🚠 mountain cableway transportation vehicle ski +🚡 aerial tramway transportation vehicle ski +🛰️ satellite communication gps orbit spaceflight NASA ISS +🚀 rocket launch ship staffmode NASA outer space outer space fly +🛸 flying saucer transportation vehicle ufo +🛎️ bellhop bell service +🧳 luggage packing travel +⌛ hourglass done time clock oldschool limit exam quiz test +⏳ hourglass not done oldschool time countdown +⌚ watch time accessories +⏰ alarm clock time wake +⏱️ stopwatch time deadline +⏲️ timer clock alarm +🕰️ mantelpiece clock time +🕛 twelve o clock time noon midnight midday late early schedule +🕧 twelve thirty time late early schedule +🕐 one o clock time late early schedule +🕜 one thirty time late early schedule +🕑 two o clock time late early schedule +🕝 two thirty time late early schedule +🕒 three o clock time late early schedule +🕞 three thirty time late early schedule +🕓 four o clock time late early schedule +🕟 four thirty time late early schedule +🕔 five o clock time late early schedule +🕠 five thirty time late early schedule +🕕 six o clock time late early schedule dawn dusk +🕡 six thirty time late early schedule +🕖 seven o clock time late early schedule +🕢 seven thirty time late early schedule +🕗 eight o clock time late early schedule +🕣 eight thirty time late early schedule +🕘 nine o clock time late early schedule +🕤 nine thirty time late early schedule +🕙 ten o clock time late early schedule +🕥 ten thirty time late early schedule +🕚 eleven o clock time late early schedule +🕦 eleven thirty time late early schedule +🌑 new moon nature twilight planet space night evening sleep +🌒 waxing crescent moon nature twilight planet space night evening sleep +🌓 first quarter moon nature twilight planet space night evening sleep +🌔 waxing gibbous moon nature night sky gray twilight planet space evening sleep +🌕 full moon nature yellow twilight planet space night evening sleep +🌖 waning gibbous moon nature twilight planet space night evening sleep waxing gibbous moon +🌗 last quarter moon nature twilight planet space night evening sleep +🌘 waning crescent moon nature twilight planet space night evening sleep +🌙 crescent moon night sleep sky evening magic +🌚 new moon face nature twilight planet space night evening sleep +🌛 first quarter moon face nature twilight planet space night evening sleep +🌜 last quarter moon face nature twilight planet space night evening sleep +🌡️ thermometer weather temperature hot cold +☀️ sun weather nature brightness summer beach spring +🌝 full moon face nature twilight planet space night evening sleep +🌞 sun with face nature morning sky +🪐 ringed planet outerspace +⭐ star night yellow +🌟 glowing star night sparkle awesome good magic +🌠 shooting star night photo +🌌 milky way photo space stars +☁️ cloud weather sky +⛅ sun behind cloud weather nature cloudy morning fall spring +⛈️ cloud with lightning and rain weather lightning +🌤️ sun behind small cloud weather +🌥️ sun behind large cloud weather +🌦️ sun behind rain cloud weather +🌧️ cloud with rain weather +🌨️ cloud with snow weather +🌩️ cloud with lightning weather thunder +🌪️ tornado weather cyclone twister +🌫️ fog weather +🌬️ wind face gust air +🌀 cyclone weather swirl blue cloud vortex spiral whirlpool spin tornado hurricane typhoon +🌈 rainbow nature happy unicorn face photo sky spring +🌂 closed umbrella weather rain drizzle +☂️ umbrella weather spring +☔ umbrella with rain drops rainy weather spring +⛱️ umbrella on ground weather summer +⚡ high voltage thunder weather lightning bolt fast +❄️ snowflake winter season cold weather christmas xmas +☃️ snowman winter season cold weather christmas xmas frozen +⛄ snowman without snow winter season cold weather christmas xmas frozen without snow +☄️ comet space +🔥 fire hot cook flame +💧 droplet water drip faucet spring +🌊 water wave sea water wave nature tsunami disaster +🎃 jack o lantern halloween light pumpkin creepy fall +🎄 christmas tree festival vacation december xmas celebration +🎆 fireworks photo festival carnival congratulations +🎇 sparkler stars night shine +🧨 firecracker dynamite boom explode explosion explosive +✨ sparkles stars shine shiny cool awesome good magic +🎈 balloon party celebration birthday circus +🎉 party popper party congratulations birthday magic circus celebration tada +🎊 confetti ball festival party birthday circus +🎋 tanabata tree plant nature branch summer +🎍 pine decoration plant nature vegetable panda pine decoration +🎎 japanese dolls japanese toy kimono +🎏 carp streamer fish japanese koinobori carp banner +🎐 wind chime nature ding spring bell +🎑 moon viewing ceremony photo japan asia tsukimi +🧧 red envelope gift +🎀 ribbon decoration pink girl bowtie +🎁 wrapped gift present birthday christmas xmas +🎗️ reminder ribbon sports cause support awareness +🎟️ admission tickets sports concert entrance +🎫 ticket event concert pass +🎖️ military medal award winning army +🏆 trophy win award contest place ftw ceremony +🏅 sports medal award winning +🥇 1st place medal award winning first +🥈 2nd place medal award second +🥉 3rd place medal award third +⚽ soccer ball sports football +⚾ baseball sports balls +🥎 softball sports balls +🏀 basketball sports balls NBA +🏐 volleyball sports balls +🏈 american football sports balls NFL +🏉 rugby football sports team +🎾 tennis sports balls green +🥏 flying disc sports frisbee ultimate +🎳 bowling sports fun play +🏏 cricket game sports +🏑 field hockey sports +🏒 ice hockey sports +🥍 lacrosse sports ball stick +🏓 ping pong sports pingpong +🏸 badminton sports +🥊 boxing glove sports fighting +🥋 martial arts uniform judo karate taekwondo +🥅 goal net sports +⛳ flag in hole sports business flag hole summer +⛸️ ice skate sports +🎣 fishing pole food hobby summer +🤿 diving mask sport ocean +🎽 running shirt play pageant +🎿 skis sports winter cold snow +🛷 sled sleigh luge toboggan +🥌 curling stone sports +🎯 direct hit game play bar target bullseye +🪀 yo yo toy +🪁 kite wind fly +🎱 pool 8 ball pool hobby game luck magic +🔮 crystal ball disco party magic circus fortune teller +🧿 nazar amulet bead charm +🎮 video game play console PS4 controller +🕹️ joystick game play +🎰 slot machine bet gamble vegas fruit machine luck casino +🎲 game die dice random tabletop play luck +🧩 puzzle piece interlocking puzzle piece +🧸 teddy bear plush stuffed +♠️ spade suit poker cards suits magic +♥️ heart suit poker cards magic suits +♦️ diamond suit poker cards magic suits +♣️ club suit poker cards magic suits +♟️ chess pawn expendable +🃏 joker poker cards game play magic +🀄 mahjong red dragon game play chinese kanji +🎴 flower playing cards game sunset red +🎭 performing arts acting theater drama +🖼️ framed picture photography +🎨 artist palette design paint draw colors +🧵 thread needle sewing spool string +🧶 yarn ball crochet knit +👓 glasses fashion accessories eyesight nerdy dork geek +🕶️ sunglasses face cool accessories +🥽 goggles eyes protection safety +🥼 lab coat doctor experiment scientist chemist +🦺 safety vest protection +👔 necktie shirt suitup formal fashion cloth business +👕 t shirt fashion cloth casual shirt tee +👖 jeans fashion shopping +🧣 scarf neck winter clothes +🧤 gloves hands winter clothes +🧥 coat jacket +🧦 socks stockings clothes +👗 dress clothes fashion shopping +👘 kimono dress fashion women female japanese +🥻 sari dress +🩱 one piece swimsuit fashion +🩲 briefs clothing +🩳 shorts clothing +👙 bikini swimming female woman girl fashion beach summer +👚 woman s clothes fashion shopping bags female +👛 purse fashion accessories money sales shopping +👜 handbag fashion accessory accessories shopping +👝 clutch bag bag accessories shopping +🛍️ shopping bags mall buy purchase +🎒 backpack student education bag backpack +👞 man s shoe fashion male +👟 running shoe shoes sports sneakers +🥾 hiking boot backpacking camping hiking +🥿 flat shoe ballet slip-on slipper +👠 high heeled shoe fashion shoes female pumps stiletto +👡 woman s sandal shoes fashion flip flops +🩰 ballet shoes dance +👢 woman s boot shoes fashion +👑 crown king kod leader royalty lord +👒 woman s hat fashion accessories female lady spring +🎩 top hat magic gentleman classy circus +🎓 graduation cap school college degree university graduation cap hat legal learn education +🧢 billed cap cap baseball +⛑️ rescue worker s helmet construction build +📿 prayer beads dhikr religious +💄 lipstick female girl fashion woman +💍 ring wedding propose marriage valentines diamond fashion jewelry gem engagement +💎 gem stone blue ruby diamond jewelry +🔇 muted speaker sound volume silence quiet +🔈 speaker low volume sound volume silence broadcast +🔉 speaker medium volume volume speaker broadcast +🔊 speaker high volume volume noise noisy speaker broadcast +📢 loudspeaker volume sound +📣 megaphone sound speaker volume +📯 postal horn instrument music +🔔 bell sound notification christmas xmas chime +🔕 bell with slash sound volume mute quiet silent +🎼 musical score treble clef compose +🎵 musical note score tone sound +🎶 musical notes music score +🎙️ studio microphone sing recording artist talkshow +🎚️ level slider scale +🎛️ control knobs dial +🎤 microphone sound music PA sing talkshow +🎧 headphone music score gadgets +📻 radio communication music podcast program +🎷 saxophone music instrument jazz blues +🎸 guitar music instrument +🎹 musical keyboard piano instrument compose +🎺 trumpet music brass +🎻 violin music instrument orchestra symphony +🪕 banjo music instructment +🥁 drum music instrument drumsticks snare +📱 mobile phone technology apple gadgets dial +📲 mobile phone with arrow iphone incoming +☎️ telephone technology communication dial telephone +📞 telephone receiver technology communication dial +📟 pager bbcall oldschool 90s +📠 fax machine communication technology +🔋 battery power energy sustain +🔌 electric plug charger power +💻 laptop technology laptop screen display monitor +🖥️ desktop computer technology computing screen +🖨️ printer paper ink +⌨️ keyboard technology computer type input text +🖱️ computer mouse click +🖲️ trackball technology trackpad +💽 computer disk technology record data disk 90s +💾 floppy disk oldschool technology save 90s 80s +💿 optical disk technology dvd disk disc 90s +📀 dvd cd disk disc +🧮 abacus calculation +🎥 movie camera film record +🎞️ film frames movie +📽️ film projector video tape record movie +🎬 clapper board movie film record +📺 television technology program oldschool show television +📷 camera gadgets photography +📸 camera with flash photography gadgets +📹 video camera film record +📼 videocassette record video oldschool 90s 80s +🔍 magnifying glass tilted left search zoom find detective +🔎 magnifying glass tilted right search zoom find detective +🕯️ candle fire wax +💡 light bulb light electricity idea +🔦 flashlight dark camping sight night +🏮 red paper lantern light paper halloween spooky +🪔 diya lamp lighting +📔 notebook with decorative cover classroom notes record paper study +📕 closed book read library knowledge textbook learn +📖 open book book read library knowledge literature learn study +📗 green book read library knowledge study +📘 blue book read library knowledge learn study +📙 orange book read library knowledge textbook study +📚 books literature library study +📓 notebook stationery record notes paper study +📒 ledger notes paper +📃 page with curl documents office paper +📜 scroll documents ancient history paper +📄 page facing up documents office paper information +📰 newspaper press headline +🗞️ rolled up newspaper press headline +📑 bookmark tabs favorite save order tidy +🔖 bookmark favorite label save +🏷️ label sale tag +💰 money bag dollar payment coins sale +💴 yen banknote money sales japanese dollar currency +💵 dollar banknote money sales bill currency +💶 euro banknote money sales dollar currency +💷 pound banknote british sterling money sales bills uk england currency +💸 money with wings dollar bills payment sale +💳 credit card money sales dollar bill payment shopping +🧾 receipt accounting expenses +💹 chart increasing with yen green-square graph presentation stats +💱 currency exchange money sales dollar travel +💲 heavy dollar sign money sales payment currency buck +✉️ envelope letter postal inbox communication +📧 e mail communication inbox +📨 incoming envelope email inbox +📩 envelope with arrow email communication +📤 outbox tray inbox email +📥 inbox tray email documents +📦 package mail gift cardboard box moving +📫 closed mailbox with raised flag email inbox communication +📪 closed mailbox with lowered flag email communication inbox +📬 open mailbox with raised flag email inbox communication +📭 open mailbox with lowered flag email inbox +📮 postbox email letter envelope +🗳️ ballot box with ballot election vote +✏️ pencil stationery write paper writing school study +✒️ black nib pen stationery writing write +🖋️ fountain pen stationery writing write +🖊️ pen stationery writing write +🖌️ paintbrush drawing creativity art +🖍️ crayon drawing creativity +📝 memo write documents stationery pencil paper writing legal exam quiz test study compose +💼 briefcase business documents work law legal job career +📁 file folder documents business office +📂 open file folder documents load +🗂️ card index dividers organizing business stationery +📅 calendar calendar schedule +📆 tear off calendar schedule date planning +🗒️ spiral notepad memo stationery +🗓️ spiral calendar date schedule planning +📇 card index business stationery +📈 chart increasing graph presentation stats recovery business economics money sales good success +📉 chart decreasing graph presentation stats recession business economics money sales bad failure +📊 bar chart graph presentation stats +📋 clipboard stationery documents +📌 pushpin stationery mark here +📍 round pushpin stationery location map here +📎 paperclip documents stationery +🖇️ linked paperclips documents stationery +📏 straight ruler stationery calculate length math school drawing architect sketch +📐 triangular ruler stationery math architect sketch +✂️ scissors stationery cut +🗃️ card file box business stationery +🗄️ file cabinet filing organizing +🗑️ wastebasket bin trash rubbish garbage toss +🔒 locked security password padlock +🔓 unlocked privacy security +🔏 locked with pen security secret +🔐 locked with key security privacy +🔑 key lock door password +🗝️ old key lock door password +🔨 hammer tools build create +🪓 axe tool chop cut +⛏️ pick tools dig +⚒️ hammer and pick tools build create +🛠️ hammer and wrench tools build create +🗡️ dagger weapon +⚔️ crossed swords weapon +🔫 pistol violence weapon pistol revolver +🏹 bow and arrow sports +🛡️ shield protection security +🔧 wrench tools diy ikea fix maintainer +🔩 nut and bolt handy tools fix +⚙️ gear cog +🗜️ clamp tool +⚖️ balance scale law fairness weight +🦯 probing cane accessibility +🔗 link rings url +⛓️ chains lock arrest +🧰 toolbox tools diy fix maintainer mechanic +🧲 magnet attraction magnetic +⚗️ alembic distilling science experiment chemistry +🧪 test tube chemistry experiment lab science +🧫 petri dish bacteria biology culture lab +🧬 dna biologist genetics life +🔬 microscope laboratory experiment zoomin science study +🔭 telescope stars space zoom science astronomy +📡 satellite antenna communication future radio space +💉 syringe health hospital drugs blood medicine needle doctor nurse +🩸 drop of blood period hurt harm wound +💊 pill health medicine doctor pharmacy drug +🩹 adhesive bandage heal +🩺 stethoscope health +🚪 door house entry exit +🛏️ bed sleep rest +🛋️ couch and lamp read chill +🪑 chair sit furniture +🚽 toilet restroom wc washroom bathroom potty +🚿 shower clean water bathroom +🛁 bathtub clean shower bathroom +🪒 razor cut +🧴 lotion bottle moisturizer sunscreen +🧷 safety pin diaper +🧹 broom cleaning sweeping witch +🧺 basket laundry +🧻 roll of paper roll +🧼 soap bar bathing cleaning lather +🧽 sponge absorbing cleaning porous +🧯 fire extinguisher quench +🛒 shopping cart trolley +🚬 cigarette kills tobacco cigarette joint smoke +⚰️ coffin vampire dead die death rip graveyard cemetery casket funeral box +⚱️ funeral urn dead die death rip ashes +🗿 moai rock easter island moai +🏧 atm sign money sales cash blue-square payment bank +🚮 litter in bin sign blue-square sign human info +🚰 potable water blue-square liquid restroom cleaning faucet +♿ wheelchair symbol blue-square disabled accessibility +🚹 men s room toilet restroom wc blue-square gender male +🚺 women s room purple-square woman female toilet loo restroom gender +🚻 restroom blue-square toilet refresh wc gender +🚼 baby symbol orange-square child +🚾 water closet toilet restroom blue-square +🛂 passport control custom blue-square +🛃 customs passport border blue-square +🛄 baggage claim blue-square airport transport +🛅 left luggage blue-square travel +⚠️ warning exclamation wip alert error problem issue +🚸 children crossing school warning danger sign driving yellow-diamond +⛔ no entry limit security privacy bad denied stop circle +🚫 prohibited forbid stop limit denied disallow circle +🚳 no bicycles cyclist prohibited circle +🚭 no smoking cigarette blue-square smell smoke +🚯 no littering trash bin garbage circle +🚱 non potable water drink faucet tap circle +🚷 no pedestrians rules crossing walking circle +📵 no mobile phones iphone mute circle +🔞 no one under eighteen 18 drink pub night minor circle +☢️ radioactive nuclear danger +☣️ biohazard danger +⬆️ up arrow blue-square continue top direction +↗️ up right arrow blue-square point direction diagonal northeast +➡️ right arrow blue-square next +↘️ down right arrow blue-square direction diagonal southeast +⬇️ down arrow blue-square direction bottom +↙️ down left arrow blue-square direction diagonal southwest +⬅️ left arrow blue-square previous back +↖️ up left arrow blue-square point direction diagonal northwest +↕️ up down arrow blue-square direction way vertical +↔️ left right arrow shape direction horizontal sideways +↩️ right arrow curving left back return blue-square undo enter +↪️ left arrow curving right blue-square return rotate direction +⤴️ right arrow curving up blue-square direction top +⤵️ right arrow curving down blue-square direction bottom +🔃 clockwise vertical arrows sync cycle round repeat +🔄 counterclockwise arrows button blue-square sync cycle +🔙 back arrow arrow words return +🔚 end arrow words arrow +🔛 on arrow arrow words +🔜 soon arrow arrow words +🔝 top arrow words blue-square +🛐 place of worship religion church temple prayer +⚛️ atom symbol science physics chemistry +🕉️ om hinduism buddhism sikhism jainism +✡️ star of david judaism +☸️ wheel of dharma hinduism buddhism sikhism jainism +☯️ yin yang balance +✝️ latin cross christianity +☦️ orthodox cross suppedaneum religion +☪️ star and crescent islam +☮️ peace symbol hippie +🕎 menorah hanukkah candles jewish +🔯 dotted six pointed star purple-square religion jewish hexagram +♈ aries sign purple-square zodiac astrology +♉ taurus purple-square sign zodiac astrology +♊ gemini sign zodiac purple-square astrology +♋ cancer sign zodiac purple-square astrology +♌ leo sign purple-square zodiac astrology +♍ virgo sign zodiac purple-square astrology +♎ libra sign purple-square zodiac astrology +♏ scorpio sign zodiac purple-square astrology scorpio +♐ sagittarius sign zodiac purple-square astrology +♑ capricorn sign zodiac purple-square astrology +♒ aquarius sign purple-square zodiac astrology +♓ pisces purple-square sign zodiac astrology +⛎ ophiuchus sign purple-square constellation astrology +🔀 shuffle tracks button blue-square shuffle music random +🔁 repeat button loop record +🔂 repeat single button blue-square loop +▶️ play button blue-square right direction play +⏩ fast forward button blue-square play speed continue +⏭️ next track button forward next blue-square +⏯️ play or pause button blue-square play pause +◀️ reverse button blue-square left direction +⏪ fast reverse button play blue-square +⏮️ last track button backward +🔼 upwards button blue-square triangle direction point forward top +⏫ fast up button blue-square direction top +🔽 downwards button blue-square direction bottom +⏬ fast down button blue-square direction bottom +⏸️ pause button pause blue-square +⏹️ stop button blue-square +⏺️ record button blue-square +⏏️ eject button blue-square +🎦 cinema blue-square record film movie curtain stage theater +🔅 dim button sun afternoon warm summer +🔆 bright button sun light +📶 antenna bars blue-square reception phone internet connection wifi bluetooth bars +📳 vibration mode orange-square phone +📴 mobile phone off mute orange-square silence quiet +♀️ female sign woman women lady girl +♂️ male sign man boy men +⚕️ medical symbol health hospital +♾️ infinity forever +♻️ recycling symbol arrow environment garbage trash +⚜️ fleur de lis decorative scout +🔱 trident emblem weapon spear +📛 name badge fire forbid +🔰 japanese symbol for beginner badge shield +⭕ hollow red circle circle round +✅ check mark button green-square ok agree vote election answer tick +☑️ check box with check ok agree confirm black-square vote election yes tick +✔️ check mark ok nike answer yes tick +✖️ multiplication sign math calculation +❌ cross mark no delete remove cancel red +❎ cross mark button x green-square no deny +➕ plus sign math calculation addition more increase +➖ minus sign math calculation subtract less +➗ division sign divide math calculation +➰ curly loop scribble draw shape squiggle +➿ double curly loop tape cassette +〽️ part alternation mark graph presentation stats business economics bad +✳️ eight spoked asterisk star sparkle green-square +✴️ eight pointed star orange-square shape polygon +❇️ sparkle stars green-square awesome good fireworks +‼️ double exclamation mark exclamation surprise +⁉️ exclamation question mark wat punctuation surprise +❓ question mark doubt confused +❔ white question mark doubts gray huh confused +❕ white exclamation mark surprise punctuation gray wow warning +❗ exclamation mark heavy exclamation mark danger surprise punctuation wow warning +〰️ wavy dash draw line moustache mustache squiggle scribble +©️ copyright ip license circle law legal +®️ registered alphabet circle +™️ trade mark trademark brand law legal +#️⃣ keycap symbol blue-square twitter +*️⃣ keycap star keycap +0️⃣ keycap 0 0 numbers blue-square null +1️⃣ keycap 1 blue-square numbers 1 +2️⃣ keycap 2 numbers 2 prime blue-square +3️⃣ keycap 3 3 numbers prime blue-square +4️⃣ keycap 4 4 numbers blue-square +5️⃣ keycap 5 5 numbers blue-square prime +6️⃣ keycap 6 6 numbers blue-square +7️⃣ keycap 7 7 numbers blue-square prime +8️⃣ keycap 8 8 blue-square numbers +9️⃣ keycap 9 blue-square numbers 9 +🔟 keycap 10 numbers 10 blue-square +🔠 input latin uppercase alphabet words blue-square +🔡 input latin lowercase blue-square alphabet +🔢 input numbers numbers blue-square +🔣 input symbols blue-square music note ampersand percent glyphs characters +🔤 input latin letters blue-square alphabet +🅰️ a button red-square alphabet letter +🆎 ab button red-square alphabet +🅱️ b button red-square alphabet letter +🆑 cl button alphabet words red-square +🆒 cool button words blue-square +🆓 free button blue-square words +ℹ️ information blue-square alphabet letter +🆔 id button purple-square words +Ⓜ️ circled m alphabet blue-circle letter +🆕 new button blue-square words start +🆖 ng button blue-square words shape icon +🅾️ o button alphabet red-square letter +🆗 ok button good agree yes blue-square +🅿️ p button cars blue-square alphabet letter +🆘 sos button help red-square words emergency 911 +🆙 up button blue-square above high +🆚 vs button words orange-square +🈁 japanese here button blue-square here katakana japanese destination +🈂️ japanese service charge button japanese blue-square katakana +🈷️ japanese monthly amount button chinese month moon japanese orange-square kanji +🈶 japanese not free of charge button orange-square chinese have kanji +🈯 japanese reserved button chinese point green-square kanji +🉐 japanese bargain button chinese kanji obtain get circle +🈹 japanese discount button cut divide chinese kanji pink-square +🈚 japanese free of charge button nothing chinese kanji japanese orange-square +🈲 japanese prohibited button kanji japanese chinese forbidden limit restricted red-square +🉑 japanese acceptable button ok good chinese kanji agree yes orange-circle +🈸 japanese application button chinese japanese kanji orange-square +🈴 japanese passing grade button japanese chinese join kanji red-square +🈳 japanese vacancy button kanji japanese chinese empty sky blue-square +㊗️ japanese congratulations button chinese kanji japanese red-circle +㊙️ japanese secret button privacy chinese sshh kanji red-circle +🈺 japanese open for business button japanese opening hours orange-square +🈵 japanese no vacancy button full chinese japanese red-square kanji +🔴 red circle shape error danger +🟠 orange circle round +🟡 yellow circle round +🟢 green circle round +🔵 blue circle shape icon button +🟣 purple circle round +🟤 brown circle round +⚫ black circle shape button round +⚪ white circle shape round +🟥 red square +🟧 orange square +🟨 yellow square +🟩 green square +🟦 blue square +🟪 purple square +🟫 brown square +⬛ black large square shape icon button +⬜ white large square shape icon stone button +◼️ black medium square shape button icon +◻️ white medium square shape stone icon +◾ black medium small square icon shape button +◽ white medium small square shape stone icon button +▪️ black small square shape icon +▫️ white small square shape icon +🔶 large orange diamond shape jewel gem +🔷 large blue diamond shape jewel gem +🔸 small orange diamond shape jewel gem +🔹 small blue diamond shape jewel gem +🔺 red triangle pointed up shape direction up top +🔻 red triangle pointed down shape direction bottom +💠 diamond with a dot jewel blue gem crystal fancy +🔘 radio button input old music circle +🔳 white square button shape input +🔲 black square button shape input frame +🏁 chequered flag contest finishline race gokart +🚩 triangular flag mark milestone place +🎌 crossed flags japanese nation country border +🏴 black flag pirate +🏳️ white flag losing loser lost surrender give up fail +🏳️‍🌈 rainbow flag flag rainbow pride gay lgbt glbt queer homosexual lesbian bisexual transgender +🏴‍☠️ pirate flag skull crossbones flag banner +🇦🇨 flag ascension island +🇦🇩 flag andorra ad flag nation country banner andorra +🇦🇪 flag united arab emirates united arab emirates flag nation country banner united arab emirates +🇦🇫 flag afghanistan af flag nation country banner afghanistan +🇦🇬 flag antigua barbuda antigua barbuda flag nation country banner antigua barbuda +🇦🇮 flag anguilla ai flag nation country banner anguilla +🇦🇱 flag albania al flag nation country banner albania +🇦🇲 flag armenia am flag nation country banner armenia +🇦🇴 flag angola ao flag nation country banner angola +🇦🇶 flag antarctica aq flag nation country banner antarctica +🇦🇷 flag argentina ar flag nation country banner argentina +🇦🇸 flag american samoa american ws flag nation country banner american samoa +🇦🇹 flag austria at flag nation country banner austria +🇦🇺 flag australia au flag nation country banner australia +🇦🇼 flag aruba aw flag nation country banner aruba +🇦🇽 flag aland islands Åland islands flag nation country banner aland islands +🇦🇿 flag azerbaijan az flag nation country banner azerbaijan +🇧🇦 flag bosnia herzegovina bosnia herzegovina flag nation country banner bosnia herzegovina +🇧🇧 flag barbados bb flag nation country banner barbados +🇧🇩 flag bangladesh bd flag nation country banner bangladesh +🇧🇪 flag belgium be flag nation country banner belgium +🇧🇫 flag burkina faso burkina faso flag nation country banner burkina faso +🇧🇬 flag bulgaria bg flag nation country banner bulgaria +🇧🇭 flag bahrain bh flag nation country banner bahrain +🇧🇮 flag burundi bi flag nation country banner burundi +🇧🇯 flag benin bj flag nation country banner benin +🇧🇱 flag st barthelemy saint barthélemy flag nation country banner st barthelemy +🇧🇲 flag bermuda bm flag nation country banner bermuda +🇧🇳 flag brunei bn darussalam flag nation country banner brunei +🇧🇴 flag bolivia bo flag nation country banner bolivia +🇧🇶 flag caribbean netherlands bonaire flag nation country banner caribbean netherlands +🇧🇷 flag brazil br flag nation country banner brazil +🇧🇸 flag bahamas bs flag nation country banner bahamas +🇧🇹 flag bhutan bt flag nation country banner bhutan +🇧🇻 flag bouvet island norway +🇧🇼 flag botswana bw flag nation country banner botswana +🇧🇾 flag belarus by flag nation country banner belarus +🇧🇿 flag belize bz flag nation country banner belize +🇨🇦 flag canada ca flag nation country banner canada +🇨🇨 flag cocos islands cocos keeling islands flag nation country banner cocos islands +🇨🇩 flag congo kinshasa congo democratic republic flag nation country banner congo kinshasa +🇨🇫 flag central african republic central african republic flag nation country banner central african republic +🇨🇬 flag congo brazzaville congo flag nation country banner congo brazzaville +🇨🇭 flag switzerland ch flag nation country banner switzerland +🇨🇮 flag cote d ivoire ivory coast flag nation country banner cote d ivoire +🇨🇰 flag cook islands cook islands flag nation country banner cook islands +🇨🇱 flag chile flag nation country banner chile +🇨🇲 flag cameroon cm flag nation country banner cameroon +🇨🇳 flag china china chinese prc flag country nation banner china +🇨🇴 flag colombia co flag nation country banner colombia +🇨🇵 flag clipperton island +🇨🇷 flag costa rica costa rica flag nation country banner costa rica +🇨🇺 flag cuba cu flag nation country banner cuba +🇨🇻 flag cape verde cabo verde flag nation country banner cape verde +🇨🇼 flag curacao curaçao flag nation country banner curacao +🇨🇽 flag christmas island christmas island flag nation country banner christmas island +🇨🇾 flag cyprus cy flag nation country banner cyprus +🇨🇿 flag czechia cz flag nation country banner czechia +🇩🇪 flag germany german nation flag country banner germany +🇩🇬 flag diego garcia +🇩🇯 flag djibouti dj flag nation country banner djibouti +🇩🇰 flag denmark dk flag nation country banner denmark +🇩🇲 flag dominica dm flag nation country banner dominica +🇩🇴 flag dominican republic dominican republic flag nation country banner dominican republic +🇩🇿 flag algeria dz flag nation country banner algeria +🇪🇦 flag ceuta melilla +🇪🇨 flag ecuador ec flag nation country banner ecuador +🇪🇪 flag estonia ee flag nation country banner estonia +🇪🇬 flag egypt eg flag nation country banner egypt +🇪🇭 flag western sahara western sahara flag nation country banner western sahara +🇪🇷 flag eritrea er flag nation country banner eritrea +🇪🇸 flag spain spain flag nation country banner spain +🇪🇹 flag ethiopia et flag nation country banner ethiopia +🇪🇺 flag european union european union flag banner +🇫🇮 flag finland fi flag nation country banner finland +🇫🇯 flag fiji fj flag nation country banner fiji +🇫🇰 flag falkland islands falkland islands malvinas flag nation country banner falkland islands +🇫🇲 flag micronesia micronesia federated states flag nation country banner micronesia +🇫🇴 flag faroe islands faroe islands flag nation country banner faroe islands +🇫🇷 flag france banner flag nation france french country france +🇬🇦 flag gabon ga flag nation country banner gabon +🇬🇧 flag united kingdom united kingdom great britain northern ireland flag nation country banner british UK english england union jack united kingdom +🇬🇩 flag grenada gd flag nation country banner grenada +🇬🇪 flag georgia ge flag nation country banner georgia +🇬🇫 flag french guiana french guiana flag nation country banner french guiana +🇬🇬 flag guernsey gg flag nation country banner guernsey +🇬🇭 flag ghana gh flag nation country banner ghana +🇬🇮 flag gibraltar gi flag nation country banner gibraltar +🇬🇱 flag greenland gl flag nation country banner greenland +🇬🇲 flag gambia gm flag nation country banner gambia +🇬🇳 flag guinea gn flag nation country banner guinea +🇬🇵 flag guadeloupe gp flag nation country banner guadeloupe +🇬🇶 flag equatorial guinea equatorial gn flag nation country banner equatorial guinea +🇬🇷 flag greece gr flag nation country banner greece +🇬🇸 flag south georgia south sandwich islands south georgia sandwich islands flag nation country banner south georgia south sandwich islands +🇬🇹 flag guatemala gt flag nation country banner guatemala +🇬🇺 flag guam gu flag nation country banner guam +🇬🇼 flag guinea bissau gw bissau flag nation country banner guinea bissau +🇬🇾 flag guyana gy flag nation country banner guyana +🇭🇰 flag hong kong sar china hong kong flag nation country banner hong kong sar china +🇭🇲 flag heard mcdonald islands +🇭🇳 flag honduras hn flag nation country banner honduras +🇭🇷 flag croatia hr flag nation country banner croatia +🇭🇹 flag haiti ht flag nation country banner haiti +🇭🇺 flag hungary hu flag nation country banner hungary +🇮🇨 flag canary islands canary islands flag nation country banner canary islands +🇮🇩 flag indonesia flag nation country banner indonesia +🇮🇪 flag ireland ie flag nation country banner ireland +🇮🇱 flag israel il flag nation country banner israel +🇮🇲 flag isle of man isle man flag nation country banner isle of man +🇮🇳 flag india in flag nation country banner india +🇮🇴 flag british indian ocean territory british indian ocean territory flag nation country banner british indian ocean territory +🇮🇶 flag iraq iq flag nation country banner iraq +🇮🇷 flag iran iran islamic republic flag nation country banner iran +🇮🇸 flag iceland is flag nation country banner iceland +🇮🇹 flag italy italy flag nation country banner italy +🇯🇪 flag jersey je flag nation country banner jersey +🇯🇲 flag jamaica jm flag nation country banner jamaica +🇯🇴 flag jordan jo flag nation country banner jordan +🇯🇵 flag japan japanese nation flag country banner japan +🇰🇪 flag kenya ke flag nation country banner kenya +🇰🇬 flag kyrgyzstan kg flag nation country banner kyrgyzstan +🇰🇭 flag cambodia kh flag nation country banner cambodia +🇰🇮 flag kiribati ki flag nation country banner kiribati +🇰🇲 flag comoros km flag nation country banner comoros +🇰🇳 flag st kitts nevis saint kitts nevis flag nation country banner st kitts nevis +🇰🇵 flag north korea north korea nation flag country banner north korea +🇰🇷 flag south korea south korea nation flag country banner south korea +🇰🇼 flag kuwait kw flag nation country banner kuwait +🇰🇾 flag cayman islands cayman islands flag nation country banner cayman islands +🇰🇿 flag kazakhstan kz flag nation country banner kazakhstan +🇱🇦 flag laos lao democratic republic flag nation country banner laos +🇱🇧 flag lebanon lb flag nation country banner lebanon +🇱🇨 flag st lucia saint lucia flag nation country banner st lucia +🇱🇮 flag liechtenstein li flag nation country banner liechtenstein +🇱🇰 flag sri lanka sri lanka flag nation country banner sri lanka +🇱🇷 flag liberia lr flag nation country banner liberia +🇱🇸 flag lesotho ls flag nation country banner lesotho +🇱🇹 flag lithuania lt flag nation country banner lithuania +🇱🇺 flag luxembourg lu flag nation country banner luxembourg +🇱🇻 flag latvia lv flag nation country banner latvia +🇱🇾 flag libya ly flag nation country banner libya +🇲🇦 flag morocco ma flag nation country banner morocco +🇲🇨 flag monaco mc flag nation country banner monaco +🇲🇩 flag moldova moldova republic flag nation country banner moldova +🇲🇪 flag montenegro me flag nation country banner montenegro +🇲🇫 flag st martin +🇲🇬 flag madagascar mg flag nation country banner madagascar +🇲🇭 flag marshall islands marshall islands flag nation country banner marshall islands +🇲🇰 flag north macedonia macedonia flag nation country banner north macedonia +🇲🇱 flag mali ml flag nation country banner mali +🇲🇲 flag myanmar mm flag nation country banner myanmar +🇲🇳 flag mongolia mn flag nation country banner mongolia +🇲🇴 flag macao sar china macao flag nation country banner macao sar china +🇲🇵 flag northern mariana islands northern mariana islands flag nation country banner northern mariana islands +🇲🇶 flag martinique mq flag nation country banner martinique +🇲🇷 flag mauritania mr flag nation country banner mauritania +🇲🇸 flag montserrat ms flag nation country banner montserrat +🇲🇹 flag malta mt flag nation country banner malta +🇲🇺 flag mauritius mu flag nation country banner mauritius +🇲🇻 flag maldives mv flag nation country banner maldives +🇲🇼 flag malawi mw flag nation country banner malawi +🇲🇽 flag mexico mx flag nation country banner mexico +🇲🇾 flag malaysia my flag nation country banner malaysia +🇲🇿 flag mozambique mz flag nation country banner mozambique +🇳🇦 flag namibia na flag nation country banner namibia +🇳🇨 flag new caledonia new caledonia flag nation country banner new caledonia +🇳🇪 flag niger ne flag nation country banner niger +🇳🇫 flag norfolk island norfolk island flag nation country banner norfolk island +🇳🇬 flag nigeria flag nation country banner nigeria +🇳🇮 flag nicaragua ni flag nation country banner nicaragua +🇳🇱 flag netherlands nl flag nation country banner netherlands +🇳🇴 flag norway no flag nation country banner norway +🇳🇵 flag nepal np flag nation country banner nepal +🇳🇷 flag nauru nr flag nation country banner nauru +🇳🇺 flag niue nu flag nation country banner niue +🇳🇿 flag new zealand new zealand flag nation country banner new zealand +🇴🇲 flag oman om symbol flag nation country banner oman +🇵🇦 flag panama pa flag nation country banner panama +🇵🇪 flag peru pe flag nation country banner peru +🇵🇫 flag french polynesia french polynesia flag nation country banner french polynesia +🇵🇬 flag papua new guinea papua new guinea flag nation country banner papua new guinea +🇵🇭 flag philippines ph flag nation country banner philippines +🇵🇰 flag pakistan pk flag nation country banner pakistan +🇵🇱 flag poland pl flag nation country banner poland +🇵🇲 flag st pierre miquelon saint pierre miquelon flag nation country banner st pierre miquelon +🇵🇳 flag pitcairn islands pitcairn flag nation country banner pitcairn islands +🇵🇷 flag puerto rico puerto rico flag nation country banner puerto rico +🇵🇸 flag palestinian territories palestine palestinian territories flag nation country banner palestinian territories +🇵🇹 flag portugal pt flag nation country banner portugal +🇵🇼 flag palau pw flag nation country banner palau +🇵🇾 flag paraguay py flag nation country banner paraguay +🇶🇦 flag qatar qa flag nation country banner qatar +🇷🇪 flag reunion réunion flag nation country banner reunion +🇷🇴 flag romania ro flag nation country banner romania +🇷🇸 flag serbia rs flag nation country banner serbia +🇷🇺 flag russia russian federation flag nation country banner russia +🇷🇼 flag rwanda rw flag nation country banner rwanda +🇸🇦 flag saudi arabia flag nation country banner saudi arabia +🇸🇧 flag solomon islands solomon islands flag nation country banner solomon islands +🇸🇨 flag seychelles sc flag nation country banner seychelles +🇸🇩 flag sudan sd flag nation country banner sudan +🇸🇪 flag sweden se flag nation country banner sweden +🇸🇬 flag singapore sg flag nation country banner singapore +🇸🇭 flag st helena saint helena ascension tristan cunha flag nation country banner st helena +🇸🇮 flag slovenia si flag nation country banner slovenia +🇸🇯 flag svalbard jan mayen +🇸🇰 flag slovakia sk flag nation country banner slovakia +🇸🇱 flag sierra leone sierra leone flag nation country banner sierra leone +🇸🇲 flag san marino san marino flag nation country banner san marino +🇸🇳 flag senegal sn flag nation country banner senegal +🇸🇴 flag somalia so flag nation country banner somalia +🇸🇷 flag suriname sr flag nation country banner suriname +🇸🇸 flag south sudan south sd flag nation country banner south sudan +🇸🇹 flag sao tome principe sao tome principe flag nation country banner sao tome principe +🇸🇻 flag el salvador el salvador flag nation country banner el salvador +🇸🇽 flag sint maarten sint maarten dutch flag nation country banner sint maarten +🇸🇾 flag syria syrian arab republic flag nation country banner syria +🇸🇿 flag eswatini sz flag nation country banner eswatini +🇹🇦 flag tristan da cunha +🇹🇨 flag turks caicos islands turks caicos islands flag nation country banner turks caicos islands +🇹🇩 flag chad td flag nation country banner chad +🇹🇫 flag french southern territories french southern territories flag nation country banner french southern territories +🇹🇬 flag togo tg flag nation country banner togo +🇹🇭 flag thailand th flag nation country banner thailand +🇹🇯 flag tajikistan tj flag nation country banner tajikistan +🇹🇰 flag tokelau tk flag nation country banner tokelau +🇹🇱 flag timor leste timor leste flag nation country banner timor leste +🇹🇲 flag turkmenistan flag nation country banner turkmenistan +🇹🇳 flag tunisia tn flag nation country banner tunisia +🇹🇴 flag tonga to flag nation country banner tonga +🇹🇷 flag turkey turkey flag nation country banner turkey +🇹🇹 flag trinidad tobago trinidad tobago flag nation country banner trinidad tobago +🇹🇻 flag tuvalu flag nation country banner tuvalu +🇹🇼 flag taiwan tw flag nation country banner taiwan +🇹🇿 flag tanzania tanzania united republic flag nation country banner tanzania +🇺🇦 flag ukraine ua flag nation country banner ukraine +🇺🇬 flag uganda ug flag nation country banner uganda +🇺🇲 flag u s outlying islands +🇺🇳 flag united nations un flag banner +🇺🇸 flag united states united states america flag nation country banner united states +🇺🇾 flag uruguay uy flag nation country banner uruguay +🇺🇿 flag uzbekistan uz flag nation country banner uzbekistan +🇻🇦 flag vatican city vatican city flag nation country banner vatican city +🇻🇨 flag st vincent grenadines saint vincent grenadines flag nation country banner st vincent grenadines +🇻🇪 flag venezuela ve bolivarian republic flag nation country banner venezuela +🇻🇬 flag british virgin islands british virgin islands bvi flag nation country banner british virgin islands +🇻🇮 flag u s virgin islands virgin islands us flag nation country banner u s virgin islands +🇻🇳 flag vietnam viet nam flag nation country banner vietnam +🇻🇺 flag vanuatu vu flag nation country banner vanuatu +🇼🇫 flag wallis futuna wallis futuna flag nation country banner wallis futuna +🇼🇸 flag samoa ws flag nation country banner samoa +🇽🇰 flag kosovo xk flag nation country banner kosovo +🇾🇪 flag yemen ye flag nation country banner yemen +🇾🇹 flag mayotte yt flag nation country banner mayotte +🇿🇦 flag south africa south africa flag nation country banner south africa +🇿🇲 flag zambia zm flag nation country banner zambia +🇿🇼 flag zimbabwe zw flag nation country banner zimbabwe +🏴󠁧󠁢󠁥󠁮󠁧󠁿 flag england flag english +🏴󠁧󠁢󠁳󠁣󠁴󠁿 flag scotland flag scottish +🏴󠁧󠁢󠁷󠁬󠁳󠁿 flag wales flag welsh +🥲 smiling face with tear sad cry pretend +🥸 disguised face pretent brows glasses moustache +🤌 pinched fingers size tiny small +🫀 anatomical heart health heartbeat +🫁 lungs breathe +🥷 ninja ninjutsu skills japanese +🤵‍♂️ man in tuxedo formal fashion +🤵‍♀️ woman in tuxedo formal fashion +👰‍♂️ man with veil wedding marriage +👰‍♀️ woman with veil wedding marriage +👩‍🍼 woman feeding baby birth food +👨‍🍼 man feeding baby birth food +🧑‍🍼 person feeding baby birth food +🧑‍🎄 mx claus christmas +🫂 people hugging care +🐈‍⬛ black cat superstition luck +🦬 bison ox +🦣 mammoth elephant tusks +🦫 beaver animal rodent +🐻‍❄️ polar bear animal arctic +🦤 dodo animal bird +🪶 feather bird fly +🦭 seal animal creature sea +🪲 beetle insect +🪳 cockroach insect pests +🪰 fly insect +🪱 worm animal +🪴 potted plant greenery house +🫐 blueberries fruit +🫒 olive fruit +🫑 bell pepper fruit plant +🫓 flatbread flour food +🫔 tamale food masa +🫕 fondue cheese pot food +🫖 teapot drink hot +🧋 bubble tea taiwan boba milk tea straw +🪨 rock stone +🪵 wood nature timber trunk +🛖 hut house structure +🛻 pickup truck car transportation +🛼 roller skate footwear sports +🪄 magic wand supernature power +🪅 pinata mexico candy celebration +🪆 nesting dolls matryoshka toy +🪡 sewing needle stitches +🪢 knot rope scout +🩴 thong sandal footwear summer +🪖 military helmet army protection +🪗 accordion music +🪘 long drum music +🪙 coin money currency +🪃 boomerang weapon +🪚 carpentry saw cut chop +🪛 screwdriver tools +🪝 hook tools +🪜 ladder tools +🛗 elevator lift +🪞 mirror reflection +🪟 window scenery +🪠 plunger toilet +🪤 mouse trap cheese +🪣 bucket water container +🪥 toothbrush hygiene dental +🪦 headstone death rip grave +🪧 placard announcement +⚧️ transgender symbol lgbtq +🏳️‍⚧️ transgender flag lgbtq +😶‍🌫️ face in clouds shower steam dream +😮‍💨 face exhaling relieve relief tired sigh +😵‍💫 face with spiral eyes sick ill confused nauseous nausea +❤️‍🔥 heart on fire passionate enthusiastic +❤️‍🩹 mending heart broken heart bandage wounded +🧔‍♂️ man beard facial hair +🧔‍♀️ woman beard facial hair +🫠 melting face hot heat +🫢 face with open eyes and hand over mouth silence secret shock surprise +🫣 face with peeking eye scared frightening embarrassing +🫡 saluting face respect salute +🫥 dotted line face invisible lonely isolation depression +🫤 face with diagonal mouth skeptic confuse frustrated indifferent +🥹 face holding back tears touched gratitude +🫱 rightwards hand palm offer +🫲 leftwards hand palm offer +🫳 palm down hand palm drop +🫴 palm up hand lift offer demand +🫰 hand with index finger and thumb crossed heart love money expensive +🫵 index pointing at the viewer you recruit +🫶 heart hands love appreciation support +🫦 biting lip flirt sexy pain worry +🫅 person with crown royalty power +🫃 pregnant man baby belly +🫄 pregnant person baby belly +🧌 troll mystical monster +🪸 coral ocean sea reef +🪷 lotus flower calm meditation +🪹 empty nest bird +🪺 nest with eggs bird +🫘 beans food +🫗 pouring liquid cup water +🫙 jar container sauce +🛝 playground slide fun park +🛞 wheel car transport +🛟 ring buoy life saver life preserver +🪬 hamsa religion protection +🪩 mirror ball disco dance party +🪫 low battery drained dead +🩼 crutch accessibility assist +🩻 x-ray skeleton medicine +🫧 bubbles soap fun carbonation sparkling +🪪 identification card document +🟰 heavy equals sign math From c1eebe1cd95ecdc7733d293e3bf89cc966b098a1 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 16:26:39 -0400 Subject: [PATCH 088/110] Wifi Menu Slightly modified from https://github.com/fourstepper/wofi-wifi-menu --- wofi/wofi-wifi-menu.sh | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100755 wofi/wofi-wifi-menu.sh diff --git a/wofi/wofi-wifi-menu.sh b/wofi/wofi-wifi-menu.sh new file mode 100755 index 0000000..79e2493 --- /dev/null +++ b/wofi/wofi-wifi-menu.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +# Starts a scan of available broadcasting SSIDs +# nmcli dev wifi rescan + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +FIELDS=SSID,SECURITY +POSITION=0 +YOFF=0 +XOFF=0 + +if [ -r "$DIR/config" ]; then + source "$DIR/config" +elif [ -r "$HOME/.dotfiles/wofi/wifi" ]; then + source "$HOME/.dotfiles/wofi/wifi" +else + echo "WARNING: config file not found! Using default values." +fi + +LIST=$(nmcli --fields "$FIELDS" device wifi list | sed '/^--/d') +# For some reason wofi always approximates character width 2 short... hmmm +RWIDTH=$(($(echo "$LIST" | head -n 1 | awk '{print length($0); }')*10)) +# Dynamically change the height of the wofi menu +LINENUM=$(echo "$LIST" | wc -l) +# Gives a list of known connections so we can parse it later +KNOWNCON=$(nmcli connection show) +# Really janky way of telling if there is currently a connection +CONSTATE=$(nmcli -fields WIFI g) + +CURRSSID=$(LANGUAGE=C nmcli -t -f active,ssid dev wifi | awk -F: '$1 ~ /^yes/ {print $2}') + +if [[ ! -z $CURRSSID ]]; then + HIGHLINE=$(echo "$(echo "$LIST" | awk -F "[ ]{2,}" '{print $1}' | grep -Fxn -m 1 "$CURRSSID" | awk -F ":" '{print $1}') + 1" | bc ) +fi + +# HOPEFULLY you won't need this as often as I do +# If there are more than 8 SSIDs, the menu will still only have 8 lines +if [ "$LINENUM" -gt 8 ] && [[ "$CONSTATE" =~ "enabled" ]]; then + LINENUM=8 +elif [[ "$CONSTATE" =~ "disabled" ]]; then + LINENUM=1 +fi + + +if [[ "$CONSTATE" =~ "enabled" ]]; then + TOGGLE="toggle off" +elif [[ "$CONSTATE" =~ "disabled" ]]; then + TOGGLE="toggle on" +fi + + +CHENTRY=$(echo -e "$TOGGLE\nmanual\n$LIST" | uniq -u | wofi -s $HOME/.dotfiles/wofi/style.css -i -d --prompt "Wi-Fi SSID: " --lines "$LINENUM" --location "$POSITION" --yoffset "$YOFF" --xoffset "$XOFF" --width $RWIDTH) +if [[ $CHENTRY == "" ]]; then + exit +fi +#echo "$CHENTRY" +CHSSID=$(echo "$CHENTRY" | sed 's/\s\{2,\}/\|/g' | awk -F "|" '{print $1}') +#echo "$CHSSID" + +# If the user inputs "manual" as their SSID in the start window, it will bring them to this screen +if [ "$CHENTRY" = "manual" ] ; then + # Manual entry of the SSID and password (if appplicable) + MSSID=$(echo "enter the SSID of the network (SSID,password)" | wofi -s $HOME/.dotfiles/wofi/style.css -d "Manual Entry: " --lines 1) + # Separating the password from the entered string + MPASS=$(echo "$MSSID" | awk -F "," '{print $2}') + + #echo "$MSSID" + #echo "$MPASS" + + # If the user entered a manual password, then use the password nmcli command + if [ "$MPASS" = "" ]; then + nmcli dev wifi con "$MSSID" + else + nmcli dev wifi con "$MSSID" password "$MPASS" + fi + +elif [ "$CHENTRY" = "toggle on" ]; then + nmcli radio wifi on + +elif [ "$CHENTRY" = "toggle off" ]; then + nmcli radio wifi off + +else + + # If the connection is already in use, then this will still be able to get the SSID + if [ "$CHSSID" = "*" ]; then + CHSSID=$(echo "$CHENTRY" | sed 's/\s\{2,\}/\|/g' | awk -F "|" '{print $3}') + fi + + # Parses the list of preconfigured connections to see if it already contains the chosen SSID. This speeds up the connection process + if [[ $(echo "$KNOWNCON" | grep "$CHSSID") = "$CHSSID" ]]; then + nmcli con up "$CHSSID" + else + if [[ "$CHENTRY" =~ "WPA2" ]] || [[ "$CHENTRY" =~ "WEP" ]]; then + WIFIPASS=$(echo "if connection is stored, hit enter" | wofi -s $HOME/.dotfiles/wofi/style.css -P -d --prompt "password" --lines 1 --location "$POSITION" --yoffset "$YOFF" --xoffset "$XOFF" --width $RWIDTH) + fi + nmcli dev wifi con "$CHSSID" password "$WIFIPASS" + fi + +fi From 67e4eb1d8a5333a7814702b4114e34ff69db63f5 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 17:00:11 -0400 Subject: [PATCH 089/110] Rename and give attribution --- wofi/{wofi-emoji => wofi-emoji.sh} | 3 +++ 1 file changed, 3 insertions(+) rename wofi/{wofi-emoji => wofi-emoji.sh} (99%) diff --git a/wofi/wofi-emoji b/wofi/wofi-emoji.sh similarity index 99% rename from wofi/wofi-emoji rename to wofi/wofi-emoji.sh index 0248dc6..8f45995 100755 --- a/wofi/wofi-emoji +++ b/wofi/wofi-emoji.sh @@ -1,4 +1,7 @@ #!/bin/bash + +# Modified from: https://github.com/dln/wofi-emoji + sed '1,/^### DATA ###$/d' $0 | wofi --show dmenu -i -s $HOME/.dotfiles/wofi/style.css | cut -d ' ' -f 1 | tr -d '\n' | wl-copy --primary exit ### DATA ### From cf703f1696bf5349759324e57c9d868fbf15aa20 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 17:02:46 -0400 Subject: [PATCH 090/110] Use sidebar config --- wofi/wofi-drun.sh | 10 ++++++++++ wofi/wofi-emoji.sh | 2 +- wofi/wofi-wifi-menu.sh | 6 +++--- 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100755 wofi/wofi-drun.sh diff --git a/wofi/wofi-drun.sh b/wofi/wofi-drun.sh new file mode 100755 index 0000000..6d36035 --- /dev/null +++ b/wofi/wofi-drun.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +WOFI=$(pgrep -xc wofi | cut -b 1) +echo $WOFI + +if [[ "$WOFI" -eq "0" ]]; then + wofi -s /home/jpm/.dotfiles/wofi/style.css -c $HOME/.dotfiles/wofi/sidebar --show drun -I +else + killall wofi 2&>1 /dev/null +fi diff --git a/wofi/wofi-emoji.sh b/wofi/wofi-emoji.sh index 8f45995..8487e6d 100755 --- a/wofi/wofi-emoji.sh +++ b/wofi/wofi-emoji.sh @@ -2,7 +2,7 @@ # Modified from: https://github.com/dln/wofi-emoji -sed '1,/^### DATA ###$/d' $0 | wofi --show dmenu -i -s $HOME/.dotfiles/wofi/style.css | cut -d ' ' -f 1 | tr -d '\n' | wl-copy --primary +sed '1,/^### DATA ###$/d' $0 | wofi --show dmenu -i -c $HOME/.dotfiles/wofi/sidebar -s $HOME/.dotfiles/wofi/style.css | cut -d ' ' -f 1 | tr -d '\n' | wl-copy --primary exit ### DATA ### 😀 grinning face face smile happy joy :D grin diff --git a/wofi/wofi-wifi-menu.sh b/wofi/wofi-wifi-menu.sh index 79e2493..f269aa1 100755 --- a/wofi/wofi-wifi-menu.sh +++ b/wofi/wofi-wifi-menu.sh @@ -50,7 +50,7 @@ elif [[ "$CONSTATE" =~ "disabled" ]]; then fi -CHENTRY=$(echo -e "$TOGGLE\nmanual\n$LIST" | uniq -u | wofi -s $HOME/.dotfiles/wofi/style.css -i -d --prompt "Wi-Fi SSID: " --lines "$LINENUM" --location "$POSITION" --yoffset "$YOFF" --xoffset "$XOFF" --width $RWIDTH) +CHENTRY=$(echo -e "$TOGGLE\nmanual\n$LIST" | uniq -u | wofi -s $HOME/.dotfiles/wofi/style.css -i -d --prompt "Wi-Fi SSID: " -c $HOME/.dotfiles/wofi/sidebar) if [[ $CHENTRY == "" ]]; then exit fi @@ -61,7 +61,7 @@ CHSSID=$(echo "$CHENTRY" | sed 's/\s\{2,\}/\|/g' | awk -F "|" '{print $1}') # If the user inputs "manual" as their SSID in the start window, it will bring them to this screen if [ "$CHENTRY" = "manual" ] ; then # Manual entry of the SSID and password (if appplicable) - MSSID=$(echo "enter the SSID of the network (SSID,password)" | wofi -s $HOME/.dotfiles/wofi/style.css -d "Manual Entry: " --lines 1) + MSSID=$(echo "enter the SSID of the network (SSID,password)" | wofi -s $HOME/.dotfiles/wofi/style.css -d "Manual Entry: " -c $HOME/.dotfiles/wofi/sidebar) # Separating the password from the entered string MPASS=$(echo "$MSSID" | awk -F "," '{print $2}') @@ -93,7 +93,7 @@ else nmcli con up "$CHSSID" else if [[ "$CHENTRY" =~ "WPA2" ]] || [[ "$CHENTRY" =~ "WEP" ]]; then - WIFIPASS=$(echo "if connection is stored, hit enter" | wofi -s $HOME/.dotfiles/wofi/style.css -P -d --prompt "password" --lines 1 --location "$POSITION" --yoffset "$YOFF" --xoffset "$XOFF" --width $RWIDTH) + WIFIPASS=$(echo "if connection is stored, hit enter" | wofi -s $HOME/.dotfiles/wofi/style.css -P -d --prompt "password" -c $HOME/.dotfiles/wofi/sidebar) fi nmcli dev wifi con "$CHSSID" password "$WIFIPASS" fi From 7a5f625d177074bfb2e10e3109f6027382c8e968 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 17:03:01 -0400 Subject: [PATCH 091/110] attribution --- wofi/wofi-wifi-menu.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wofi/wofi-wifi-menu.sh b/wofi/wofi-wifi-menu.sh index f269aa1..b830f29 100755 --- a/wofi/wofi-wifi-menu.sh +++ b/wofi/wofi-wifi-menu.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +# Modified from: https://github.com/fourstepper/wofi-wifi-menu + # Starts a scan of available broadcasting SSIDs # nmcli dev wifi rescan From 6b53d53196dd8951c2ab205f6a1f8931657d3c80 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Sat, 17 Sep 2022 17:03:16 -0400 Subject: [PATCH 092/110] Clean up unnecessary vars --- wofi/wofi-wifi-menu.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/wofi/wofi-wifi-menu.sh b/wofi/wofi-wifi-menu.sh index b830f29..0838c4b 100755 --- a/wofi/wofi-wifi-menu.sh +++ b/wofi/wofi-wifi-menu.sh @@ -8,9 +8,6 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" FIELDS=SSID,SECURITY -POSITION=0 -YOFF=0 -XOFF=0 if [ -r "$DIR/config" ]; then source "$DIR/config" From 8bff2f7147e7ac78951a85e91960bab6fcc42917 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 22 Sep 2022 13:48:43 -0400 Subject: [PATCH 093/110] Update wofi-alt-tab.sh --- wofi/wofi-alt-tab.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wofi/wofi-alt-tab.sh b/wofi/wofi-alt-tab.sh index d087523..c7c59bb 100755 --- a/wofi/wofi-alt-tab.sh +++ b/wofi/wofi-alt-tab.sh @@ -5,7 +5,8 @@ swaymsg -t get_tree | grep -v '__i3_scratch' | sed -e 's/\([^\-]\)\- *[^\-]*$/\1/' | sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | - wofi -I --show dmenu | { - read -r id name - swaymsg "[con_id=$id]" focus - } + wofi -I -s /home/jpm/.dotfiles/wofi/style.css -c \ + $HOME/.dotfiles/wofi/sidebar --show dmenu | { + read -r id name + swaymsg "[con_id=$id]" focus + } From bc61b23883dd9c4abd8e164d29aa413e0a57f75c Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 22 Sep 2022 14:32:09 -0400 Subject: [PATCH 094/110] Script to rotate wallpaper --- sway/rotate-wallpaper.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 sway/rotate-wallpaper.sh diff --git a/sway/rotate-wallpaper.sh b/sway/rotate-wallpaper.sh new file mode 100755 index 0000000..4f3cb39 --- /dev/null +++ b/sway/rotate-wallpaper.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +PID=`cat /tmp/$USER-wallpaper.pid` + +if [ $PID ]; then + kill -SIGUSR1 $PID +else + systemctl --user restart wallpapers.service +fi From fa007b60ef1b5a8f3c7a6157f1bd2913dff32515 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Thu, 22 Sep 2022 14:32:39 -0400 Subject: [PATCH 095/110] Fix file path of cropped image --- sway/wallpaper.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sway/wallpaper.pl b/sway/wallpaper.pl index 5aabc79..a342327 100755 --- a/sway/wallpaper.pl +++ b/sway/wallpaper.pl @@ -226,7 +226,7 @@ sub crop my $oh = shift; my $cropped = $image; - $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$1-cropped.$2#; + $cropped =~ s#^.*/([^/]*)\.([^\.]+)$#$self->{'path'}$1-cropped.$2#; #$image = "/tmp/Pharma-out.png.jpg"; use Image::Magick; @@ -355,9 +355,9 @@ sub run } $self->set_background($target,$cropped); if ($self->{crop}) { - $self->do_log('LOG_DEBUG', "Deleting $cropped"); # Give swaybg a second, otherwise the file will be missing before it ends - sleep(2); + sleep(1); + $self->do_log('LOG_DEBUG', "Deleting $cropped"); unlink($cropped) || $self->do_log("LOG_WARNING", "Failed to delete $cropped after setting: $!"); } } else { From 1cc843e6eb7ea2799ee69c1f3a3295de49d20110 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 17:37:09 -0400 Subject: [PATCH 096/110] Generic power-menu.sh script for rofi/wofi depending on WM --- rofi/rofi-power-menu.sh => sway/power-menu.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) rename rofi/rofi-power-menu.sh => sway/power-menu.sh (65%) diff --git a/rofi/rofi-power-menu.sh b/sway/power-menu.sh similarity index 65% rename from rofi/rofi-power-menu.sh rename to sway/power-menu.sh index 9676a57..7114853 100755 --- a/rofi/rofi-power-menu.sh +++ b/sway/power-menu.sh @@ -10,12 +10,13 @@ else fi if [[ $WM == 'i3' ]]; then - res=$(printf "🔒 Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) + res=$(printf "⚿ Lock|↩ Logout|↻ Reload i3|↹ Restart i3|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -columns 1 -rows 7 -width 32 -l 1 -theme /home/jpm/.config/rofi/sidebar.rasi -hide-scrollbar -eh 1 -location 0 -padding 12 -opacity 100 -auto-select -no-fullscreen) else - res=$(echo "🔒 Lock|🖵 Toggle Displays|⚿ Yubico Authenticator|↻ Reload Sway|↻ Reload Waybar|↩ Logout|↯ Hibernate|🡙 Reboot|⏻ Shutdown" | rofi -sep "|" -dmenu -i -p 'Power: ' "" -theme /home/jpm/.config/rofi/sidebar.rasi -no-lazy-grab -auto-select -no-fullscreen) + res=$(printf "⚿ Lock\n🖵 Toggle Displays\n⚿ Yubico Authenticator\n↻ Reload Sway\n↻ Reload Waybar\n↩ Logout\n↯ Hibernate\n🡙 Reboot\n⏻ Shutdown" | wofi -I -s $HOME/.dotfiles/wofi/style.css -c $HOME/.dotfiles/wofi/sidebar --show dmenu + ) fi -if [ "$res" == "🔒 Lock" ]; then +if [ "$res" == "⚿ Lock" ]; then ${WM}lock -c 000000 elif [ "$res" == "↩ Logout" ]; then # Prevent auto-login From 5cfbde8fdc473a54bae19ab12bb11a4801bfacf4 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:03:41 -0400 Subject: [PATCH 097/110] Bar argument in error output --- waybar/waybar-debian.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waybar/waybar-debian.sh b/waybar/waybar-debian.sh index b32fef3..c76ec86 100755 --- a/waybar/waybar-debian.sh +++ b/waybar/waybar-debian.sh @@ -32,5 +32,5 @@ elif [ "$1" == 'update' ]; then let COUNT-- echo $COUNT > /home/jpm/.spool/apt-upgradeable else - echo "Missing argument: update, upgrade" + echo "Missing argument: update, upgrade, bar" fi From 4c35268b8fa9c6672b2503e148c4d49955c761c3 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:07:06 -0400 Subject: [PATCH 098/110] More robust gammastep applet --- waybar/waybar-gammastep.sh | 55 +++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/waybar/waybar-gammastep.sh b/waybar/waybar-gammastep.sh index 5d0c16b..1b0a7e5 100755 --- a/waybar/waybar-gammastep.sh +++ b/waybar/waybar-gammastep.sh @@ -1,18 +1,59 @@ #!/bin/bash -RUNNING=$(pgrep gammastep) +PID=$(pgrep gammastep) +RUNNING=`cat $HOME/.spool/gammastep.status` -if [[ $1 == 'toggle' ]]; then - echo "toggling" - if [ "$RUNNING" ]; then - kill -9 $RUNNING 2&>1 /dev/null +ACTION=$1 +if [[ "$1" == '' ]]; then + ACTION='bar' +fi +echo "$ACTION" >&2 + +if [[ $ACTION == 'bar' ]]; then + : +elif [[ $ACTION == 'toggle' ]]; then + if [ "$PID" ]; then + kill -SIGUSR1 $PID + else + echo 'Gammastep is not running' + fi +elif [[ $ACTION == 'start' ]]; then + if [ "$PID" ]; then + echo 'Gammastep is already running' else $HOME/scripts/sway/gammastep.pl fi - RUNNING=$(pgrep gammastep) +elif [[ $ACTION == 'stop' ]]; then + if [ "$PID" ]; then + kill $PID + else + echo 'Gammastep is not running' + fi +elif [[ $ACTION == 'enable' ]]; then + if [ $PID ]; then + if [ $RUNNING ]; then + echo 'Already enabled' + else + kill -SIGUSR1 $PID + fi + else + echo 'Gammastep is not running' + fi +elif [[ $ACTION == 'disable' ]]; then + if [ $PID ]; then + if [ $RUNNING ]; then + kill -SIGUSR1 $PID + else + echo 'Already disabled' + fi + else + echo 'Gammastep in not running' + fi +else + echo "Invalid argument '$ACTION'. Use 'bar', 'toggle', 'start', 'stop', 'enable', 'disable'." fi - +RUNNING=`cat $HOME/.spool/gammastep.status` if [ "$RUNNING" ]; then echo '{"text":"ɣ","icon":"ɣ","tooltip":"Disable Gammastep","class":"enabled"}' else From 391ad2810cbc2efbb62a3e4fe299dac4c70e2ddc Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:07:29 -0400 Subject: [PATCH 099/110] update flag file path to .spool --- waybar/waybar-keyboard.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waybar/waybar-keyboard.sh b/waybar/waybar-keyboard.sh index 5c49617..9312d3f 100755 --- a/waybar/waybar-keyboard.sh +++ b/waybar/waybar-keyboard.sh @@ -1,6 +1,6 @@ #!/bin/bash -FILE=/home/jpm/.config/onscreen-keyboard +FILE=/home/jpm/.spool/onscreen-keyboard if [ -f $FILE ]; then rm $FILE busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b false From a146b0c1994a01e22f4d7f58f396407d4d4f6a77 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:19:25 -0400 Subject: [PATCH 100/110] Increase icon size --- waybar/waybar-weather.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waybar/waybar-weather.pl b/waybar/waybar-weather.pl index 2f5efcd..f8593a3 100755 --- a/waybar/waybar-weather.pl +++ b/waybar/waybar-weather.pl @@ -30,7 +30,7 @@ if ($cmd eq 'bar') { my $temp = $ref->{current}->{temp} - 273.15; my $icon = $ref->{current}->{weather}->[0]->{icon}; - printf("%s%.1f%s", $icons{$icon}, ${temp}, "°C"); + printf("%s%.1f%s", $icons{$icon}, ${temp}, "°C"); } elsif ($cmd eq 'notify') { `notify-send weather TODO`; } else { From 9d69a634cb36e657fcdd3fe09e87a3d9eae52069 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:19:51 -0400 Subject: [PATCH 101/110] Add a few icon options (still need a comprehensive list) --- waybar/waybar-weather.pl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/waybar/waybar-weather.pl b/waybar/waybar-weather.pl index f8593a3..db5a9b4 100755 --- a/waybar/waybar-weather.pl +++ b/waybar/waybar-weather.pl @@ -11,7 +11,16 @@ if (defined($ARGV[0])) { my $url = "https://john.me.tz/weather/weather.json"; my %icons = ( + '01d' => "☀", + '01n' => "☾", + '02d' => "☁", + '02n' => "☁", + '03d' => "☁", + '03n' => "☁", '04d' => "☁", + '04n' => "☁", + '10d' => "🌧", + '10n' => "🌧", ); use LWP::UserAgent; my $ua = LWP::UserAgent->new(); From c1e205b2516410edd9988e86d4968844d586344a Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:23:04 -0400 Subject: [PATCH 102/110] Superseded by using wofi-wifi-menu.sh directly --- waybar/waybar-nm.sh | 9 --------- 1 file changed, 9 deletions(-) delete mode 100755 waybar/waybar-nm.sh diff --git a/waybar/waybar-nm.sh b/waybar/waybar-nm.sh deleted file mode 100755 index d65f57f..0000000 --- a/waybar/waybar-nm.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -RUNNING=$(pgrep nmtui) - -if [ "$RUNNING" ]; then - kill $RUNNING 2&>1 /dev/null -else - /usr/bin/uxterm -e '/usr/bin/nmtui' -fi From 49925afc61f0418bb14bdc4005951987b9d3fdfe Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:25:32 -0400 Subject: [PATCH 103/110] clean up window titles --- wofi/wofi-alt-tab.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wofi/wofi-alt-tab.sh b/wofi/wofi-alt-tab.sh index c7c59bb..3aae524 100755 --- a/wofi/wofi-alt-tab.sh +++ b/wofi/wofi-alt-tab.sh @@ -1,9 +1,9 @@ #!/bin/bash swaymsg -t get_tree | - jq -r '.nodes[].nodes[] | if .nodes then [recurse(.nodes[])] else [] end + .floating_nodes | .[] | select(.nodes==[]) | if .app_id then ((.app_id | tostring) + " -- " + .name) else .name end' | - grep -v '__i3_scratch' | - sed -e 's/\([^\-]\)\- *[^\-]*$/\1/' | + grep -v __i3_scratch | + sed -e 's/^.*\-\- \(.*\)$/\1/' | + sed -e 's/^\(.*\) [—-] .*$/\1/'| sed -e 's/^\([0-9]*\)\t*\(.*\)/\2 \1/' | wofi -I -s /home/jpm/.dotfiles/wofi/style.css -c \ $HOME/.dotfiles/wofi/sidebar --show dmenu | { From 913952a596a10677f7f6b489093e794cabd239b3 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 18:26:56 -0400 Subject: [PATCH 104/110] Clean up some unneeded variables --- wofi/wofi-wifi-menu.sh | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/wofi/wofi-wifi-menu.sh b/wofi/wofi-wifi-menu.sh index 0838c4b..40c00ab 100755 --- a/wofi/wofi-wifi-menu.sh +++ b/wofi/wofi-wifi-menu.sh @@ -18,10 +18,6 @@ else fi LIST=$(nmcli --fields "$FIELDS" device wifi list | sed '/^--/d') -# For some reason wofi always approximates character width 2 short... hmmm -RWIDTH=$(($(echo "$LIST" | head -n 1 | awk '{print length($0); }')*10)) -# Dynamically change the height of the wofi menu -LINENUM=$(echo "$LIST" | wc -l) # Gives a list of known connections so we can parse it later KNOWNCON=$(nmcli connection show) # Really janky way of telling if there is currently a connection @@ -33,22 +29,12 @@ if [[ ! -z $CURRSSID ]]; then HIGHLINE=$(echo "$(echo "$LIST" | awk -F "[ ]{2,}" '{print $1}' | grep -Fxn -m 1 "$CURRSSID" | awk -F ":" '{print $1}') + 1" | bc ) fi -# HOPEFULLY you won't need this as often as I do -# If there are more than 8 SSIDs, the menu will still only have 8 lines -if [ "$LINENUM" -gt 8 ] && [[ "$CONSTATE" =~ "enabled" ]]; then - LINENUM=8 -elif [[ "$CONSTATE" =~ "disabled" ]]; then - LINENUM=1 -fi - - if [[ "$CONSTATE" =~ "enabled" ]]; then TOGGLE="toggle off" elif [[ "$CONSTATE" =~ "disabled" ]]; then TOGGLE="toggle on" fi - CHENTRY=$(echo -e "$TOGGLE\nmanual\n$LIST" | uniq -u | wofi -s $HOME/.dotfiles/wofi/style.css -i -d --prompt "Wi-Fi SSID: " -c $HOME/.dotfiles/wofi/sidebar) if [[ $CHENTRY == "" ]]; then exit From 4d73b99abf563bb9e3d338740e459081c85c170e Mon Sep 17 00:00:00 2001 From: John Mertz Date: Fri, 23 Sep 2022 22:37:07 -0400 Subject: [PATCH 105/110] Window transparency effecs --- sway/window-transparency.py | 106 ++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 sway/window-transparency.py diff --git a/sway/window-transparency.py b/sway/window-transparency.py new file mode 100755 index 0000000..dd97c44 --- /dev/null +++ b/sway/window-transparency.py @@ -0,0 +1,106 @@ +#!/usr/bin/python + +# This script requires i3ipc-python package (install it from a system package manager +# or pip). +# It makes inactive windows transparent. Use `transparency_val` variable to control +# transparency strength in range of 0…1 or use the command line argument -o. + +import argparse +import i3ipc +import signal +import sys +import os +from pathlib import Path +from functools import partial + +def on_window_focus(opacity, ipc, event): + if os.path.exists(flag): + return + global prev_focused + global prev_workspace + + focused_workspace = ipc.get_tree().find_focused() + + if focused_workspace == None: + return + + focused = event.container + workspace = focused_workspace.workspace().num + + if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859 + focused.command("opacity 1") + if workspace == prev_workspace: + prev_focused.command("opacity " + opacity) + prev_focused = focused + prev_workspace = workspace + +def show_hide(ipc, opacity): + global flag + if os.path.exists(flag): + os.remove(flag) + else: + opacity = 0 + Path(flag).touch() + for workspace in ipc.get_tree().workspaces(): + for w in workspace: + if w.focused and opacity != 0: + w.command("opacity 1") + else: + w.command("opacity "+str(opacity)) + +def remove_opacity(ipc): + global pid + global flag + for workspace in ipc.get_tree().workspaces(): + for w in workspace: + w.command("opacity 1") + for file in [pid, flag]: + if os.path.exists(file): + os.remove(file) + ipc.main_quit() + sys.exit(0) + +def set_all(ipc,opacity): + for window in ipc.get_tree(): + window.command("opacity " + opacity) + +flag = os.environ["HOME"]+"/.spool/sway-hidden" +pid = os.environ["HOME"]+"/.spool/sway-transparency" +opacity = "0.8" + +if __name__ == "__main__": + f = open(pid, "w") + try: + f.write(str(os.getpid())) + except AssertionError as error: + print("Failed to write PID to file "+pid+": "+error) + sys.exit(0) + f.close() + + parser = argparse.ArgumentParser( + description="This script allows you to set the transparency of unfocused windows in sway." + ) + parser.add_argument( + "--opacity", + "-o", + type=str, + default=opacity, + help="set opacity value in range 0...1", + ) + args = parser.parse_args() + + ipc = i3ipc.Connection() + prev_focused = None + prev_workspace = ipc.get_tree().find_focused().workspace().num + + for window in ipc.get_tree(): + if window.focused: + prev_focused = window + else: + window.command("opacity " + args.opacity) + for sig in [signal.SIGINT, signal.SIGTERM]: + signal.signal(sig, lambda signal, frame: remove_opacity(ipc)) + signal.signal(signal.SIGUSR1, lambda signal, frame: show_hide(ipc, opacity)) + ipc.on("window::focus", partial(on_window_focus, args.opacity)) + ipc.main() + From 03bb1b16951ba05d2cceda771c0511237e1d5947 Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 31 Oct 2022 18:07:44 -0400 Subject: [PATCH 106/110] TODO wofi --- send-to-kodi.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/send-to-kodi.sh b/send-to-kodi.sh index e40e422..81279eb 100755 --- a/send-to-kodi.sh +++ b/send-to-kodi.sh @@ -1,5 +1,7 @@ #!/bin/bash +# TODO replace `zenity` with `wofi` + # Required settings host=192.168.2.66 port=8080 From d90eaeed5c295e875ab717476498311915cefb9f Mon Sep 17 00:00:00 2001 From: John Mertz Date: Mon, 31 Oct 2022 18:08:05 -0400 Subject: [PATCH 107/110] improve idle behaviour --- sway/idle.sh | 104 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/sway/idle.sh b/sway/idle.sh index c93e922..e11e571 100755 --- a/sway/idle.sh +++ b/sway/idle.sh @@ -1,50 +1,76 @@ #!/bin/bash -BLFILE="/home/jpm/.config/blc.last" -OPFILE="/home/jpm/.config/active_outputs" +BLFILE="/home/jpm/.spool/idle.dim" +OPFILE="/home/jpm/.spool/active_outputs" + +FADE_TIMEOUT=60 # one minute +DIM_TIMEOUT=120 # two minutes +LOCK_TIMEOUT=300 # five minutes +DPMS_TIMEOUT=600 # ten minutes +SUSPEND_TIMEOUT=3600 # one hour + +function usage() +{ + echo "usage: $0