Unfortunately (or fortunately depending on your opinion - keep reading...) this script is of questionable value in Windows 11 since they neutered the taskbar (generally). I did test when the windows 10 insiders build had full wslg support and everything worked fine, but the windows 11 taskbar is now unrecognizable from that build and there is currently no way to add the toolbar in the way which this project expects.
However as of Windows 11, this script is not actually required. If you run powertoys, you can enable Powertoys Run and use alt+space. Your GUI apps from your WSL installs will have shortcuts there with your distribution name in brackets as you launch them and you won't need to go looking for them in the traditional tree-based structure. Thanks to the new Windows 11 WSLG support, it should "just work" without any display magic or third party X11 servers.
Note you may wait for the Windows indexer to refresh after you install a new app, but it will get there eventually automatically.
This script will create a Windows toolbar launcher for an underlying WSL install which can be used to fire up linux native applications directly from Windows via the standard Windows toolbar, like this:
It's particularly cool because WSL 2 is coming which is unlocking unprecedented performance and compatibility improvements, so this will literally bring the full suite of Linux GUI applications directly to Windows UI.
The script expects to be run within the WSL execution environment with:
wsl.exe -- source ~/.bashrc ; xterm
).
If this fails, check your DISPLAY
variable (more details in troubleshooting).And optionally (but recommended):
pip3 install cairosvg
). This will allow you to convert .svg
based icons.sudo apt install imagemagick
/ dnf install imagemagick
etc). This will allow you to have
an additional opportunity to convert appropriate icon files if other methods fail.To install:
pip3 install wsl-windows-toolbar
To run:
wsl-windows-toolbar
After installation, right click on your toolbar, go to
Toolbars -> New toolbar...
and select
%USERPROFILE%\.config\wsl-windows-toolbar-launcher\menus\WSL
as the target folder (unless
you selected an alternative directory).
Note there are many options available with --help
if you'd prefer to use alternative locations.
If new software has been installed in the WSL environment, simply run the script again from the WSL environment to pick the new GUIs up.
Notable changes:
wsl-windows-toolbar
without the trailing .py
.$ python wsl-windows-toolbar.py --help
Usage: wsl_windows_toolbar.py [OPTIONS]
Options:
-i, --install-directory PATH Install the launchers here [default:
/c/Users/$USER/.config/wsl-windows-toolbar-
launcher/metadata]
-m, --metadata-directory PATH Install any metadata here [default:
/c/Users/$USER/.config/wsl-windows-toolbar-
launcher/metadata]
-d, --distribution TEXT WSL Distro to generate shortcuts for
[default: $WSL_DISTRO_NAME]
-u, --user TEXT WSL Distro's user to launch programs as
[default: $USER]
-y, --confirm-yes Assume the answer to all confirmation
prompts is 'yes' [default: False]
-f, --menu-file FILENAME The *.menu menu file to parse [default:
/etc/xdg/menus/gnome-applications.menu]
-w, --wsl-executable TEXT Path to the WSL executable relative to the
windows installation [default:
C:\Windows\System32\wsl.exe]
-n, --target-name TEXT Name to give to the created installation
(will be displayed in toolbar menu)
[default: WSL]
-t, --preferred-theme TEXT Preferred menu theme to use [default:
Adwaita]
-T, --alternative-theme TEXT Alternative menu themes to consider (pass
multiple times) [default: Papirus,
Humanity, elementary-xfce]
-j, --jinja-template-batch FILENAME
Optional Jinja template to use instead of
the inbuilt default (advanced users only)
-J, --jinja-template-shell FILENAME
Optional Jinja template to use instead of
the inbuilt default (advanced users only)
-r, --rc-file FILENAME Optional rc file to source prior to
launching the command instead of ~/.bashrc
-D, --launch-directory DIRECTORY
Optional default linux path to open
applications relative to (defaults to ~)
--help Show this message and exit.
The launcher process is fairly broken down to separate responsibilities and allow customizations at several layers. It looks like this:
lnk -> vbscript (sometimes) -> bat -> wsl bash -> app
The .lnk
is the shortcut with the icon etc. The vbscript exists only to launch the batch file
without a terminal window appearing. The batch file bootstraps the wsl bash script using wsl.exe
which in turn (finally) launches the app. It may seem convoluted but I have found this is the
easiest way to break it down to allow flexibility and ease of maintenance at each layer.
Note the vbscript is only called if run_in_terminal
is set to false (as it tends to be for most
applications). The templates which define the batch and bash files are used may be overridden
by -j
and -J
respectively, though you shouldn't usually need to override this behaviour.
The default templates used are wsl-windows-toolbar-template.bat.j2
and
wsl-windows-toolbar-template.sh.j2
. The following possible variables passed
through from the script:
distribution
: The distribution selected in the scriptuser
: The user selected in the scriptcommand
: The individual command for each launcher entry in WSL environment (e.g. xterm
)wsl
: The wsl executable discoveredrcfile
: The rc file (e.g. .bashrc
) to source prior to launch selected in the scriptlaunch_script
: The path of the linux launcher scriptexec_dir
: The directory in which this command will be run (linux path)run_in_terminal
: Boolean specifying whether or not this app expects to run in a terminalIf no applications are launching at all, it's most likely an issue with either:
DISPLAY
not being set correctlyDISPLAY
being set fine, but its destination is not accessible from the WSL environmentNote that for this section, you can check which version of WSL you're using with:
wsl.exe -l --verbose
$DISPLAY
variableIf you're running WSL1, the DISPLAY
variable for WSL1 should simply be localhost:0.0
if this is the default distribution.
$DISPLAY
variableUnfortunately for WSL2, it's a little more complicated for now, though I think they're planning on fixing this. You'll need something like this to extract the correct host:
export DISPLAY=$(grep -m 1 nameserver /etc/resolv.conf | awk '{print $2}'):0.0
Then you need to worry about the firewall. WSL comes up as a public network, but I wouldn't recommend allowing all public network traffic to access your X server. So instead, you can go ahead and select defaults when this sort of prompt comes up:
Now, irritatingly this will actively add a block rule (rather than simply not add an allow rule) for public networks which you will need to disable for the next step by going into Windows Defender Firewall -> Inbound Rules and disabling this block rule for TCP on the Public Network.
If you don't do the above step, the Block rule will take precedence over the Allow allow rule and you won't get through.
Now, right click on Inbound Rules and select New Rule...
, select TCP port 6000 (most likely, but verify with display number / X11 server documentation before continuing) and select defaults. This
will open up your public network for this port... which is also not what you want. What you want is to only allow traffic
from the WSL subnet. So refresh the list, scroll to your recently created name, right click and go to properties. Now
under Scope
, go to Remote IP address, Select These IP addresses
and add in 172.16.0.0/12
to limit the subnets
which can access this port to the WSL subnet. It should look something like this:
Alternatively you could just disable the entire firewall for WSL, but that adds a firewall warning that constantly irritates me:
powershell.exe -Command "Set-NetFirewallProfile -DisabledInterfaceAliases \"vEthernet (WSL)\""
Does the application use dbus? If so, it's recommended to put something like this in your .bashrc
to satisfy the many
applications which depend on dbus to function:
dbus_status=$(service dbus status)
if [[ $dbus_status = *"is not running"* ]]; then
sudo service dbus --full-restart
fi
Also check that the .bashrc
tweaks are added before any nastiness like this in your .bashrc
which would prevent DISPLAY
from being set:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
You can do similar with docker
or any other service which you will need access to, but won't necessarily already be
running in a vanilla WSL installation.
To debug further, you can run the shortcut directly from the command line from a cmd
shell:
wsl.exe -d <your-wsl-distro> -u <your-wsl-user> -- source ~/.bashrc ; env; xterm
Replacing xterm with whatever command you're trying to launch. Note the env
command will
print out all environment variables set before running xterm
in this example, so this should
help you double check if DISPLAY
is really set correctly.
Issues may be raised in github issues. Before raising an issue though:
If an issue is to be required, please prepare the log output from the command and details on your
execution environment. Ideally try and find the .desktop
file relating to the failing software as well.