From a623fed63460d6d810605ce1ce858a58a5b222f7 Mon Sep 17 00:00:00 2001 From: Sakamoto Date: Tue, 12 May 2026 18:31:15 -0500 Subject: init --- dot_config/sway/executable_config | 244 +++++++++++++++++++++++ dot_config/sway/executable_launcher.sh | 350 +++++++++++++++++++++++++++++++++ 2 files changed, 594 insertions(+) create mode 100644 dot_config/sway/executable_config create mode 100644 dot_config/sway/executable_launcher.sh (limited to 'dot_config/sway') diff --git a/dot_config/sway/executable_config b/dot_config/sway/executable_config new file mode 100644 index 0000000..7b75619 --- /dev/null +++ b/dot_config/sway/executable_config @@ -0,0 +1,244 @@ +# Default config for sway +# +# Copy this to ~/.config/sway/config and edit it to your liking. +# +# Read `man 5 sway` for a complete reference. + +### Variables +# +# Logo key. Use Mod1 for Alt. +set $mod Mod1 +# Home row direction keys, like vim +set $left h +set $down j +set $up k +set $right l +# Your preferred terminal emulator +set $term wezterm +# Your preferred application launcher +# Note: pass the final command to swaymsg so that the resulting window can be opened +# on the original workspace that the command was run on. +set $menu exec rofi -show drun -theme android_notification + +### Output configuration +# +# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/) +output * bg ~/Pictures/thumbnail.png center +# +# Example configuration: +# +# output HDMI-A-1 resolution 1920x1080 position 1920,0 +# +# You can get the names of your outputs by running: swaymsg -t get_outputs + +### Idle configuration +# +# Example configuration: +# +# exec swayidle -w \ +# timeout 300 'swaylock -f -c 000000' \ +# timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \ +# before-sleep 'swaylock -f -c 000000' +# +# This will lock your screen after 300 seconds of inactivity, then turn off +# your displays after another 300 seconds, and turn your screens back on when +# resumed. It will also lock your screen before your computer goes to sleep. + +### Input configuration +# +# Example configuration: +# +# input "2:14:SynPS/2_Synaptics_TouchPad" { +# dwt enabled +# tap enabled +# natural_scroll enabled +# middle_emulation enabled +# } +# +# You can get the names of your inputs by running: swaymsg -t get_inputs +# Read `man 5 sway-input` for more information about this section. + +### Key bindings +# +# Basics: +# + # Start a terminal + bindsym $mod+Shift+Return exec $term + + # Kill focused window + bindsym $mod+Shift+q kill + + # Start your launcher + bindsym $mod+d exec $menu + + # Drag floating windows by holding down $mod and left mouse button. + # Resize them with right mouse button + $mod. + # Despite the name, also works for non-floating windows. + # Change normal to inverse to use left mouse button for resizing and right + # mouse button for dragging. + floating_modifier $mod normal + + # Reload the configuration file + bindsym $mod+Shift+c reload + + # Exit sway (logs you out of your Wayland session) + bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit' + # Lock screen + bindsym $mod+Shift+m exec lock +# +# Moving around: +# + # Move your focus around + bindsym $mod+$left focus left + bindsym $mod+$down focus down + bindsym $mod+$up focus up + bindsym $mod+$right focus right + # Or use $mod+[up|down|left|right] + bindsym $mod+Left focus left + bindsym $mod+Down focus down + bindsym $mod+Up focus up + bindsym $mod+Right focus right + + # Move the focused window with the same, but add Shift + bindsym $mod+Shift+$left move left + bindsym $mod+Shift+$down move down + bindsym $mod+Shift+$up move up + bindsym $mod+Shift+$right move right + # Ditto, with arrow keys + bindsym $mod+Shift+Left move left + bindsym $mod+Shift+Down move down + bindsym $mod+Shift+Up move up + bindsym $mod+Shift+Right move right +# +# Workspaces: +# + # Switch to workspace + bindsym $mod+1 workspace number 1 + bindsym $mod+2 workspace number 2 + bindsym $mod+3 workspace number 3 + bindsym $mod+4 workspace number 4 + bindsym $mod+5 workspace number 5 + bindsym $mod+6 workspace number 6 + bindsym $mod+7 workspace number 7 + bindsym $mod+8 workspace number 8 + bindsym $mod+9 workspace number 9 + bindsym $mod+0 workspace number 10 + # Move focused container to workspace + bindsym $mod+Shift+1 move container to workspace number 1 + bindsym $mod+Shift+2 move container to workspace number 2 + bindsym $mod+Shift+3 move container to workspace number 3 + bindsym $mod+Shift+4 move container to workspace number 4 + bindsym $mod+Shift+5 move container to workspace number 5 + bindsym $mod+Shift+6 move container to workspace number 6 + bindsym $mod+Shift+7 move container to workspace number 7 + bindsym $mod+Shift+8 move container to workspace number 8 + bindsym $mod+Shift+9 move container to workspace number 9 + bindsym $mod+Shift+0 move container to workspace number 10 + # Note: workspaces can have any name you want, not just numbers. + # We just use 1-10 as the default. +# +# Layout stuff: +# + # You can "split" the current object of your focus with + # $mod+b or $mod+v, for horizontal and vertical splits + # respectively. + bindsym $mod+b splith + bindsym $mod+v splitv + + # Switch the current container between different layout styles + bindsym $mod+s layout stacking + bindsym $mod+w layout tabbed + bindsym $mod+e layout toggle split + + # Make the current focus fullscreen + bindsym $mod+f fullscreen + + # Toggle the current focus between tiling and floating mode + bindsym $mod+Shift+space floating toggle + + # Swap focus between the tiling area and the floating area + bindsym $mod+space focus mode_toggle + + # Move focus to the parent container + # bindsym $mod+a focus parent +# +# Scratchpad: +# + # Sway has a "scratchpad", which is a bag of holding for windows. + # You can send windows there and get them back later. + + # Move the currently focused window to the scratchpad + # bindsym $mod+Shift+minus move scratchpad + + # Show the next scratchpad window or hide the focused scratchpad window. + # If there are multiple scratchpad windows, this command cycles through them. + # bindsym $mod+minus scratchpad show +# +# Resizing containers: +# +mode "resize" { + # left will shrink the containers width + # right will grow the containers width + # up will shrink the containers height + # down will grow the containers height + bindsym $left resize shrink width 10px + bindsym $down resize grow height 10px + bindsym $up resize shrink height 10px + bindsym $right resize grow width 10px + + # Ditto, with arrow keys + bindsym Left resize shrink width 10px + bindsym Down resize grow height 10px + bindsym Up resize shrink height 10px + bindsym Right resize grow width 10px + + # Return to default mode + bindsym Return mode "default" + bindsym Escape mode "default" +} +bindsym $mod+r mode "resize" + +bar swaybar_command waybar + +default_border pixel +default_floating_border pixel +gaps inner 10 + +bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5% +bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5% +bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle +bindsym XF86AudioMicMute exec pactl set-source-mute @DEFAULT_SOURCE@ toggle +bindsym XF86MonBrightnessDown exec brightnessctl set 5%- +bindsym XF86MonBrightnessUp exec brightnessctl set 5%+ +bindsym XF86AudioPlay exec playerctl play-pause +bindsym XF86AudioNext exec playerctl next +bindsym XF86AudioPrev exec playerctl previous +bindsym XF86Search exec $menu + +# exec mpd-mpris +# exec easyeffects --gapplication-service +exec mako +# exec mpc clear && mpc add / +# exec fcitx5 -D +exec gammastep +exec kanshi +exec kdeconnectd +exec udiskie +exec keepassxc --minimized +exec /usr/lib/hyprpolkitagent/hyprpolkitagent + +bindsym $mod+Shift+y exec 'swaylock -f -c 000000' + +bindsym $mod+tab workspace next + +# # capture all screens to clipboard +bindsym Shift+Print exec flameshot gui -r | rpaste | wl-copy + +# capture the specified screen area to clipboard +bindsym Print exec flameshot gui + +seat * hide_cursor 4000 + +exec dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway + +include /etc/sway/config.d/* diff --git a/dot_config/sway/executable_launcher.sh b/dot_config/sway/executable_launcher.sh new file mode 100644 index 0000000..2034ed3 --- /dev/null +++ b/dot_config/sway/executable_launcher.sh @@ -0,0 +1,350 @@ +#!/usr/bin/env bash +# terminal application launcher for sway, using fzf +# Based on: https://gitlab.com/FlyingWombat/my-scripts/blob/master/sway-launcher +# https://gist.github.com/Biont/40ef59652acf3673520c7a03c9f22d2a +shopt -s nullglob globstar +set -o pipefail +if ! { exec 0>&3; } 1>/dev/null 2>&1; then + exec 3>/dev/null # If file descriptor 3 is unused in parent shell, output to /dev/null +fi +# shellcheck disable=SC2154 +trap 's=$?; echo "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR +IFS=$'\n\t' +DEL=$'\34' + +TERMINAL_COMMAND="foot" +GLYPH_COMMAND="${GLYPH_COMMAND- }" +GLYPH_DESKTOP="${GLYPH_DESKTOP- }" +CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/sway-launcher-desktop" +PROVIDERS_FILE="${PROVIDERS_FILE:=providers.conf}" +if [[ "${PROVIDERS_FILE#/}" == "${PROVIDERS_FILE}" ]]; then + # $PROVIDERS_FILE is a relative path, prepend $CONFIG_DIR + PROVIDERS_FILE="${CONFIG_DIR}/${PROVIDERS_FILE}" +fi + +# Provider config entries are separated by the field separator \034 and have the following structure: +# list_cmd,preview_cmd,launch_cmd,purge_cmd +declare -A PROVIDERS +if [ -f "${PROVIDERS_FILE}" ]; then + eval "$(awk -F= ' + BEGINFILE{ provider=""; } + /^\[.*\]/{sub("^\\[", "");sub("\\]$", "");provider=$0} + /^(launch|list|preview|purge)_cmd/{st = index($0,"=");providers[provider][$1] = substr($0,st+1)} + ENDFILE{ + for (key in providers){ + if(!("list_cmd" in providers[key])){continue;} + if(!("launch_cmd" in providers[key])){continue;} + if(!("preview_cmd" in providers[key])){continue;} + if(!("purge_cmd" in providers[key])){providers[key]["purge_cmd"] = "exit 0";} + for (entry in providers[key]){ + gsub(/[\x27,\047]/,"\x27\"\x27\"\x27", providers[key][entry]) + } + print "PROVIDERS[\x27" key "\x27]=\x27" providers[key]["list_cmd"] "\034" providers[key]["preview_cmd"] "\034" providers[key]["launch_cmd"] "\034" providers[key]["purge_cmd"] "\x27\n" + } + }' "${PROVIDERS_FILE}")" + if [[ ! -v HIST_FILE ]]; then + HIST_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/${0##*/}-${PROVIDERS_FILE##*/}-history.txt" + fi +else + PROVIDERS['desktop']="${0} list-entries${DEL}${0} describe-desktop \"{1}\"${DEL}${0} run-desktop '{1}' {2}${DEL}test -f '{1}' || exit 43" + PROVIDERS['command']="${0} list-commands${DEL}${0} describe-command \"{1}\"${DEL}${TERMINAL_COMMAND} {1}${DEL}command -v '{1}' || exit 43" + if [[ ! -v HIST_FILE ]]; then + HIST_FILE="${XDG_CACHE_HOME:-$HOME/.cache}/${0##*/}-history.txt" + fi +fi +PROVIDERS['user']="exit${DEL}exit${DEL}{1}" # Fallback provider that simply executes the exact command if there were no matches + +if [[ -n "${HIST_FILE}" ]]; then + mkdir -p "${HIST_FILE%/*}" && touch "$HIST_FILE" + readarray HIST_LINES <"$HIST_FILE" +fi + +function describe() { + # shellcheck disable=SC2086 + readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${1}]} + # shellcheck disable=SC2086 + [ -n "${PROVIDER_ARGS[1]}" ] && eval "${PROVIDER_ARGS[1]//\{1\}/${2}}" +} +function describe-desktop() { + description=$(sed -ne '/^Comment=/{s/^Comment=//;p;q}' "$1") + echo -e "\033[33m$(sed -ne '/^Name=/{s/^Name=//;p;q}' "$1")\033[0m" + echo "${description:-No description}" +} +function describe-command() { + readarray arr < <(whatis -l "$1" 2>/dev/null) + description="${arr[0]}" + description="${description#* - }" + echo -e "\033[33m${1}\033[0m" + echo "${description:-No description}" +} + +function provide() { + # shellcheck disable=SC2086 + readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[$1]} + eval "${PROVIDER_ARGS[0]}" +} +function list-commands() { + IFS=: read -ra path <<<"$PATH" + for dir in "${path[@]}"; do + printf '%s\n' "$dir/"* | + awk -F / -v pre="$GLYPH_COMMAND" '{print $NF "\034command\034\033[31m" pre "\033[0m" $NF;}' + done | sort -u +} +function list-entries() { + # Get locations of desktop application folders according to spec + # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + IFS=':' read -ra DIRS <<<"${XDG_DATA_HOME-${HOME}/.local/share}:${XDG_DATA_DIRS-/usr/local/share:/usr/share}" + for i in "${!DIRS[@]}"; do + if [[ ! -d "${DIRS[i]}" ]]; then + unset -v 'DIRS[$i]' + else + DIRS[$i]="${DIRS[i]}/applications/**/*.desktop" + fi + done + # shellcheck disable=SC2068 + entries ${DIRS[@]} +} +function entries() { + # shellcheck disable=SC2068 + awk -v pre="$GLYPH_DESKTOP" -F= ' + function desktopFileID(filename){ + sub("^.*applications/", "", filename); + sub("/", "-", filename); + return filename + } + BEGINFILE{ + application=0; + hidden=0; + block=""; + a=0 + + id=desktopFileID(FILENAME) + if(id in fileIds){ + nextfile; + }else{ + fileIds[id]=0 + } + } + /^\[Desktop Entry\]/{block="entry"} + /^Type=Application/{application=1} + /^\[Desktop Action/{ + sub("^\\[Desktop Action ", ""); + sub("\\]$", ""); + block="action"; + a++; + actions[a,"key"]=$0 + } + /^\[X-/{ + sub("^\\[X-", ""); + sub("\\]$", ""); + block="action"; + a++; + actions[a,"key"]=$0 + } + /^Name=/{ (block=="action")? actions[a,"name"]=$2 : name=$2 } + /^NoDisplay=true/{ (block=="action")? actions[a,"hidden"]=1 : hidden=1 } + ENDFILE{ + if (application){ + if (!hidden) + print FILENAME "\034desktop\034\033[33m" pre name "\033[0m"; + if (a>0) + for (i=1; i<=a; i++) + if (!actions[i, "hidden"]) + print FILENAME "\034desktop\034\033[33m" pre name "\033[0m (" actions[i, "name"] ")\034" actions[i, "key"] + } + }' \ + $@ &3)" + echo "Generated Launch command from .desktop file: ${CMD}" >&3 + eval "${CMD}" +} +function generate-command() { + # Define the search pattern that specifies the block to search for within the .desktop file + PATTERN="^\\\\[Desktop Entry\\\\]" + if [[ -n $2 ]]; then + PATTERN="^\\\\[Desktop Action ${2}\\\\]" + fi + echo "Searching for pattern: ${PATTERN}" >&3 + # 1. We see a line starting [Desktop, but we're already searching: deactivate search again + # 2. We see the specified pattern: start search + # 3. We see an Exec= line during search: remove field codes and set variable + # 3. We see a Path= line during search: set variable + # 4. Finally, build command line + awk -v pattern="${PATTERN}" -v terminal_cmd="${TERMINAL_COMMAND}" -F= ' + BEGIN{a=0;exec=0;path=0} + /^\[Desktop/{ + if(a){ a=0 } + } + $0 ~ pattern{ a=1 } + /^Terminal=/{ + sub("^Terminal=", ""); + if ($0 == "true") { terminal=1 } + } + /^Exec=/{ + if(a && !exec){ + sub("^Exec=", ""); + gsub(" ?%[cDdFfikmNnUuv]", ""); + exec=$0; + } + } + /^Path=/{ + if(a && !path){ path=$2 } + } + END{ + if(path){ printf "cd " path " && " } + printf "exec " + if (terminal){ printf terminal_cmd " " } + print exec + }' "$1" +} + +function autostart() { + for application in $(list-autostart); do + (exec setsid /bin/sh -c "$(run-desktop "${application}")" &>/dev/null &) + done +} + +function list-autostart() { + # Get locations of desktop application folders according to spec + # https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + IFS=':' read -ra DIRS <<<"${XDG_CONFIG_HOME-${HOME}/.config}:${XDG_CONFIG_DIRS-/etc/xdg}" + for i in "${!DIRS[@]}"; do + if [[ ! -d "${DIRS[i]}" ]]; then + unset -v 'DIRS[$i]' + else + DIRS[$i]="${DIRS[i]}/autostart/*.desktop" + fi + done + + # shellcheck disable=SC2068 + awk -v pre="$GLYPH_DESKTOP" -F= ' + function desktopFileID(filename){ + sub("^.*autostart/", "", filename); + sub("/", "-", filename); + return filename + } + BEGINFILE{ + application=0; + block=""; + disabled=0; + a=0 + + id=desktopFileID(FILENAME) + if(id in fileIds){ + nextfile; + }else{ + fileIds[id]=0 + } + } + /^\[Desktop Entry\]/{block="entry"} + /^Type=Application/{application=1} + /^Name=/{ iname=$2 } + /^Hidden=true/{disabled=1} + ENDFILE{ + if (application && !disabled){ + print FILENAME; + } + }' \ + ${DIRS[@]} "${HIST_FILE}" + declare -A PURGE_CMDS + for PROVIDER_NAME in "${!PROVIDERS[@]}"; do + readarray -td ${DEL} PROVIDER_ARGS <<<${PROVIDERS[${PROVIDER_NAME}]} + PURGE_CMD=${PROVIDER_ARGS[3]} + [ -z "${PURGE_CMD}" ] && PURGE_CMD='test -f "{1}" || exit 43' + PURGE_CMDS[$PROVIDER_NAME]="${PURGE_CMD%$'\n'}" + done + for HIST_LINE in "${HIST_LINES[@]#*' '}"; do + readarray -td $'\034' HIST_ENTRY <<<${HIST_LINE} + ENTRY=${HIST_ENTRY[1]} + readarray -td ' ' FILTER <<<${PURGE_CMDS[$ENTRY]//\{1\}/${HIST_ENTRY[0]}} + (eval "${FILTER[@]}" 1>/dev/null) # Run filter command discarding output. We only want the exit status + if [[ $? -ne 43 ]]; then + echo "1 ${HIST_LINE[@]%$'\n'}" >> "${HIST_FILE}" + fi + done +} + +case "$1" in +describe | describe-desktop | describe-command | entries | list-entries | list-commands | list-autostart | generate-command | autostart | run-desktop | provide | purge) + "$@" + exit + ;; +esac +echo "Starting launcher instance with the following providers:" "${!PROVIDERS[@]}" >&3 + +FZFPIPE=$(mktemp -u) +mkfifo "$FZFPIPE" +trap 'rm "$FZFPIPE"' EXIT INT + +# Append Launcher History, removing usage count +(printf '%s' "${HIST_LINES[@]#* }" >>"$FZFPIPE") & + +# Iterate over providers and run their list-command +for PROVIDER_NAME in "${!PROVIDERS[@]}"; do + (bash -c "${0} provide ${PROVIDER_NAME}" >>"$FZFPIPE") & +done + +readarray -t COMMAND_STR <<<$( + fzf --ansi +s -x -d '\034' --nth ..3 --with-nth 3 \ + --print-query \ + --preview "$0 describe {2} {1}" \ + --preview-window=up:2:noborder \ + --no-multi --cycle \ + --prompt="${GLYPH_PROMPT-# }" \ + --header='' --no-info --margin='1,2' \ + --color='16,gutter:-1' \ + <"$FZFPIPE" +) || exit 1 +# Get the last line of the fzf output. If there were no matches, it contains the query which we'll treat as a custom command +# If there were matches, it contains the selected item +COMMAND_STR=$(printf '%s\n' "${COMMAND_STR[@]: -1}") +# We still need to format the query to conform to our fallback provider. +# We check for the presence of field separator character to determine if we're dealing with a custom command +if [[ $COMMAND_STR != *$'\034'* ]]; then + COMMAND_STR="${COMMAND_STR}"$'\034user\034'"${COMMAND_STR}"$'\034' + SKIP_HIST=1 # I chose not to include custom commands in the history. If this is a bad idea, open an issue please +fi + +[ -z "$COMMAND_STR" ] && exit 1 + +if [[ -n "${HIST_FILE}" && ! "$SKIP_HIST" ]]; then + # update history + for i in "${!HIST_LINES[@]}"; do + if [[ "${HIST_LINES[i]}" == *" $COMMAND_STR"$'\n' ]]; then + HIST_COUNT=${HIST_LINES[i]%% *} + HIST_LINES[$i]="$((HIST_COUNT + 1)) $COMMAND_STR"$'\n' + match=1 + break + fi + done + if ! ((match)); then + HIST_LINES+=("1 $COMMAND_STR"$'\n') + fi + + printf '%s' "${HIST_LINES[@]}" | sort -nr >"$HIST_FILE" +fi + +# shellcheck disable=SC2086 +readarray -d $'\034' -t PARAMS <<<${COMMAND_STR} +# shellcheck disable=SC2086 +readarray -d ${DEL} -t PROVIDER_ARGS <<<${PROVIDERS[${PARAMS[1]}]} +# Substitute {1}, {2} etc with the correct values +COMMAND=${PROVIDER_ARGS[2]//\{1\}/${PARAMS[0]}} +COMMAND=${COMMAND//\{2\}/${PARAMS[3]}} +COMMAND=${COMMAND%%[[:space:]]} + +if [ -t 1 ]; then + echo "Launching command: ${COMMAND}" >&3 + setsid /bin/sh -c "${COMMAND}" >&/dev/null