Working on Windows

February 2019 ยท 5 minute read

Recently, I decided to move back to Windows for my day-to-day work. As a Linux enthusiast, it wasn’t an easy decision and frankly I dislike a lot of things about the Windows ecosystem. I’m very accustomed to using terminals, vim, i3, yadda yadda. Despite all that, I made the move anyway.

Thankfully, Windows now has a Linux subsystem (Windows Subsystem for Linux), so I was able to get my favorite distro set up, copy over my dotfiles and scripts, and get to work…kind of.

I’ve long hated Windows’ cmd.exe - it’s 20+ years behind what is available on Linux. It has many quirks and I’m not comfortable with it.

As an alacritty convert from uxrvt, I set off with a goal of getting it working along with i3.

“Package Management”

Windows handles OS updates on its own, and that’s all fine and dandy. However, there’s no built-in standard for updating applications/SDKs/etc that users might install manually.

Fortunately, it’s 2019 and we’ve got things like NuGet, Chocolatey, and my personal favorite: scoop.

Scoop feels similar to a Linux package manager, but for Windows - built by the community for the community, with a wide range of default applications and support for creating your own custom set of packages.

Scoop installs apps to ~\scoop by default, which makes me happy - knowing that it’s not just installing programs all over the place.

Updating is easy as well - just scoop update * and presto.

Most of the software I use on a daily basis isn’t Windows-based, however, so let’s move on to WSL.

Windows Subsystem for Linux

WSL is actually fairly simple - support and ease-of-use has been improved quite a lot from when it first became available.

To enable it, all you have to do is enable the “Windows Subsytem for Linux” feature under “Windows Features”. Afterwards you can immediately hop in by running bash.exe or install a custom distro - there’s a nice list on GitHub.

X11 on Windows

There are few X11 servers that work properly on Windows:

- mobaxterm
- xming
- vcxsrv
- xwinlogon

I chose vcxsrv as I was already familiar with it, having used it in the past when I would work on a remote server.

To get it, either install it manually or if you’re a scoop user:

scoop install vcxsrv

Now, we can use a Real Terminal™ rather than cmd.exe.

Using a Real Terminal™

As mentioned previously, I personally prefer alacritty as my daily-use terminal. While running this through vcxsrv with WSL and no OpenGL kind of defeats the purpose… I already have it set up the way I like and thus will keep using it for now.

In order to run a GUI app, we need vcxsrv running:

vcxsrv :0 -multiwindow -nogl -keyhook

In order, the options I pass:

- `:0` - sets the display ID to 0
- `-multiwindow` - allows us to use multiple windows ON our standard
Windows desktop, rather than one giant "X11" screen with the windows embedded
- `-nogl` - disables OpenGL
- `-keyhook` - allows passthrough of the Windows key for meta-key usage

With vcxsrv running, alacritty can run:

bash.exe -c -l DISPLAY=:0 alacritty

Presto! We have a real Linux terminal on Windows.

“Automatic” Starts

I don’t like having to launch vcxsrv manually followed by alacritty, so initially I wrote a script to handle this.


Set shell = CreateObject("WScript.Shell")
shell.Run """~\scoop\apps\vcxsrv\current\vcxsrv.exe"" :0 -multiwindow -nowgl -keyhook"

args = "-c" & " -l " & """DISPLAY=:0 alacritty"""
WScript.CreateObject("Shell.Application").ShellExecute "bash", args, "", "open", 0

The caveat here was that vcxsrv tried to launch every time I wanted to open a new terminal.

I don’t like vbscript, so I decided to write a bit of code to skip launching vcxsrv if it is already running. As a non-Windows developer, I ended up searching documentation for the proper APIs - no /proc to save us here.

As a result, I ended up hacking up launchterm. Not configurable at the moment, but I will likely iterate on it slightly to give it some potential use.

Currently, I dropped the resulting binary into my %PATH% and added it to Windows’ task bar. One click and I have a new terminal ready to go.

Shell “tricks”

bash.exe passes through the current working directory which is not what I want 99% of the time. I’d rather be $HOME.

I added the following snippet to my .zshrc to cd automatically.

if [[ "$OLDPWD" == "/c/Windows/System32" || "$OLDPWD" == "/c/Users/<me>" || "$OLDPWD" == "/c/Users/<me>/Desktop" ]]; then
    cd $HOME

Users of oh-my-zsh - or potentially any shell “theme” that checks git status will want to comment that out of their theme as it’s horrendously slow under WSL.

That’s a Wrap

There’s likely a few more things for me to do, but everything pretty much works as-is once it was copied over. All of my projects build - go, clang, gcc, etc all work and I can run the odd GUI app that I need here and there. I get the benefit of my Linux-based workflow and use various Windows tools without using Wine or KVM.

It goes without saying that YMMV and this won’t be enough for everyone, but for those interested in writing both Windows and Linux software, it does the job.

alacritty running neovim