I've been using WSL 2.0 for a while now, and am happy. It's proper Linux, without all the pain of trying to merge Windows with Linux, so no more need to run VirtualBox VM's and whatnot in order to have a pure Linux experience. I've become less fussy about distros, so it's Ubuntu/Debian all the way. In any case, the "standard" way to interface with WSL is via the new Windows Terminal, which is okay'ish, but hey ... why not all the XOrg goodness too? (after all, this is real linux, right?).
To run XOrg applications (read: GUI apps), you're going to need an X Server. Your mileage may vary in respect of Windows-based X Servers, and I'm not going to pretend that I know which ones are better than others. I do know, however, that some cost money and some don't. I'm generally partial to ones that don't cost anything (funny that), that is, ones which work and don't cost anything—enter VcXsrv.
Installing VcXsrv is relatively straightforward, it's the configuring WSL to connect to it that's arguably a little tricky (these days tricky just means you can't click something and not have to worry about anything further).
Configuring DISPLAY
Unfortunately WSL doesn't magically know that you're running an X Server, nor does it know where that X Server is running (normally localhost is just fine, but not in this case).
In order to run an XOrg application, the first thing the application is going to do is try to find out how it "displays itself"; obviously there's a process for that which is no-doubt detailed in the associated man page, but in general one can point it to the right display by setting the DISPLAY environment variable (either by exporting it or by making sure that it's passed to the process that's created by the shell using a well-supported convention).
Knowing where the DISPLAY can be found is straightforward—by default, VcXsrv listens on all interfaces, so we just need to locate the WSL virtual interface. If we're using the default settings, we can assume that the WSL runtime is pointing at the Windows host as default route, so ip route should get us the details:
ip route show
default via 172.29.80.1 dev eth0 172.29.80.0/20 dev eth0 proto kernel scope link src 172.29.80.207
So, starting xeyes, for example:
DISPLAY=172.29.80.1:0 xeyes
The :0 bit is the display number; it's required.
Automatically setting DISPLAY
So ... ultimately, we'd like something clean that just figures out what that magical IP is so that we don't have to look it up each time. Currently I have something in my .zshrc that does that for me:
PEERIP=`ipconfig.exe | sed -n /WSL/,\\$p | grep IPv4 | sed -n 1p | awk -F: '{print $2}' | tr -d ' \r\n'` export DISPLAY=${PEERIP}:0.0
... now that's quite a mouthful which promises to give anyone without some Unix-fu an immediate headache. It's one way of getting at that magical IP address and popping it into a globally accessible DISPLAY environment variable. In WSL 2.0 one can call normal Windows binaries just like the Linux ones, hence a call to ipconfig.exe (the explicit .exe on the end is required to hint to WSL that "this is a Windows executable, please treat it as such and look for it in the right places").
This is all wonderful, but I still have to start with Windows Terminal, have the shell (in my case, zsh) run in order to get the DISPLAY environment variable set up. Perhaps I'd like to start everything from WSL without any Windows stuff at all?
Enter WSH
Just when you thought we were done with the TLA's, I've thrown another one in the mix (dangerously close to WSL to-boot). WSH in this case is the Windows Scripting Host, something that isn't used that often nowadays seeing as PowerShell has become the dominant means of automation in Windows-land.
In theory one could run an XOrg-based terminal (my favourite being rxvt-unicode or urxvt for short) directly without having to bounce into Windows Terminal to do it. I'd get an XOrg-based terminal, which has some fancy features like being able to view images (yes, images in a terminal).
Get to the Point Already
Yes, I mentioned WSH then promptly changed the subject. So let's wrap this up ... In order to start urxvt aka rxvt-unicode directly without first jumping into Windows Terminal and also making sure that we don't get a nasty Windows command-prompt window flashing up first (you know what I mean), we'll use a neat little WSH script. Something like urxvt.vbs (yes, the .vbs stands for VBScript [shudder]).
WScript.CreateObject("Shell.Application").ShellExecute _ "wsl.exe", _ "-e /usr/bin/zsh /home/eric/startwin.sh", _ "", _ "open", _ 0
A quick run-through of the above:
- Start a COM object ("Shell.Application") and execute a command, in this case ... wsl.exe, the command-line interface to the WSL runtime
- wsl.exe -e runs something in WSL directly, in this case a shell
- A script (startwin.sh) takes care of setting DISPLAY and explicitly running urxvt
Let's look at startwin.sh:
export DISPLAY=$(ip route show | head -1 | awk '{print $3}'):0 xrdb /home/eric/.Xresources urxvt -cd /home/eric
If you've made it this far, dear reader, without falling fast asleep, well done! You'll notice that I'm not using ipconfig.exe to get at that magical IP this time around, well because there's actually a cleaner approach, just find out what the default route is, using ip route show (that'll be the first line, making things a lot easier).
Finally, xrdb is the X resource database utility and sets things up like colors, fonts and a myriad of other things. I like my urxvt to look a certain way, so that's where that stuff is specified.
Comments !