UP  |  HOME

sway

Table of Contents

Main Config

Listing 1: ~/.config/sway/config
set $mod Mod4

set $term alacritty

input * xkb_layout "us,us"
input * xkb_variant "dvorak,"
input * xkb_options "ctrl:nocaps,grp:shifts_toggle"

# This ordering is important. If you set * like above, and then 
# change xkb_layout for one device you end up trying to combine incompatible
# layouts and variants. Setting the variant first lets us avoid the conflict.
input "1452:598:rssa" xkb_variant "mac,dvorak,"
input "1452:598:rssa" xkb_layout "ru,us,us"
input "1452:598:rssa" xkb_options "ctrl:nocaps,grp:shifts_toggle"

input type:touchpad {
    tap enabled
    dwt enabled
    natural_scroll enabled
}

# Device specific config, subsitution handled by yadm alternates
include ~/.config/sway/config.local

# Русский layout binds 
include ~/.config/sway/config.русский

# colors used, for reference
#333333 dark grey
#56ADBC teal blue
#666666 charcoal grey
#8C6BC8 deep lavendar
#AE81FF liliac
#E3E3DD light grey
#FA9429 pumpkin
#66D9EF robin's egg

# Window Colors
# class                 border  backgr. text    indicator child_border
client.focused          #333333 #56ADBC #333333 #FA9429   #56ADBC
client.unfocused        #333333 #333333 #E3E3DD #333333   #333333
client.focused_inactive #666666 #333333 #E3E3DD #333333   #333333
client.urgent           #AE81FF #8C6BC8 #E3E3DD #8C6BC8   #8C6BC8
client.placeholder      #333333 #333333 #E3E3DD #333333   #333333

client.background       #E3E3DD

show_marks no

font pango:Fira Code 9

# start a terminal
bindsym $mod+grave  exec $term

# rox-filer shortcuts
bindsym $mod+Tab exec rox-filer

# start dmenu (a program launcher)
bindsym $mod+p exec dmenu_run -m $(swaymsg --raw -t get_outputs |jq -r '.[]|.["focused"]'| jq -s 'index(true)')
# TODO this still depends on an i3 executable
# i3-dmenu-desktop which only displays applications shipping a .desktop file
bindsym $mod+y exec i3-dmenu-desktop --dmenu="dmenu -i -m $(swaymsg --raw -t get_outputs |jq -r '.[]|.["focused"]'| jq -s 'index(true)')"

# change focus
bindsym $mod+h focus left
bindsym $mod+l focus right
bindsym $mod+k focus up
bindsym $mod+j focus down

# move focused window
bindsym $mod+Shift+h move left
bindsym $mod+Shift+l move right
bindsym $mod+Shift+k move up
bindsym $mod+Shift+j move down

# switch workspaces
bindsym $mod+Left  workspace prev
bindsym $mod+Right workspace next

# Rearrange workspaces
bindsym $mod+Shift+Left  move workspace to output left
bindsym $mod+Shift+Down  move workspace to output down
bindsym $mod+Shift+Up    move workspace to output up
bindsym $mod+Shift+Right move workspace to output right

# split in horizontal orientation
bindsym $mod+s splith

# split in vertical orientation
bindsym $mod+v splitv


# enter fullscreen mode for the focused container
bindsym $mod+u       fullscreen toggle
bindsym $mod+Shift+u fullscreen toggle global

# change container layout (stacked, tabbed, toggle split)
bindsym $mod+apostrophe layout stacking
bindsym $mod+comma      layout tabbed
bindsym $mod+period     layout toggle split

# Use Mouse+$mod to drag windows to their wanted position
floating_modifier $mod normal

# toggle tiling / floating
bindsym $mod+Shift+space floating toggle

# change focus between tiling / floating windows
bindsym $mod+space focus mode_toggle

# always float some apps
for_window [app_id="geeqie"] floating enable
for_window [app_id="zenity"] floating enable
#for_window [app_id="Remmina"] floating enable

# scratchpad
bindsym $mod+shift+z move scratchpad
bindsym $mod+shift+v scratchpad show

# focus the parent container
bindsym $mod+a focus parent

# focus the child container
bindsym $mod+d focus child

# 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
bindsym $mod+F1  workspace number 11
bindsym $mod+F2  workspace number 12
bindsym $mod+F3  workspace number 13
bindsym $mod+F4  workspace number 14
bindsym $mod+F5  workspace number 15
bindsym $mod+F6  workspace number 16
bindsym $mod+F7  workspace number 17
bindsym $mod+F8  workspace number 18
bindsym $mod+F9  workspace number 19
bindsym $mod+F10 workspace number 20

# 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
bindsym $mod+Shift+F1  move container to workspace number 11
bindsym $mod+Shift+F2  move container to workspace number 12
bindsym $mod+Shift+F3  move container to workspace number 13
bindsym $mod+Shift+F4  move container to workspace number 14
bindsym $mod+Shift+F5  move container to workspace number 15
bindsym $mod+Shift+F6  move container to workspace number 16
bindsym $mod+Shift+F7  move container to workspace number 17
bindsym $mod+Shift+F8  move container to workspace number 18
bindsym $mod+Shift+F9  move container to workspace number 19
bindsym $mod+Shift+F10 move container to workspace number 20

bindsym $mod+Shift+n exec "swaymsg workspace number $(($(swaymsg --raw -t get_workspaces |jq -r '.[].name'|cut -d':' -f 1|sort -n| tail -1) + 1))"

# work with workspaces
# Rename
bindsym $mod+Shift+r exec swaymsg rename workspace \
    $(swaymsg --raw -t get_workspaces | jq '.[] | select(.focused==true).name') \
    to \
    $(swaymsg --raw -t get_workspaces | jq '.[] | select(.focused==true).num'):$(zenity --entry --title 'Rename workspace' --text "New workspace name:")

# TODO rewrite scripts for sway (don't forget to update russian binds)
bindsym $mod+Mod1+Shift+m exec "~/.config/i3/ws_main.sh"
bindsym $mod+Mod1+Shift+c exec "~/.config/i3/ws_new_code.sh"
bindsym $mod+Mod1+Shift+d exec "~/.config/i3/ws_new_doc.sh"

# remark windows that are already swallowed
for_window [app_id="atril|devhelp|evince|gvim|calibrei-gui" workspace="^\d+:doc" con_mark="^swallowed\d$"] mark --replace unswallowed
# toggle it. (swallowed windows become unmarked, unswallowed windows are now marked)
for_window [class="^Atril$|^Devhelp$|^Evince$|^Gvim$|^calibre$" workspace="^\d+:doc"] mark --toggle unswallowed
# move unswallowed windows to the desired mark
for_window [class="^Atril$|^Devhelp$|^Evince$|^Gvim$|^calibre$" workspace="^\d+:doc" con_mark="^unswallowed$"] move window to mark doc

# Lock screen (Hyper+Alt+l)
bindsym --release $mod+Mod1+l exec "sleep 1; pkill -x --signal SIGUSR1 swayidle"

# reload the configuration file
bindsym $mod+Shift+y reload
# restart sway inplace (preserves your layout/session, can be used to upgrade sway)
bindsym $mod+Shift+p restart
# exit sway (logs you out of your X session)
bindsym $mod+Shift+period 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'

# kill focused window
bindsym --no-repeat $mod+Shift+apostrophe kill

# mouse actions
# TODO --release is broken https://github.com/swaywm/sway/issues/5333
# bindsym --no-repeat --release $mod+button2 kill
# bindsym --release $mod+button3 floating toggle
bindsym --no-repeat $mod+button2 kill
bindsym $mod+button3 floating toggle
# TODO sway: button10 and higher need to use events, not currently using relevant hardware so I'll deal with this later
#bindsym --release Mod2+button10 kill
#bindsym --release button10 kill

# move all but main (1) workspace to chosen output
# (uses zenity, swaymsg, jq)
bindsym $mod+Shift+m exec "~/.config/sway/mv_ws.sh"

# change screen layout
mode "screenlayout" {
    bindsym 1 exec ~/.screenlayout/single_left.sh
    bindsym 2 exec ~/.screenlayout/single.sh
    bindsym 3 exec ~/.screenlayout/single_right.sh
    bindsym 4 exec ~/.screenlayout/dual_left.sh
    bindsym 5 exec ~/.screenlayout/dual_right.sh
    bindsym 6 exec ~/.screenlayout/triple.sh

    # set background randomly
    bindsym 0      output * bg "$(find ~/.wallpapers/|sort -R|tail -n 1)" fill
    bindsym $mod+x mode "default"
    bindsym $mod+r mode "resize"
    bindsym Escape mode "default"
}

# resize mode
mode "resize" {
    bindsym h resize shrink width 10px
    bindsym Left resize shrink width 10px
    bindsym k resize shrink height 10px
    bindsym Up resize shrink height 10px
    bindsym l resize grow width 10px
    bindsym Right resize grow width 10px
    bindsym j resize grow height 10px
    bindsym Down resize grow height 10px

    # Return to default mode
    bindsym $mod+r mode "default"
    bindsym $mod+x mode "screenlayout"
    bindsym Escape mode "default"
}

bindsym $mod+r mode "resize"
bindsym $mod+x mode "screenlayout"

#Toggle touchscreen/touchpad
bindsym $mod+Shift+s exec ~/.config/sway/toggle_ts.sh
bindsym $mod+Shift+t exec ~/.config/sway/toggle_tp.sh

# Toggle 'disable touchpad while typing'
# force reload waybar to update the custom/dwt module (TODO find a better way)
# Ideally I could send a IPC message to waybar or something
bindsym $mod+Shift+w exec "~/.config/waybar/dwt/toggle_dwt.sh; killall -SIGUSR2 waybar"

# Multimedia, brightness keys
bindsym XF86AudioRaiseVolume  exec --no-startup-id pactl set-sink-volume 0 +3%
bindsym XF86AudioLowerVolume  exec --no-startup-id pactl set-sink-volume 0 -3%
bindsym XF86AudioMute         exec --no-startup-id pactl set-sink-mute 0 toggle

bindsym XF86Display           exec --no-startup-id lxrandr
bindsym XF86MonBrightnessUp   exec brightnessctl s +5%
bindsym XF86MonBrightnessDown exec brightnessctl s 5%-

bindsym XF86AudioPlay         exec playerctl play-pause
bindsym XF86AudioPrev         exec playerctl previous
bindsym XF86AudioNext         exec playerctl next
bindsym $mod+Shift+Mod1+space exec playerctl play-pause
bindsym $mod+Up               exec playerctl previous
bindsym $mod+Down             exec playerctl next

bar {
    swaybar_command waybar
}

# cursor setup, backgrounk
output * bg $(find ~/.wallpapers/|sort -R|tail -n 1) fill

# autostart apps
exec --no-startup-id xrdb ~/.Xresources
exec --no-startup-id systemctl --user import-environment
exec --no-startup-id rot8
exec --no-startup-id mako
exec --no-startup-id swayidle -w
exec --no-startup-id squeekboard
exec --no-startup-id remmina -i
exec --no-startup-id pasystray
exec --no-startup-id nm-applet --indicator
exec --no-startup-id udiskie --tray
exec --no-startup-id xfce4-notes
exec --no-startup-id ~/.dropbox/dropbox_start.py
exec --no-startup-id kdeconnect-indicator
exec --no-startup-id blueman-applet
exec --no-startup-id usbguard-applet-qt
exec --no-startup-id krb5-auth-dialog
# disabled because no way to start in tray
#exec --no-startup-id keepassx

# Start with a single display
exec ~/.screenlayout/single.sh

Russian keyboard layout bindings

Listing 2: ~/.config/sway/config.русский
##############################################
############ Русский layout binds ############
##############################################

bindsym $mod+less   exec $term

# kill focused window
bindsym $mod+Shift+Cyrillic_SHORTI kill

# start dmenu, i3-dmenu-desktop
bindsym $mod+Cyrillic_ka exec dmenu_run -m $(swaymsg --raw -t get_outputs |jq -r '.[]|.["focused"]'| jq -s 'index(true)')
# TODO this still depends on an i3 executable
bindsym $mod+Cyrillic_ie exec i3-dmenu-desktop --dmenu="dmenu -i -m $(swaymsg --raw -t get_outputs |jq -r '.[]|.["focused"]'| jq -s 'index(true)')"

# change focus
bindsym $mod+Cyrillic_o focus left
bindsym $mod+Cyrillic_ze focus right
bindsym $mod+Cyrillic_em focus up
bindsym $mod+Cyrillic_es focus down

# move focused window
bindsym $mod+Shift+Cyrillic_O move left
bindsym $mod+Shift+Cyrillic_ZE move right
bindsym $mod+Shift+Cyrillic_EM move up
bindsym $mod+Shift+Cyrillic_ES move down

# split in horizontal orientation
bindsym $mod+Cyrillic_zhe splith

# split in vertical orientation
bindsym $mod+Cyrillic_yu splitv

# enter fullscreen mode for the focused container
bindsym $mod+Cyrillic_a fullscreen toggle
bindsym $mod+Shift+Cyrillic_A fullscreen toggle global

# change container layout (stacked, tabbed, toggle split)
bindsym $mod+Cyrillic_shorti layout stacking
bindsym $mod+Cyrillic_tse    layout tabbed
bindsym $mod+Cyrillic_u      layout toggle split

# scratchpad binds omitted, unused, and I don't want to bind the equivalent keys

# focus the parent container
bindsym $mod+Cyrillic_ef       focus parent
# focus the child container
bindsym $mod+Shift+Cyrillic_EF focus child

# new workspace
bindsym $mod+Cyrillic_de exec "swaymsg workspace number $(($(swaymsg --raw -t get_workspaces |jq -r '.[].name'|cut -d':' -f 1|sort -n| tail -1) + 1))"

# work with workspaces
bindsym $mod+Shift+Cyrillic_SHCHA         exec swaymsg rename workspace \
    $(swaymsg --raw -t get_workspaces | jq '.[] | select(.focused==true).name') \
    to \
    $(swaymsg --raw -t get_workspaces | jq '.[] | select(.focused==true).num'):$(zenity --entry --title 'Rename workspace' --text "New workspace name:")

    # TODO rewrite scripts for sway
bindsym $mod+Mod1+Shift+Cyrillic_SOFTSIGN exec "~/.config/i3/ws_main.sh"
bindsym $mod+Mod1+Shift+Cyrillic_SHA      exec "~/.config/i3/ws_new_code.sh"
bindsym $mod+Mod1+Shift+Cyrillic_ER       exec "~/.config/i3/ws_new_doc.sh"

# Lock with xscreensaver (Hyper+Alt+l)
bindsym $mod+Mod1+Cyrillic_ze  exec "pkill -x --signal SIGUSR1 swayidle"

# reload the configuration file
bindsym $mod+Shift+Cyrillic_IE reload
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
bindsym $mod+Shift+Cyrillic_KA restart
# exit i3 (logs you out of your X session)
bindsym $mod+Shift+Cyrillic_U 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'

# move all but main (1) workspace to chosen output
# (uses zenity, swaymsg, jq)
bindsym $mod+Shift+Cyrillic_SOFTSIGN exec "~/.config/sway/mv_ws.sh"

# change screen layout
mode "screenlayout" {
    bindsym $mod+Cyrillic_i mode "default"
    bindsym $mod+Cyrillic_shcha mode "resize"
}

mode "resize" {
    bindsym Cyrillic_o  resize shrink width 10px
    bindsym Cyrillic_em resize shrink height 10px
    bindsym Cyrillic_ze resize grow width 10px
    bindsym Cyrillic_es resize grow height 10px

    bindsym $mod+Cyrillic_i mode "default"
    bindsym $mod+Cyrillic_shcha mode "resize"
}

bindsym $mod+Cyrillic_shcha mode "resize"
bindsym $mod+Cyrillic_i     mode "screenlayout"

#Toggle touchscreen/touchpad
bindsym $mod+Shift+Cyrillic_ZHE exec ~/.config/sway/toggle_ts.sh
bindsym $mod+Shift+Cyrillic_EL  exec ~/.config/sway/toggle_tp.sh

# Toggle 'disable touchpad while typing'
# force reload waybar to update the custom/dwt module (TODO find a better way)
# Ideally I could send a IPC message to waybar or something
bindsym $mod+Shift+Cyrillic_be exec "~/.config/waybar/dwt/toggle_dwt.sh; killall -SIGUSR2 waybar"

Extra stuff for Surface Go

External display, using Remarkable tablet as a display/input, and configuring touchscreen(s).

Listing 3: ~/.config/sway/config.local##o.Linux,h.devil
bindsym XF86PowerOff exec wlogout --protocol layer-shell

output eDP-1 scale 1.5
output DP-1 mode 1920x1080 scale 1.5 transform 90

# Headless output for remarkable vnsee
mode "screenlayout" {
    # create_output can't be undone, so we won't make it automatically
    bindsym 8 exec swaymsg create_output
    bindsym 9 output HEADLESS-1 res 1404x1872 scale 2
    bindsym F11 exec pkill -f 'wayvnc -o HEADLESS-1'
    bindsym F12 exec wayvnc -o HEADLESS-1 -f 10 $(ip -4 a s enx72d0c9160557 |grep -Po "inet \K[0-9.]*")
}

# Surface Go Display touch/stylus
input 1267:9754:ELAN9038:00_04F3:261A map_to_output eDP-1
input 1267:9754:ELAN9038:00_04F3:261A_Stylus map_to_output eDP-1

# MageDok 12" touch/stylus
input 7062:3843:N-trig_DuoSense map_to_output DP-1
input 7062:3843:N-trig_DuoSense_Mouse map_to_output DP-1
input 7062:3843:N-trig_DuoSense_Stylus map_to_output DP-1

# MageDok T089A Pro touch
input 8746:1:ILITEK_ILITEK-TP map_to_output DP-1

Helper utilites

dmenu

I tried wofi as a rofi clone for Wayland, but it was impressively slow at finding things in the path so I went back to dmenu. I read about bemenu as a Wayland alternative to dmenu, but it wasn't packaged in Debian at the time. Fuzzy fonts are annoying, but the functionality keeps me using dmenu.

waybar

swaybar works reasonably well with i3status, but for some reason I can't interact with the systray applications. I also had an issue with pasystray displaying correctly at all.

So I went to waybar. Configuration takes a bit, but it was capable of duplicating my i3status setup and adding functionality. I also found some features quite useful on mobile devices that I wouldn't normally use on desktop. The only annoyance is workspace numbers (used for switching to specific workspace) are hidden. I think a patch is in order to make them optional. TODO

Listing 4: ~/.config/waybar/config
{
    "position": "bottom",
    "height": 24,
    "spacing": 0,
    "modules-left": ["sway/workspaces", "sway/mode"],
    "modules-right": ["disk", "disk#home", "network", "battery", "cpu", "pulseaudio", "clock", "idle_inhibitor", "custom/dwt", "custom/osk", "custom/jgmenu", "backlight", "tray"],
    // Modules configuration
    "sway/workspaces": {
        "all-outputs": false,
        "format": "{name} {icon}",
        "format-icons": {
            "beauty": "1",
            "urgent": "",
            "focused": "",
            "default": ""
        },
        "enable-bar-scroll": true,
        "smooth-scrolling-threshold": 3,
        "on-click-middle": "swaymsg workspace number $(($(swaymsg --raw -t get_workspaces |jq -r '.[].name'|cut -d':' -f 1|sort -n| tail -1) + 1))"
    },
    "disk": {
        "path": "/",
        "format": "/ {free}"
    },
    "disk#home": {
        "path": "/home",
        "format": "~ {free}"
    },
    "cpu": {
        "format": "{load}"
    },
    "idle_inhibitor": {
        "format": "{icon}",
        "format-icons": {
            "activated": "",
            "deactivated": ""
        }
    },
    "tray": {
        "icon-size": 15,
        "spacing": 2
    },
    "clock": {
        "format": "{:%a %F %T}",
        "interval": 15,
    },
    "battery": {
        "states": {
            "good": 95,
            "warning": 30,
            "critical": 10
        },
        "format": "{capacity}% {icon}",
        "format-charging": "{capacity}% ⚡",
        "format-plugged": "{capacity}% ",
        "format-alt": "{time} {icon}",
        // "format-good": "", // An empty format will hide the module
        // "format-full": "",
        "format-icons": ["", "", "", "", ""]
    },
    "network": {
        // "interface": "wlp2*", // (Optional) To force the use of this interface
        "format-wifi": "{ipaddr} ({signalStrength}%)",
        "format-ethernet": "{ipaddr}/{cidr} 🖧",
        "tooltip-format": "{ifname} {gwaddr} 🖧",
        "format-linked": "{ifname} (No IP) 🖧",
        "format-disconnected": "Disconnected ⚠",
        "format-alt": "{ifname}: {ipaddr}/{cidr}"
    },
    "pulseaudio": {
        "on-scroll-down":  "pactl set-sink-volume 0 +1%",
        "on-scroll-up":  "pactl set-sink-volume 0 -1%",
        "format": "{icon} {volume}% {format_source}",
        "format-bluetooth": "{icon} {volume}% {format_source}",
        "format-bluetooth-muted": "🔇 {icon} {format_source}",
        "format-muted": "🔇 {format_source}",
        "format-source": " {volume}% ",
        "format-source-muted": "",
        "format-icons": {
            "headphone": "",
            "hands-free": "",
            "headset": "",
            "phone": "",
            "portable": "",
            "car": "",
            "default": ["🔈", "🔉", "🔊"]
        },
        "on-click": "pactl set-sink-mute 0 toggle",
        "on-click-right": "pavucontrol"
    },
    "backlight": {
        "format": "{icon} {percent}%",
        "format-icons": ["", ""],
        // -n to prevent going black without external brightness controls
        // scrolling is natural
        "on-scroll-down":  "brightnessctl s +1%",
        "on-scroll-up":  "brightnessctl -n s 1%-",
        "on-click": "brightnessctl -n s 10%-",
        "on-click-right": "brightnessctl s +10%"
    },
    "custom/osk": {
        "format": "{icon}",
        "format-icons": ["⌧", "⌨"],
        "exec": "$HOME/.config/waybar/osk/status.sh",
        "return-type": "json",
        // TODO just this interval sucks
        // Wish I could trigger updates when the set of input devices changes
        "interval": 5,
        "exec-on-event": true,
        // TODO don't like these device specific things here
        "exec-if": "! lsusb -d 045e:096f",
        "on-click": "$HOME/.config/waybar/osk/toggle_visible.sh",
        "on-click-right": "$HOME/.config/waybar/osk/toggle_enable.sh"
    },
    "custom/dwt": {
        "format": "{icon}",
        "format-icons": ["▢"],
        "exec": "$HOME/.config/waybar/dwt/status.sh",
        "return-type": "json",
        "interval": 600,
        "exec-on-event": true,
        // TODO don't like these device specific things here
        "exec-if": "lsusb -d 045e:096f",
        "on-click": "$HOME/.config/waybar/dwt/toggle_dwt.sh"
    },
    "custom/jgmenu": {
        "format": "{icon}",
        "format-icons": ["☰"],
        "on-click": "jgmenu"
    }
}
Listing 5: ~/.config/waybar/style.css
* {
    font-family: Hack, FiraCode, Symbola, DejaVu Sans Mono;
    font-size: 10px;
}

window#waybar {
    background-color: #1B1D1E;
    color: #E3E3DD;
    transition-property: background-color;
    transition-duration: .5s;
}

window#waybar.hidden {
    opacity: 0.2;
}

#workspaces button {
    padding: 0 0 0 4px;
    background-color: #1B1D1E;
    color: #E3E3DD;
    /* Use box-shadow instead of border so the text isn't offset */
    box-shadow: inset 0 -3px #1B1D1E;
    /* Avoid rounded borders under each workspace name */
    border: none;
    border-radius: 0;
}

/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
#workspaces button:hover {
    background: #333333;
    box-shadow: inset 0 -3px #E3E3DD;
}

#workspaces button.visible {
    color: #56ADBC;
    background-color: #333333;
}

#workspaces button.focused {
    color: #1B1D1E;
    background-color: #66D9EF;
    box-shadow: inset 0 -3px #666666;
}

#workspaces button.urgent {
    color: #333333;
    background-color: #FA9429;
}

#mode {
    background-color: #FA9429;
    color: #333333;
    border-bottom: 3px solid #E3E3DD;
}

#clock,
#battery,
#cpu,
#disk,
#network,
#pulseaudio,
#tray,
#backlight {
    padding: 0 4px 0 4px;
    border-right: 1px solid #64727D;
    color: #E3E3DD;
}

#battery.plugged { }

#battery.charging {
    color: #1B1D1E;
    background-color: #2AD043;
}

@keyframes blink {
    to {
        background-color: #E3E3DD;
        color: #F8F8F2;
    }
}

#battery.critical:not(.charging) {
    background-color: #C4265E;
    color: #F8F8F2;
    animation-name: blink;
    animation-duration: 0.5s;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-direction: alternate;
}

label:focus {
    background-color: #F8F8F2;
}


#network.disconnected {
    background-color: #FFBA68;
    color: #333333;
}


#pulseaudio.muted {
    background-color: #333333;
    color: #E3E3DD;
}


#tray > .passive {
    -gtk-icon-effect: dim;
}

#tray > .needs-attention {
    -gtk-icon-effect: highlight;
    background-color: #C4265E;
}

#custom-osk,
#idle_inhibitor,
#custom-jgmenu,
#custom-dwt {
    padding: 0 8px 0 8px;
    color: #E3E3DD;
    background-color: #333333;
}

#custom-osk,
#idle_inhibitor,
#custom-jgmenu,
#custom-dwt, 
#backlight {
    box-shadow: inset 0 3px #6A7EC8;
}

#custom-osk.activated,
#idle_inhibitor.activated,
#custom-dwt.activated {
    background-color: #E3E3DD;
    color: #333333;
}

swayidle

Daemon for executing swaylock and shutting off displays on idle timers.

Listing 6: ~/.config/swayidle/config
timeout 900 'swaylock'
timeout 930 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"'
timeout 15 'if pgrep -x swaylock; then swaymsg "output * dpms off"; fi' resume 'swaymsg "output * dpms on"'
before-sleep 'swaylock'

swaylock

Daemon for locking Wayland session.

Listing 7: ~/.config/swaylock/config
daemonize
ignore-empty-password
color=1B1D1E
image=~/.wallpapers/rivulets_by_kuzy62-d8rbpyq.jpg
indicator-radius=100
indicator-thickness=30
ring-color=66D9EF
key-hl-color=FA9429

rot8

Automatic rotation for wayland compositors. I just added it to my autostart list and it works.

https://github.com/efernau/rot8

wlogout

After disabling systemd handling the power switch I bound XF86PowerOff to run wlogout. Gives quick touch access to lock, suspend, shutdown, and reboot.

It could use a button for 'cancel', and I need to prevent it from running multiple instances. TODO

mako

Notifications daemon. Pretty basic. I just set some styling and a timeout since notifications are only useful in the moment to me.

Listing 8: ~/.config/mako/config
font=Hack 12
text-color=#66efd5
background-color=#48483e
border-color=#fc981f
default-timeout=10000

wtype

Substitute for xdotool, but with different syntax. I mostly use it for fusuma sending key combos for touchpad gestures. Might be unnecessary as I've seen that fusuma can do its own sendkey now.

Scripts

Lots of my i3 scripts were for doing things with layouts, but sway is unlikely to get this feature. That sucks.

I can probably still manage a lot of my layouts manually, but I don't think there's a good way to do my main workspace's arbitrary split.

TODO

Handling environment variables

Previously I used ~/.profile for setting environment variables in X.

With Wayland the best way to do it on a user file level seems to be ~/.pam_environment, but this isn't enabled by default. There are some security implications to consider: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989919#20

To enable it I modified /etc/pam.d/common-session since it seems to be included in most other pam configs. It was suggested that pam_env.so be loaded last, but common-session often gets loaded before keyring modules, and common-password. In any case I added it at the end before the final comment. It looks like:

Listing 9: /etc/pam.d/common-session (excerpt)
session required    pam_env.so user_readenv=1
# end of pam-auth-update config

I just put all KEY=​VALUE entries one per line in ~/.pam_environment. Now any session that loads common-session should get those environment variables.

Modifying PATH

TODO

Slow GTK app startup

Add exec systemctl --user import-environment to sway config. https://github.com/swaywm/sway/issues/5732

Kitty or Alacritty (urxvt replacement)

Kitty is mostly good. Fonts look right, and many comparable features as a urxvt replacement. However it completely lacks scroll bars. The key combos for scrolling are useless on compact keyboards.

Kitty also doesn't update windows titles reasonably. All my windows just say 'bash'. I found out vim requires 'set title' in it's config to set titles in a way that will update properly.

Alacritty is unfortunately is very comparable to Kitty. It lacks scrollbars. Key combos are a little better. Configuration (live reload) is convenient and wasn't too hard to set up how I prefer.