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