Skip to content

WindowManager: Linux Wayland support #36

Description

@almarklein

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_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendA proposal for a new backend

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions