Qt 6 introduced a new way to access platform specific objects and functionality in the QNativeInterface namespace. Starting with Qt 6.5 it will be possible to obtain handles to wayland object handles this way. Let’s look at what’s new and how it improves on the past method.

In Qt 5 there were to two options to access platform-specific API and native handles of the current platform. If you were lucky, your platform had an ‘Extras’ module like Qt Max Extras, Qt X11 Extras or Qt Android Extras. However these were removed for Qt 6 and if you ever needed something that was not exposed this way or the platform had no ‘Extras’ module (like Wayland), it was also possible to access functionality via QPlatformNativeInterface. An example usage of would look like this:

QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
if (!nativeInterface) {
    return;
}
auto seat = static_cast<wl_seat*>(nativeInterface->nativeResourceForIntegration("wl_seat"));
auto surface = static_cast<wl_surface*>(nativeInterface->nativeResourceForWindow("surface", window));
if (!seat || !surface) {
    return;
}
// do something with seat and surface

The snippet shows multiple problems of this API. One is that it is not type safe, the nativeResourceFor... functions return void*. I could easily have forgotten to change the type in the second cast with further implications down the line. The second problem is that it is not obvious at all what is available, no header file will tell you. One has to either already know or read the implementation. Additionally any typo in the string will break the functionality.

Qt 6 solves this with the interfaces in the QNativeInterface namespace. They provide type safe access to the platform specific parts. Using the new interfaces for Wayland in Qt 6.5 we can rewrite the above:

auto waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
auto waylandWindow = window->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
if (!waylandApp || !waylandWindow) {
    return;
}
auto seat = waylandApp->seat();
auto surface = waylandWindow->surface();
if (!seat || !surface) {
    return;
}
// do something with seat and surface

Much nicer. The nativeInterface functions check that the interface is available on the object and from there on usage is straightforward. It’s obvious what’s available by looking at the header or the documentation. For example through QWaylandApplication it’s possible to access the wayland objects that Qt is using internally as well as the input serial of the last user action which is sometimes required to pass in other wayland protocols.

The astute reader might have noticed that in the snippet QWaylandWindow is in the nested QNativeInterface::Private namespace for now. The interface chosen here is being evaluated and a bit experimental (due to the need of signalling surface creation and destruction, it’s the first native interface inheriting from QObject!) and as I wanted to get this into Qt 6.5 I followed the precedent of QWindow native interfaces of the other platforms also being private for now. QWaylandOutput also resides next to its cousins in QNativeInterface::Private. Still I hope they don’t need to stay too long there and can be made public soon.