Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WSLg, Wayland, Ubuntu 24.04, PyQt6 #12616

Open
1 of 2 tasks
hmedina opened this issue Feb 21, 2025 · 8 comments
Open
1 of 2 tasks

WSLg, Wayland, Ubuntu 24.04, PyQt6 #12616

hmedina opened this issue Feb 21, 2025 · 8 comments
Labels

Comments

@hmedina
Copy link

hmedina commented Feb 21, 2025

Windows Version

Microsoft Windows [Version 10.0.26100.3194]

WSL Version

2.4.11.0

Are you using WSL 1 or WSL 2?

  • WSL 2
  • WSL 1

Kernel Version

5.15.167.4-1

Distro Version

Ubuntu 24.04

Other Software

PyQt6 v6.8.1
python3 v3.13.2
gnome-text-editor v46.3 (46.3)

Repro Steps

About

The goal was to plot some data under Ubuntu 24, using Python3's Matplotlib, via PyQt6. A cryptic error about wayland sent me down a rabbit hole. As this dive collected bits and pieces from multiple forums and discussions, I am posting it here such that, by keyword indexing and search engines, other users can find a way forward with less searching.

This is broken into two sections: the first concerns issues with DRI3 and MESA drivers not being up-to-date in Ubuntu 24.04; once that part of the stack is working, the second part deals with Wayland configuration in WSLg.

To reproduce:

  1. In a fresh Ubuntu 24.04 machine, install python 3.13.2 and its packages PyQt6 & matplotlib
  2. Try to plot something. By default, Qt6 installs, finds, and loads a wayland plugin
  3. Cryptic error about the wayland plugin being unable to load from ""

WSL & component versions:

PS C:\WINDOWS\System32> wsl --version
WSL version: 2.4.11.0
Kernel version: 5.15.167.4-1
WSLg version: 1.0.65
MSRDC version: 1.2.5716
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26100.1-240331-1435.ge-release
Windows version: 10.0.26100.3194

MESA

According to https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps WSL should support the Wayland protocol for GUI apps. Given the contents of that tutorial, I expected it to work out of the box; this was not the case. Attempting to launch the Gnome text editor yields an error:

$ gnome-text-editor
libEGL warning: DRI3: Screen seems not DRI3 capable
libEGL warning: DRI3: Screen seems not DRI3 capable
MESA: error: ZINK: failed to choose pdev
libEGL warning: egl: failed to create dri2 screen
Couldn't open libGLESv2.so.2: libGLESv2.so.2: cannot open shared object file: No such file or directory
Aborted (core dumped)

Issues with GUI apps that mention MESA, libEGL have been reported in microsoft/wslg#1250

Installing the Ubuntu package libgles2-mesa-dev allowed the application to launch, the window to draw. The text editor was able to display submenus (e.g. about, save-as file view), save a file, and close the window. This said, the console had:

$ gnome-text-editor
libEGL warning: DRI3: Screen seems not DRI3 capable
libEGL warning: DRI3: Screen seems not DRI3 capable
MESA: error: ZINK: failed to choose pdev
libEGL warning: egl: failed to create dri2 screen

(gnome-text-editor:985): editor-document-WARNING **: 19:09:45.238: Failed to save cursor position: Setting attribute metadata::gte-cursor not supported

It seems the MESA driver on Ubuntu 24.04 is broken but there is an update from a 3rd party PPA https://askubuntu.com/questions/1516040/mesa-and-glx-errors-when-running-glxinfo-ubuntu-24-04
The current version of the MESA driver in the main Ubuntu package repo is

$ glxinfo | grep Mesa
client glx vendor string: Mesa Project and SGI
OpenGL core profile version string: 4.6 (Core Profile) Mesa 24.2.8-1ubuntu1~24.04.1
OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.2.8-1ubuntu1~24.04.1
OpenGL ES profile version string: OpenGL ES 3.1 Mesa 24.2.8-1ubuntu1~24.04.1

After updating via the PPA addition, as documented at https://itsfoss.com/install-mesa-ubuntu/ :

$ glxinfo | grep Mesa
client glx vendor string: Mesa Project and SGI
    Vendor: Mesa (0xffffffff)
OpenGL vendor string: Mesa
OpenGL core profile version string: 4.5 (Core Profile) Mesa 24.3.4 - kisak-mesa PPA
OpenGL version string: 4.5 (Compatibility Profile) Mesa 24.3.4 - kisak-mesa PPA
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 24.3.4 - kisak-mesa PPA

Now, launching the gnome text editor launches a nicer window (no extra frame around the window), and the console has:

$ gnome-text-editor

(gnome-text-editor:3003): editor-document-WARNING **: 19:44:18.935: Failed to save cursor position: Setting attribute metadata::gte-cursor not supported

However, I couldn't figure out how to resize the window; hovering the mouse cursor over the edge did not change the cursor's icon, nor did it allow the usual grab-to-resize behavior of most window management systems. However, it seems to be using DRI3 at least.

Qt6, Python, Wayland

Ok, so now at least the WSLg demo is kind of working. On to what I actually wanted to do: Qt6 & Python

Installing PyQt6 and testing a minimal sample:

$ python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()"
Failed to create wl_display (No such file or directory)
qt.qpa.plugin: Could not load the Qt platform plugin "wayland" in "" even though it was found.

A window is created, the contents are blank, and the error suggests an issue with the wayland protocol plugin.

WSLg supports the Wayland protocol and has a Weston composer inside the "system distro" https://github.com/microsoft/wslg?tab=readme-ov-file#wslg-architecture-overview

Some environment variables for these are set to the correct values, as per https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg:

$ echo $DISPLAY
:0
$ echo $WAYLAND_DISPLAY
wayland-0

After setting the environment variable $ export QT_DEBUG_PLUGINS=1, the same command shows more verbose output, but does show several plugins from the python PyQt6 library at /home/[user]/.local/lib/python3.13/site-packages/PyQt6/Qt6/plugins/platforms, including wayland, wayland-egl, and minimalegl

Manually inspecting the contents of the folder, there are files there:

$ ls ~/.local/lib/python3.13/site-packages/PyQt6/Qt6/plugins/platforms
libqeglfs.so    libqminimal.so     libqoffscreen.so     libqvnc.so          libqwayland-generic.so
libqlinuxfb.so  libqminimalegl.so  libqvkkhrdisplay.so  libqwayland-egl.so  libqxcb.so

The plugins were installed, by are failing to load. They can be manually selected via an environment variable.

Try wayland directly

$ export QT_QPA_PLATFORM=wayland ; python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()"
Failed to create wl_display (No such file or directory)
qt.qpa.plugin: Could not load the Qt platform plugin "wayland" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: wayland, offscreen, vnc, xcb, eglfs, vkkhrdisplay, linuxfb, minimal, wayland-egl, minimalegl.

Aborted (core dumped)

No window was drawn.

Try wayland-egl

$ export QT_QPA_PLATFORM=wayland-egl ; python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()"
Failed to create wl_display (No such file or directory)
qt.qpa.wayland: Failed to initialize EGL display 3001
qt.qpa.plugin: Could not load the Qt platform plugin "wayland-egl" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: wayland, offscreen, vnc, xcb, eglfs, vkkhrdisplay, linuxfb, minimal, wayland-egl, minimalegl.

Aborted (core dumped)

No window was drawn.

Try minimal

$ export QT_QPA_PLATFORM=minimal ; python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()"

This yielded an unresponsive terminal and no window; the terminal was manually terminated.

Try xcb

$ export QT_QPA_PLATFORM=xcb ; python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()"

This drew an empty window, with no contents; but also, with no errors.

In this context, with the xcb platform selected via the environment variable above, using matplotlib to draw a plot as expected, using the QtAgg backend.

$ python3
Python 3.13.2 (main, Feb 12 2025, 04:07:04) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib
>>> import matplotlib.pyplot as plt
>>> plt.plot([1, 2, 3])
[<matplotlib.lines.Line2D object at 0x7f36e9fc9810>]
>>> plt.show()
>>>
>>> print(matplotlib.get_backend())
qtagg

xcb is a library for the X protocol, suggesting this works by bypassing Wayland and instead using an X11 path.

All together, this suggests an issue with Wayland, Ubuntu 24 and WSLg. Searching online eventually showed
https://stackoverflow.com/questions/79151910/how-to-fix-errors-in-wsl-gui which pointed to https://github.com/viruscamp/wslg-links

As per https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg, there does seem to be an X server running:

$ ls /tmp/.X11-unix
X0

However, this does not appear to be a link to a different file from /mnt/wslg/

$ ls -la /tmp/.X11-unix
total 4
drwxrwxrwx  2 root    root      60 Feb 20 18:48 .
drwxrwxrwt 13 root    root    4096 Feb 20 19:44 ..
srwxrwxrwx  1 [user]  [user]     0 Feb 20 18:48 X0

These support Virus Camp's results. The suggested fix from https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg#setting-tmp-in-etcfstab yields an error, as:

$ ln -s /mnt/wslg/.X11-unix /tmp/.X11-unix
ln: failed to create symbolic link '/tmp/.X11-unix/.X11-unix': Read-only file system

Testing Virus Camp's approach:

$ wget https://github.com/viruscamp/wslg-links/archive/refs/heads/main.zip
$ unzip main.zip
$ cd wslg-links-main/
$ sudo cp wslg-tmp-x11.service /usr/lib/systemd/system/
$ sudo cp wslg-runtime-dir.service /usr/lib/systemd/user/
$ sudo systemctl --global disable pulseaudio.socket
Failed to disable unit, unit pulseaudio.socket does not exist.
$ sudo systemctl enable wslg-tmp-x11
Created symlink /etc/systemd/system/default.target.wants/wslg-tmp-x11.service → /usr/lib/systemd/system/wslg-tmp-x11.service.
$ sudo systemctl --global enable wslg-runtime-dir
Created symlink /etc/systemd/user/default.target.wants/wslg-runtime-dir.service → /usr/lib/systemd/user/wslg-runtime-dir.service.

I do not know what issue there is with pulseaudio; I have not noticed issues, but I also don't use audio under WSL...

After rebooting the WSL VM PS > wsl --shutdown, relaunching and trying

$ export QT_QPA_PLATFORM=wayland ; python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()"

The window displays, can be resized, and there's no errors on screen. The gnome-text-editor screen can now be resized. Plotting with Matplotlib and PyQt6 works as expected. In a different session (i.e. without setting QT_QPA_PLATFORM), everything works as expected too.

This said, the .X11-unix link still seems missing, with neither ls nor readlink suggesting it's a link:

$ ls -lah /tmp/.X11-unix
total 4
drwxrwxrwx  2 root    root      60 Feb 20 20:55 .
drwxrwxrwt 12 root    root    4096 Feb 20 20:56 ..
srwxrwxrwx  1 [user]  [user]     0 Feb 20 20:55 X0
$ readlink /tmp/.X11-unix/X0
$

Summary

Instead of working out-of-the-box, Wayland apps appear to require a few extra components to work under Ubuntu 24.04 and WSLg. These include an updated MESA "driver" from an external PPA, libgles2-mesa-dev from Ubuntu's package tracker, and some more complex file over-writting shenanigans to get a very protected link re-written the right way.

Once Ubuntu updates their MESA driver, the first section of this write-up will be (hopefully) obsolete.

As for the .X11-unix/X0 link, that seems to be Microsoft's to fix.

Expected Behavior

The wayland application works out of the box, as advertised.

Actual Behavior

The wayland application does not work.

Diagnostic Logs

No response

Copy link

No logs.etl found in the archive. Make sure that you ran collect-wsl-logs.ps1 as administrator and that the logs.etl file is in the archive.

Diagnostic information
Found '/question', adding tag 'question'
appxpackage.txt not found
optional-components.txt not found
No logs.etl found in archive.
Error while parsing the logs. See action page for details

@viruscamp
Copy link

viruscamp commented Feb 21, 2025

Actually, wslg-links do /bin/ln -sf /mnt/wslg/.X11-unix /tmp/.X11-unix.

So the link is /tmp/.X11-unix --> /mnt/wslg/.X11-unix, not /tmp/.X11-unix/X0 --> /mnt/wslg/.X11-unix/X0

Try realpath /tmp/.X11-unix/X0 .

@hmedina
Copy link
Author

hmedina commented Feb 21, 2025

Hi there, the content appears to not be linked (if I'm misunderstanding the tool's usage, please clarify):

$ realpath /tmp/.X11-unix/X0
/tmp/.X11-unix/X0
$ realpath /tmp/.X11-unix
/tmp/.X11-unix

Just to sanity check the tool, realpath did resolve something else (as did ls -lah for that matter):

$ realpath /usr/local/bin/python3
/usr/local/bin/python3.13

@borjamunozf
Copy link

borjamunozf commented Feb 21, 2025

I would avoid using Ubuntu 24.04 in WSL for now. We're still using the 22.04, sadly 24.04 has too many issues yet with WSL and involves hacks to make it work decently.

Hope they'll fix it soon.

@viruscamp
Copy link

viruscamp commented Feb 21, 2025

Ah, I got it, Ubuntu and Debian do not need wslg-tmp-x11.service . I wrote it in wslg-links Why, not so obvious.

@loadhigh
Copy link

Add the following line to /etc/fstab so wsl mounts it before systemd is initialized

tmpfs    /tmp    tmpfs    defaults,strictatime,mode=1777,nr_inodes=1m  0  0

If tmp.mount systemd service exists in your distro, disable it by masking it so it does not mount over /tmp/.X11-unix (may not be needed for Ubuntu):

sudo systemctl mask tmp.mount

Override user-runtime-dir@.service to re-create the wayland and pulseaudio sockets

sudo systemctl edit user-runtime-dir@.service

and add the following

### Editing /etc/systemd/system/user-runtime-dir@.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file

[Service]
ExecStart = sh -c "ln -fs /mnt/wslg/runtime-dir/* /run/user/"%i

### Edits below this comment will be discarded

Confirm that wayland socket is available:

$ ls -l /run/user/$UID/wayland-0
lrwxrwxrwx 1 root root 31 Feb 21 16:06 /run/user/1000/wayland-0 -> /mnt/wslg/runtime-dir/wayland-0

@hmedina
Copy link
Author

hmedina commented Feb 22, 2025

Hi @viruscamp ; I read the post you had, but I did not understand what you meant there. I had thought "mask" may mean some technical term for some sort of linking or mounting

Please correct me if I'm misunderstanding: if Ubuntu doesn't rely on the /tmp/X11-unix folder having the X0 files (et al. for other displays), then the only part that a user needs to do is get $XDG_RUNTIME_DIR to point to the right location? And that would be the contents of https://github.com/viruscamp/wslg-links/blob/main/wslg-runtime-dir.service ?

I'm not familiar with systemd configuration files, but from what I gathered, you're using the %t specifier (which should resolve to $XDG_RUNTIME_DIR "for user managers"; elegant!) to force create a symbolic link that points to /mnt/wslg/runtime-dir ? And this is held in a service file at /etc/systemd/system/default.target.wants/wslg-tmp-x11.service, which in turn points to /usr/lib/systemd/system/wslg-tmp-x11.service ? Is this a service that runs at system launch? At user sign-in?

Regardless, the re-directs are working:

$ echo $XDG_RUNTIME_DIR
/run/user/1000/
$ ls -lah /run/user/1000/
total 0
drwx------ 4 [user]  [user]  200 Feb 21 18:24 .
drwxr-xr-x 3 root    root     60 Feb 21 18:24 ..
srw-rw-rw- 1 [user]  [user]    0 Feb 21 18:24 bus
drwx------ 2 [user]  [user]  160 Feb 21 18:24 gnupg
srw-rw-rw- 1 [user]  [user]    0 Feb 21 18:24 pk-debconf-socket
lrwxrwxrwx 1 [user]  [user]   27 Feb 21 18:24 pulse -> /mnt/wslg/runtime-dir/pulse
srw-rw-rw- 1 [user]  [user]    0 Feb 21 18:24 snapd-session-agent.socket
drwxr-xr-x 6 [user]  [user]  160 Feb 21 18:24 systemd
lrwxrwxrwx 1 [user]  [user]   31 Feb 21 18:24 wayland-0 -> /mnt/wslg/runtime-dir/wayland-0
lrwxrwxrwx 1 [user]  [user]   36 Feb 21 18:24 wayland-0.lock -> /mnt/wslg/runtime-dir/wayland-0.lock

@loadhigh could you elaborate what does your approach do differently from Virus Camp's? Is there a general benefit (beyond the current wayland issue) to mounting fstab before systemd initializes? Your suggesting for the system service seems (to my untrained eye) to do the same that Virus Camp's does; is this just an alternative file to edit, or does your process achieve something I'm missing?

@viruscamp
Copy link

viruscamp commented Feb 22, 2025

  1. wslg-tmp-x11.service makes /tmp/.X11-unix/X0 exist. If the file already exists, the service is needless.
    Systemd tmp.mount unit will mount /tmp and then make /tmp/.X11-unix/X0 missing in most WSL distro.
    Ubuntu and Debian in WSL does not need wslg-tmp-x11.service, because tmp.mount is disabled (masked) in the distro.

  2. wslg-runtime-dir.service makes /run/user/1000/wayland-0 exist. If the file already exists, the service is needless.
    Systemd user-runtime-dir@.service unit will mount /run/user/1000/ and then make /run/user/1000/wayland-0 missing.
    The user-runtime-dir@.service cannot be disabled.
    Ubuntu-22.04 won't mount /run/user/1000 due to a bug in /usr/lib/systemd/systemd-user-runtime-dir, so wslg-runtime-dir.service is needless.
    Ubuntu-24.04 use a new version of systemd which fix the bug, so it will mount /run/user/1000, and make $XDG_RUNTIME_DIR/wayland-0 missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants