The Autodidacts

Exploring the universe from the inside out

Zen and the Art of Yak Shaving: Switching From i3 to Sway on Ubuntu 20.04

When I upgraded from Ubuntu 18.04 to 20.04 LTS, I finally took the plunge and switched from the i3 window manager on X11 to Sway, an almost drop-in Wayland replacement. Here's my experience of the transition.

Here be Dragons

Here Be Dragons

Tiling window managers are not for the faint of heart. On top of that, Wayland and Sway are newer technologies than X11 and i3, and in my experience less likely to just work™. But for those of you who:

  1. Already have a keyboard-driven workflow, or want to switch to one,
  2. Want to be able to customize your desktop environment and workflow endlessly (in both senses of the word), and
  3. Aren't afraid of building (most) packages from source

… this article might make the switch from i3 to Sway slightly quicker and more pleasant!

Installing Sway

Sway is at last in the Ubuntu repos, and installing it is as easy as:

sudo apt install sway

The version in the repositories worked alright, but it had two bugs that had been fixed in the master branch: it failed to refocus the keyboard on the previous window after interacting with a popup, and it crashed when wtype was run (due to an issue with virtual keyboard grouping). After procrastinating as long as I could, I built Sway 1.5 rc2 from source, which resolved both issues.

Waybar

I spent a while hacking away at a custom statusline script, with underwhelming results. Eventually I abandoned it and installed Waybar, a more full-featured Sway bar written in C++:

sudo apt install waybar

I didn’t manage to find the FontAwesome package that it depends on, but that was just as well, because I didn’t want the icons anyway. I just edited my Waybar config, and removed all the icons that didn’t display properly.

Other than that, I left the Waybar config mostly default, only removing the stuff I didn't need, and adding a more usable time and date widget. I also removed the garish background colours on the different widgets. The end result, while far from gorgeous, is functional and non-offensive:

waybar

Making Waybar Space-Efficient

In my i3 config, I had mod+n bound to toggle i3bar visibility:

bindsym $mod+n bar mode toggle

To replicate that with Sway and Waybar:

bindsym $mod+n exec killall -SIGUSR1 waybar

Launcher Woes

My entire workflow revolves around my app launcher, which I use to launch apps (duh), find files, calculate things, control my system, and occasionally run commands. I used Gnome Do, which is blazingly fast, and supports fuzzy search. I summon Do with ctrl+spacebar, and then have access to pretty much everything I have used even remotely recently with 2-5 keypresses.

Sadly, Gnome Do hasn't been updated or maintained since 2009. It still worked on Ubuntu 18.04 on X11, but to my great disappointment it is not in the Ubuntu 20.04 repositories. Also, it is an X app.

Albert

Sway Desktop with Albert Summoned

In the past, I have also tried Synapse, Albert, Kupfer, Rofi, and dmenu. Albert does not support Wayland, and I have had trouble getting it to even work previously, but it’s also one of the more powerful and actively maintained, and is the closest thing to a drop-in replacement for Gnome Do. I read about people running it on Wayland, even though it doesn’t officially support it, so I decided to give it a shot.

Getting to work turned out to be more arduous than expected, and involved a lot of time head-scratching about why it was having segmentation faults. I eventually got it working by installing the wayland-crash-fix branch of johanhelsing's fork in lieu of the official version. Here is the script that I cobbled together to successfully install it:

#!/bin/bash

pwd=$PWD

sudo apt update
sudo apt install --no-install-recommends -y cmake g++ libmuparser-dev libqt5charts5-dev libqalculate-dev libqt5svg5-dev libqt5x11extras5-dev python3-dev qtbase5-dev qtdeclarative5-dev unzip virtualbox wget libqt5sql5-sqlite

# git clone https://github.com/albertlauncher/albert.git
git clone -b wayland-crash-fix https://github.com/johanhelsing/albert/ wayland-crash-fix
# cd $pwd/albert
cd $pwd/wayland-crash-fix
git clone https://github.com/albertlauncher/plugins.git
# cd $pwd/albert/plugins/python
cd $pwd/wayland-crash-fix/plugins/python
git clone https://github.com/pybind/pybind11.git
mkdir $pwd/albert-build
cd $pwd/albert-build
# cmake ../albert -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug
cmake ../wayland-crash-fix -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug
make
sudo make install

However, once installed, you're still not quite done. To get it not to crash (segfault) when summoned, it you have to set the following environment variables somewhere where Albert can find them: QT_QPA_PLATFORM=xcb and DISPLAY=:0. To start Albert on boot, I have the following in my Sway config:

exec sh -c "export QT_QPA_PLATFORM=\"xcb\" && export DISPLAY=:0 && /usr/bin/albert"

And to set the hotkey:

bindsym ctrl+space exec '/usr/bin/albert toggle'

Caveat: while Albert now works on Wayland, can find my files, and is fast to summon, it still isn't as good as Gnome Do. It is quite slow to start up, which means I have to launch the first few apps I use with dmenu, while waiting for it; it is strangely slow to open some files (LibreOffice files); and when indexing a lot of files, it is a real memory hog: when idle, it can sit on up to ~680MB of RAM. This sucks, but since it took so long to get it working at all, and I don't have any usable alternative, I'm willing to live with it for now. If I start doing something that's going to hog a lot of RAM, I quit Albert, and drop back to dmenu.

Kupfer

Kupfer
Rocking the Windows 98 look

After writing the above section about Albert, I Googled Kupfer to make sure I had the spelling right. I couldn't remember what exactly I had disliked about it when I tried it years ago, but I noticed that it was in the Ubuntu repositories. I thought it was a KDE app (it isn’t), so I assumed it would crash on Wayland like most things do, but installed it anyway just in case it worked:

sudo apt install kupfer

To my surprise, it launched without incident. No environment variables, no coddling, no building from branches of forks of the source code. It just ran on Wayland. To my even greater surprise, it found this file without having to manually add folders to its index, and then add exclusions so that it wouldn't slow down my computer indexing too many files. However, Kupfer doesn’t seem quite a snappy as Albert, and its quirks are different: after using it for a few days, I switched back to my baling-twine-and-elastic build of Albert.

Note: Though it is in the Ubuntu 20.04 repositories, the last Kupfer release was over three years ago, so it may not be a long term solution — but then again, I cheerfully used Gnome Do for ten years after its last release in 2009.

More fun with Segmentation Faults

One of my favourite i3 shortcuts was this hideous line:

bindsym control+semicolon exec date '+%Y-%m-%d' | tr -d "\n" | xsel -i -b && xdotool sleep 0.5 key "ctrl+v"

This was a hacky way to put the current date on the clipboard and paste it. (I tried less hacky ways and they didn't work; but at the time I wrote this snippet I barely knew what a pipe was…) Porting this tiny snippet over to Wayland took more time than anything else in my config.

ydotool

My first attempt, after some initial fiddling with wl-copy and wl-paste from wl-clipboard — notice the ominous first letter of xsel — involved ydotool, the Wayland equivalent of xdotool.

To install ydotool I had to build it from source, which was fairly straightforward using the provided instructions. Its dependencies? Less so. I installed libevdevPlus from a .deb, and did the same for libuInputPlus. However, the latest version of ydotool (which I was hoping wouldn't segfault) required newer versions of these dependencies, which had to be built from source. I didn’t find any instructions, so I used the commands listed in the GitLab Continuous Integration YAML files. I also had to install the following:

sudo apt install libboost-program-options-dev

However, when I tried to use ydotool for my snippet, I discovered that a) the daemon segfaults mysteriously, and b) it needs to be run as root. So the only way to get it to work (adding it to sudoers, or modifying the permissions of /dev/uinput) would have kind of nullified the main (only?) benefit of Wayland: security.

In the end, none of it got me closer to my goal, but it did mean that I had a working and up-to-date version of ydotool, in case I ever need it. (The daemon is another story, and a very unpleasant one, too!)

wtype

After making a fool of myself on the #sway IRC channel, and getting help from the helpful danschick and emersion, I ended up with the following snippet:

bindsym control+semicolon exec sh -c "wtype `date '+%Y-%m-%d'`"

As mentioned above, there is a bug in the version of Sway that's available in the Ubuntu repos — which has now been fixed in master — which causes wtype to crash Wayland windows as soon as it is run. But if you build Sway from the master branch, this snippet works, and is the most correct, secure, Wayland equivalent of the monstrosity above.

To install wtype, which must be built from source, like so many other Wayland things:

git clone https://github.com/atx/wtype
cd wtype-master
sudo apt install meson
meson build
ninja -C build
sudo ninja -C build install

There is, unfortunately, one remaining caveat: it only works on Wayland windows. If you hit the keybinding when an Xwayland window is focused, it will produce gibberish. This is the result not of a bug in wtype, but a limitation of X. The silver lining is that if incentivises getting other apps (like Firefox) to run natively on Wayland, rather than running them on Xwayland. (Firefox works pretty well, if you set the necessary environment variables: MOZ_ENABLE_WAYLAND=1 and GDK_BACKEND=wayland.)

Screenshots

If you're used to hitting the print screen button and having something happen, think again. Wayland / Sway doesn't have that built in. However, it's easy to set up. I installed the necessary tools with:

sudo apt install slurp grim notify-send jq wl-clipboard

Then, grab the grimshot script from https://github.com/swaywm/sway/blob/master/contrib/grimshot and put it in ~/.config/sway/grimshot. Then you can put a line in your sway config like this:

bindsym Print exec sh -c "env XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR SWAYSOCK=$SWAYSOCK bash ~/.config/sway/grimshot copy active"

This puts a screenshot of the active window on the clipboard. (If you want obnoxiously cheerful audio feedback, add this to the end of the command: && aplay /usr/share/sounds/sound-icons/trumpet-12.wav)

I thought of binding other more sophisticated screenshot stuff to other combinations of Print Screen on control or shift, but for now I just have that one binding, and in the event I want to grab an area of the screen (and it’s not a browser window) I run grimshot from the command line. I also didn't want to be to silently and automatically saving screenshots on a single keypress, since I never get around to sorting screenshots that I save. A bit of friction can be a good thing!

Swaylock

You will probably want to install Swaylock and Swayidle with:

sudo apt install swaylock swayidle

I have mine setup like so in my Sway config:

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'

(As far as I recall I just uncommented the example snippet.)

Swaylock is … delightfully minimal, but works as expected — and doesn't force you to focus a field before typing, which is a major plus.

Input configuration

If you're like me, natural scrolling is a must. I enabled that with this snippet:

   input "2:14:SynPS/2_Synaptics_TouchPad" {
       dwt enabled
       tap enabled
       natural_scroll enabled
       middle_emulation enabled
   }

This snippet is in the default Sway config. I just uncommented it and changed 2:14 to what I got when I ran swaymsg -t get_inputs (in my case, 2:7).

$SWAYSOCK

I had issues with the $SWAYSOCK environment variable not being set / available. I have the following line in my .bashrc, which seems to have fixed the problem:

export SWAYSOCK=/run/user/$(id -u)/sway-ipc.$(id -u).$(pgrep -x sway).sock

Install Redshift on Wayland

My favourite screen colour temperature adjustment tool doesn’t work out of the box on Wayland. But there's a fork which does. To install it, I ran:

sudo apt install autopoint autoconf intltool libtool
git clone -b wayland https://github.com/minus7/redshift.git
cd redshift
./bootstrap
./configure
make
sudo make install

And then added the following to my Sway config:

exec redshift-gtk

It turned out that this didn't actually work. It would start, but wouldn't adjust the colour temperature successfully. Now, I have this line:

exec redshift -m wayland

I still haven't gotten the applet (redshift-gtk) to work on Wayland, but that's not a huge deal.

Wayland Clipboard Support in Vim

If you’re used to copying to the system clipboard from Vim, you will notice that "+y doesn't work under Wayland. I put the following snippet in my .vimrc to use wl-copy to replicate this functionality:

" Wayland Clipboard Support
xnoremap "+y y:call system("wl-copy", @")<cr>
nnoremap "+p :let @"=substitute(system("wl-paste --no-newline"), '<C-v><C-m>', '', 'g')<cr>p
nnoremap "*p :let @"=substitute(system("wl-paste --no-newline --primary"), '<C-v><C-m>', '', 'g')<cr>p

Note: wl-clipboard must be installed for this snippet to work.

Making it possible to run graphical applications with sudo

If you’re used to running sudo gedit or sudo nautilus on Ubuntu, you will discover that these fail on Wayland. Here's the solution I ended up using:

Create a file called wsudo.sh (or some such) wherever you store your little utility scripts. Paste the following into it, courtesy of this Reddit thread:

#!/bin/bash
#small script to enable root access to x-windows system
xhost +SI:localuser:root
sudo $1
#disable root access after application terminates
xhost -SI:localuser:root
#print access status to allow verification that root access was removed
xhost

Make it executable with chmod +x /path/to/wsudo.sh.

Then, make an alias for it in your .bashrc like so: alias wsudo='bash /path/to/wsudo.sh'

And reload your bashrc with source ~/.bashrc

Now, you can run graphical apps with wsudo, the way you used to using regular sudo.

More Fun Keybindings

Here are a few other snippets from my config:

# Make Alt+F4 work like usual
bindsym Mod1+F4 kill

# Maps over to Windows nicely, which means that I don't look incompetent when I try to use a PC :)
# Split has been mapped to $mod+s, since I never really used stacked layout.
bindsym $mod+e exec nautilus --new-window

# Reload the Sway configuration file with the same keybinding I had in i3
bindsym $mod+Shift+r reload

# Make Lenovo ThinkPad T430 audio buttons work
bindsym XF86AudioRaiseVolume exec "amixer -q sset Master,0 1+ unmute"
bindsym XF86AudioLowerVolume exec "amixer -q sset Master,0 1- unmute"
bindsym XF86AudioMute exec "amixer -q sset Master,0 toggle && amixer -q sset Speaker,0 toggle"
bindsym XF86AudioMicMute exec "amixer set Capture toggle"

# 1. Set right alt as the compose key, so I can type em-dashes, ellipses, and special characters
# 2. Disable caps lock so it can be used for window switching
input * {
  xkb_options compose:ralt,caps:none
}

# Alt tab script
# from: https://gist.github.com/SidharthArya/f4d80c246793eb61be0ae928c9184406
# remember to chmod +x ~/.config/sway/alttab
# Keycode 66 is caps lock. Caps lock is disabled up above, so we have to use the keycode instead of the name
bindcode 66 exec swaymsg [con_id=$(swaymsg -t get_tree | ~/.config/sway/alttab t)] focus
# Keep normal Alt+Tab behaviour since I haven't retrained my fingers to use caps lock exclusively.
bindsym Mod1+tab exec swaymsg [con_id=$(swaymsg -t get_tree | ~/.config/sway/alttab t)] focus
bindsym Mod1+shift+tab exec swaymsg [con_id=$(swaymsg -t get_tree | ~/.config/sway/alttab f)] focus

Conclusion

xkcd #963
xkcd #963

When I switched, I knew absolutely nothing about Wayland other than the most obvious hand-wavey stuff — despite being a long-time Linux user. I have now been using Sway for three months, and have no plans to switch back.

Even now, I know vanishingly little about Wayland internals and other Sway things that haven’t directly caused an error that I had to debug. This guide, therefore, is more like a series of tree blazes made by a half-delerious explorer than the precise work of a cartographer. While I wouldn’t necessarily recommend the blind-adventurer approach that I took, it has its charms.