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