Sway

Published Fri 7 Feb 2025.
A post in the series.

I use the sway Wayland compositor, which is a clone of the X11 i3 window manager for Wayland. Wayland is a communications protocol for next-generation display servers used in Unix-like systems which has been adopted as the default display server by Linux distributions including Fedora with KDE, and Ubuntu and Debian with GNOME. I use the sway Wayland compositor. It aims to replace the venerable X display server with a modern alternative. X leaves logic such as window management to application software, which has allowed the proliferation of different approaches. Wayland, however, centralises this logic in the ‘compositor’, which assumes both display server and window manager roles.

Status

In lieu of a status bar I invoke a little script with Super+Esc which shows various system information in a notification with the dunst notification daemon,

#!/usr/bin/env bash

INFOS=()

DATE=`date "+%a %Y-%m-%d %I:%M:%S%p"`

add_info() {
 local SCRIPT_NAME=$1
 local INFO="`$(dirname "$0")/../lib/${SCRIPT_NAME}.sh`"
 if [ "$INFO" != "" ]; then
  INFOS+=("$INFO")
 fi
}

TIMEOUT=10000

if [ "$#" -eq 0 ] || ([ "$#" -eq 2 ] && ([[ "$1" = "-t" ]] || [[ "$1" = "--timeout" ]])) ; then
 INFOS+=("$DATE")
 add_info "workspace"
 add_info "mail"
 add_info "idle"
 add_info "disk"
 add_info "cpu"
 add_info "temperature"
 add_info "load_average"
 add_info "memory"
 add_info "network"
 add_info "backlight"
 add_info "pulse"
 add_info "player"
 add_info "battery"
else
 while (( "$#" )); do
  case "$1" in
   -t|--timeout)
    TIMEOUT=$2
    shift 2
    ;;
   *)
    case "$1" in
     date)         INFOS+=("$DATE") ;;
     workspace)    add_info "workspace" ;;
     mail)         add_info "mail" ;;
     idle)         add_info "idle" ;;
     disk)         add_info "disk" ;;
     cpu)          add_info "cpu" ;;
     temperature)  add_info "temperature" ;;
     load_average) add_info "load_average" ;;
     memory)       add_info "memory" ;;
     network)      add_info "network" ;;
     backlight)    add_info "backlight" ;;
     pulse)        add_info "pulse" ;;
     player)       add_info "player" ;;
     battery)      add_info "battery" ;;
     *) echo "Warning: Unknown argument '$1'";;
    esac
    shift
    ;;
  esac
 done
fi

IFS=$'\n'; echo "${INFOS[*]}"

ID_FILE="${XDG_CACHE_DIR:-"$HOME/.cache"}/st_id"
ID="$(cat $ID_FILE)"
REPLACE_ARG=""
if [ ! -z $ID ]; then
 REPLACE="-r"
fi

dunstify -t $TIMEOUT -u low "Status" -p $REPLACE $ID "`IFS=$'\n'; echo "${INFOS[*]}"`" > $ID_FILE

For example, here is a script which shows the pulse audio status,

#!/usr/bin/env bash

sink_ids=($(pactl list short sinks | cut -f 1))
sinks=($(pactl list short sinks | cut -f 2))

default_sink=$(pactl info | sed -En 's/Default Sink: (.*)/\1/p')
default_source=$(pactl info | sed -En 's/Default Source: (.*)/\1/p')

for i in "${!sinks[@]}"; do
 if [[ "${sinks[$i]}" = "${default_sink}" ]]; then
  break
 fi
done

deets="$(pactl list sinks | grep -A14 "#${sink_ids[$i]}")"
vol="$(echo "$deets" | grep "Volume" | head -1 | awk '{print $5}')"
mute="$(echo "$deets" | grep "Mute: yes")"

if [ ! -z "$mute" ]; then
 label=""
else
 label=""
fi

mic_mute="$(pactl list sources | grep -A14 "$default_source" | grep "Mute: no")"
if [ -z "$mic_mute" ]; then
 mic=""
else
 mic=""
fi

echo "$label $vol [${sink_ids[$i]}] $mic"

Workspace history

I’ve got a few bindings and scripts to manage workspaces, for example Super-<number> will go to that number workspace, Super-m will take me to the next free workspace, Super-t will rename a workspace, Super+\ will search workspaces names, etc.

I often use Super+` to switch back_and_forth between workspaces, but sometimes I’m working between 3 or more workspaces and I get a bit lost.

I’m used to vim’s jumplist behaviour so I wrote i3-workspace-history to replicate this behaviour in sway/i3. It uses a daemon to listen for workspace changes through sway/i3’s Inter-Process Communication (IPC) interface and keeps track of workspace history, and a client which can travel back and forth through this history.

Using it is as simple as,

exec i3-workspace-history -sway

bindsym $mod+i exec i3_workspace_history -mode=forward -sway; exec st workspace -t 500
bindsym $mod+o exec i3_workspace_history -mode=back    -sway; exec st workspace -t 500

Conclusion

There’s a hundred other tips and tricks in my configuration which you can find here.