Updated 17-09-2024
Current status
Up to 17-09-2024:
- GLFW
- Works by telling glfw to use the X11 API (i.e. XWayland).
- When using the Wayland API there are no window decorations and no events.
- The latter may work with a newer release of glfw.
- Qt
- Works by rendering via an offscreen texture
- Panics when trying via the X11 API (this worked before, but not anymore)
- Segfaults when trying to use the Wayland API.
- The above issues may be resolved if we get the proper display id.
- Wx
Introduction
Since Ubuntu 21.04, Wayland is the default display server. This means that this issue potentially affects a lot of users.
The XDG_SESSION_TYPE env variable is either x11 or wayland. This variable is used by many applications to select the window system. What's important for us is that glfw and qt (and wx?) use this variable too.
Forntunately, there is XWayland, a compatibility layer that allows applications to "talk X", but still run on Wayland. XWayland is installed by default on Ubuntu too.
This means we can tell glfw and qt to just use X, even when on Wayland. There are env vars for that.
How does it affect us exactly?
To obtain a surface id for the canvas to render to, we call wgpuInstanceCreateSurface(), the descriptor argument for that function is platform specific; there is a different struct for Windows, Metal, X11, Wayland, and Xcb.
On Windows and MacOS, that struct can be composed with just the "window id". Glfw, Qt and Wx have a metthod to obtain it. So Windows and MacOS are relatievely easy.
On Linux, apart from having to deal with multiple window platforms, we also need an additional value: the display id. This is basically a pointer to a display context: the thing an app creates to start doing things with x11/Wayland. A bit similar to a device of wgpu. This is where the hard part is.
Support for glfw
GLFW has improved support over the past years/months, but seems not quite 100% yet. Pyglfw on Linux includes one lib for x11 and one for Wayland, and selects one based on XDG_SESSION_TYPE and a few other variables.
The latest glfw (3.4, released 23-02-2024) ought to have better support for Wayland. And includes that support in a single binary lib. Unfortunately, there are some build problems, so pyglfw cannot ship with these binaries yet. It ships glfw 3.3.9 instead.
When I apt install libglfw3 it installs version 3.3.6 (on Ubunty 22.04). I don't feel like compiling glfw from source right now. So I have not tested the new glfw 3.4.
This snippet can be used to create a glfw window. Without the PYGLFW_LIBRARY_VARIANT this produces an unresponsive window without decorations on Wayland (with glfw 3.3.9).
import os
# os.environ["PYGLFW_LIBRARY_VARIANT"] = "x11" # force using XWayland
import glfw
glfw.init()
glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
glfw.window_hint(glfw.RESIZABLE, True)
w = glfw.create_window(800, 800, "Test!", None, None)
while True:
glfw.poll_events()
Also see gfx-rs/wgpu#4775 and gfx-rs/wgpu-native#377.
The solution for now (March 2024) is to force glfw to use X11 (i.e. XWayland on Wayland).
Support for Qt
The problem with Qt is that we cannot obtain the display id that Qt uses internally. There is QGuiApplication.nativeInterface but ... it's not implemented in PySide or PyQt. See e.g. https://wiki.qt.io/Qt_for_Python_Missing_Bindings. Though maybe its available soon?
Another thing I tried was to mage qt's WgpuCanvas a QWindow instead of a QWidget. This class has a surfaceHandle() method ... except it raises an exception saying the method is private.
Instead of using the actual display id that Qt uses, we can also create our own "display object" and use that. That works fine for X11. Unfortunately, this does not work for Wayland.
Then there is QT_QPA_PLATFORM, which can be set to (amongst other things "wayland-egl" and "xcb".
The solution for now (March 2024) is to set QT_QPA_PLATFORM to xcb to tell Qt to use X11 (i.e. XWayland on Wayland).
Support for wx
Can force to use x11 by setting GDK_BACKEND to "x11". But I haven't tested because cannot install wxPython with apt or pip.
Updated 17-09-2024
Current status
Up to 17-09-2024:
Introduction
Since Ubuntu 21.04, Wayland is the default display server. This means that this issue potentially affects a lot of users.
The
XDG_SESSION_TYPEenv variable is eitherx11orwayland. This variable is used by many applications to select the window system. What's important for us is that glfw and qt (and wx?) use this variable too.Forntunately, there is XWayland, a compatibility layer that allows applications to "talk X", but still run on Wayland. XWayland is installed by default on Ubuntu too.
This means we can tell glfw and qt to just use X, even when on Wayland. There are env vars for that.
How does it affect us exactly?
To obtain a surface id for the canvas to render to, we call
wgpuInstanceCreateSurface(), the descriptor argument for that function is platform specific; there is a different struct for Windows, Metal, X11, Wayland, and Xcb.On Windows and MacOS, that struct can be composed with just the "window id". Glfw, Qt and Wx have a metthod to obtain it. So Windows and MacOS are relatievely easy.
On Linux, apart from having to deal with multiple window platforms, we also need an additional value: the display id. This is basically a pointer to a display context: the thing an app creates to start doing things with x11/Wayland. A bit similar to a device of wgpu. This is where the hard part is.
Support for glfw
GLFW has improved support over the past years/months, but seems not quite 100% yet. Pyglfw on Linux includes one lib for x11 and one for Wayland, and selects one based on
XDG_SESSION_TYPEand a few other variables.The latest glfw (3.4, released 23-02-2024) ought to have better support for Wayland. And includes that support in a single binary lib. Unfortunately, there are some build problems, so pyglfw cannot ship with these binaries yet. It ships glfw 3.3.9 instead.
When I
apt install libglfw3it installs version 3.3.6 (on Ubunty 22.04). I don't feel like compiling glfw from source right now. So I have not tested the new glfw 3.4.This snippet can be used to create a glfw window. Without the
PYGLFW_LIBRARY_VARIANTthis produces an unresponsive window without decorations on Wayland (with glfw 3.3.9).Also see gfx-rs/wgpu#4775 and gfx-rs/wgpu-native#377.
The solution for now (March 2024) is to force glfw to use X11 (i.e. XWayland on Wayland).
Support for Qt
The problem with Qt is that we cannot obtain the display id that Qt uses internally. There is QGuiApplication.nativeInterface but ... it's not implemented in PySide or PyQt. See e.g. https://wiki.qt.io/Qt_for_Python_Missing_Bindings. Though maybe its available soon?
Another thing I tried was to mage qt's
WgpuCanvasaQWindowinstead of aQWidget. This class has asurfaceHandle()method ... except it raises an exception saying the method is private.Instead of using the actual display id that Qt uses, we can also create our own "display object" and use that. That works fine for X11. Unfortunately, this does not work for Wayland.
Then there is
QT_QPA_PLATFORM, which can be set to (amongst other things "wayland-egl" and "xcb".The solution for now (March 2024) is to set
QT_QPA_PLATFORMtoxcbto tell Qt to use X11 (i.e. XWayland on Wayland).Support for wx
Can force to use x11 by setting
GDK_BACKENDto "x11". But I haven't tested because cannot installwxPythonwith apt or pip.