[Development] Untangling our platform plugins
Tor Arne Vestbø
Tor.arne.Vestbo at qt.io
Fri May 15 11:20:26 CEST 2020
During the 2019 contributor summit we had a session on what to do with our ever expanding platform APIs/backends in Qt . I’ve now prototyped some of the ideas put forward in that session, and it’s shaping up nicely.
The gist of it is that our platform plugins — while a good abstraction for Qt 5 — have become somewhat of a kitchen sink.
During the transition from Qt 4 to Qt 5, the platform plugins (and the QPA layer) served as mechanism to put proper abstractions in place under the window-system bits, mainly serving QtGui. Over time we’ve added various other “platform” pieces there too — sometimes resulting in awkward indirections when the functionality was needed in modules such as QtWidgets or QtPrintSupport. At the same time, we never went all in and made the platform plugin the only place to put platform abstractions. QtCore for one has lots of them, and there are countless other examples.
With Qt 6 ahead it’s time to do some house cleaning so we’re prepared for another major series.
In practical terms this means moving code from the platform plugins to the modules they are providing backend implementations for. For the most part this is QtGui, due to the window-system focus of the plugins, but also includes QtOpenGL, QtCore, and QtPrintSupport. This aligns the backend implementations with the cross platform pieces, which makes it easier to reason about them as one unit, for example:
src/plugins/platforms/foo/qfoofontengine_p.h → src/gui/text/foo/qfoofontengine_p.h
This is already the pattern we use across all of Qt, where the backend code lives next to the cross platform code and interface APIs, eg:
or for a more recent example:
This restructuring includes the platform support libraries, which originally served as a way to conditionally enable functionality per platform, and share it between platforms. With the new configure system in Qt we no longer need to do this at the build system level with static libraries, and sharing the code via the relevant modules allows a more fine grained choice of which backends to build in our out.
Another benefit of having the code live in the relevant modules is that the backends can make their headers privately available, to clients in other modules or user code. This allows us to remove the boilerplate and indirections of QPlatformNativeInterface , and the dark corners of QtPlatformHeaders , in favor of a simple qobject_cast and direct call:
[cid:2E567B6F-D6E0-416D-B291-3C62B6E51D32 at dyran.local]
One important thing to note is that none of this affects the API-layer of QPA itself. Having a clearly defined API boundary for the window system bits is a good thing, and we want to keep that.
Nor does it affect the “plugin” part of the platform backends. They are still plugins, which can be chosen at runtime, and could potentially live outside of qtbase, like the Wayland platform plugin does. But for the ones that live in qtbase, the majority of their code would be moved to the relevant modules, leaving only the plugin’s entry point as a shared library. Or, in the case of platforms such as macOS where there’s only one “platform”, the plugin is built directly into QtGui as a static plugin.
Over time, we might find that the configure system and this restructuring allows us a more granular runtime choice of backends too, instead of having to pass the choice of e.g. font backend through the platform plugin, but that’s not an immediate goal.
The prototype of moving the entire macOS plugin, plus all its platform-support dependencies, into the relevant modules can be found at https://codereview.qt-project.org/c/qt/qtbase/+/295888/8. That took roughly a day for the initial work, so I’m positive that we should be able to shuffle things around without hitting too many traps.
The key change to make ASAP is making QtPlatformHeaders private APIs in Qt 6, so that we don’t have any public APIs limiting us in the work going forward. They are not going away until we have a replacement, but having them private means we decouple the internal restructuring of the platform layers from the direct 6.0 timeline. Considering the use-cases of those APIs, making them private for now should be fine.
The tracking issue for this work is https://bugreports.qt.io/browse/QTBUG-80233 for anyone who want to follow along at home or have ideas or thoughts. Thanks for making it this far 😊
-------------- next part --------------
An HTML attachment was scrubbed...
-------------- next part --------------
A non-text attachment was scrubbed...
Size: 179618 bytes
More information about the Development