Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwaylandintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include "qwaylanddisplay_p.h"
13#if QT_CONFIG(clipboard)
14#include "qwaylandclipboard_p.h"
15#endif
16#include "qwaylanddnd_p.h"
18#include "qwaylandscreen_p.h"
19#include "qwaylandcursor_p.h"
20
21#if defined(Q_OS_MACOS)
22# include <QtGui/private/qcoretextfontdatabase_p.h>
23# include <QtGui/private/qfontengine_coretext_p.h>
24#else
25# include <QtGui/private/qgenericunixfontdatabase_p.h>
26#endif
27#include <QtGui/private/qgenericunixeventdispatcher_p.h>
28#include <QtGui/private/qgenericunixthemes_p.h>
29
30#include <QtGui/private/qguiapplication_p.h>
31
32#include <qpa/qwindowsysteminterface.h>
33#include <qpa/qplatformcursor.h>
34#include <QtGui/QSurfaceFormat>
35#if QT_CONFIG(opengl)
36#include <QtGui/QOpenGLContext>
37#endif // QT_CONFIG(opengl)
38#include <QSocketNotifier>
39
40#include <qpa/qplatforminputcontextfactory_p.h>
41#include <qpa/qplatformaccessibility.h>
42#include <qpa/qplatforminputcontext.h>
43
47
51
54
57#include "qwaylandwindow_p.h"
58
59#if QT_CONFIG(accessibility_atspi_bridge)
60#include <QtGui/private/qspiaccessiblebridge_p.h>
61#endif
62
63#if QT_CONFIG(xkbcommon)
64#include <QtGui/private/qxkbcommon_p.h>
65#endif
66
67#if QT_CONFIG(vulkan)
70#endif
71
73
74namespace QtWaylandClient {
75
76QWaylandIntegration *QWaylandIntegration::sInstance = nullptr;
77
79#if defined(Q_OS_MACOS)
81#else
82 : mFontDb(new QGenericUnixFontDatabase())
83#endif
84{
85 mDisplay.reset(new QWaylandDisplay(this));
86
88 !qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
89
90 sInstance = this;
91}
92
94{
95 sInstance = nullptr;
96}
97
99{
100 return mDisplay->initialize();
101}
102
104{
105 return mNativeInterface.data();
106}
107
109{
110 switch (cap) {
111 case ThreadedPixmaps: return true;
112 case OpenGL:
113 return mDisplay->clientBufferIntegration();
114 case ThreadedOpenGL:
115 return mDisplay->clientBufferIntegration() && mDisplay->clientBufferIntegration()->supportsThreadedOpenGL();
117 return true;
118 case MultipleWindows:
120 return true;
121 case RasterGLSurface:
122 return true;
123 case WindowActivation:
124 return false;
125 case ScreenWindowGrabbing: // whether QScreen::grabWindow() is supported
126 return false;
128 }
129}
130
132{
133 if ((window->surfaceType() == QWindow::OpenGLSurface || window->surfaceType() == QWindow::RasterGLSurface)
134 && mDisplay->clientBufferIntegration())
135 return mDisplay->clientBufferIntegration()->createEglWindow(window);
136
137#if QT_CONFIG(vulkan)
138 if (window->surfaceType() == QSurface::VulkanSurface)
139 return new QWaylandVulkanWindow(window, mDisplay.data());
140#endif // QT_CONFIG(vulkan)
141
142 return new QWaylandShmWindow(window, mDisplay.data());
143}
144
145#if QT_CONFIG(opengl)
147{
148 if (mDisplay->clientBufferIntegration())
149 return mDisplay->clientBufferIntegration()->createPlatformOpenGLContext(context->format(), context->shareHandle());
150 return nullptr;
151}
152#endif // opengl
153
155{
156 return new QWaylandShmBackingStore(window, mDisplay.data());
157}
158
160{
161 return createUnixEventDispatcher();
162}
163
165{
166 return new QWaylandNativeInterface(this);
167}
168
169// Support platform specific initialization
170void QWaylandIntegration::initializePlatform()
171{
172 mDisplay->initEventThread();
173
174 mNativeInterface.reset(createPlatformNativeInterface());
175 initializeInputDeviceIntegration();
176#if QT_CONFIG(clipboard)
177 mClipboard.reset(new QWaylandClipboard(mDisplay.data()));
178#endif
179#if QT_CONFIG(draganddrop)
180 mDrag.reset(new QWaylandDrag(mDisplay.data()));
181#endif
182
184}
185
187{
188 initializePlatform();
189
190 // Call this after initializing event thread for QWaylandDisplay::flushRequests()
192 QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
193 QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
194
195 // Qt does not support running with no screens
196 mDisplay->ensureScreen();
197}
198
200{
201 return mFontDb.data();
202}
203
204#if QT_CONFIG(clipboard)
206{
207 return mClipboard.data();
208}
209#endif
210
211#if QT_CONFIG(draganddrop)
212QPlatformDrag *QWaylandIntegration::drag() const
213{
214 return mDrag.data();
215}
216#endif // draganddrop
217
219{
220 return mInputContext.data();
221}
222
224{
225 if (hint == ShowIsFullScreen && mDisplay->windowManagerIntegration())
226 return mDisplay->windowManagerIntegration()->showIsFullScreen();
227
229}
230
231#if QT_CONFIG(accessibility)
232QPlatformAccessibility *QWaylandIntegration::accessibility() const
233{
234 if (!mAccessibility) {
235#if QT_CONFIG(accessibility_atspi_bridge)
236 Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QWaylandIntegration",
237 "Initializing accessibility without event-dispatcher!");
238 mAccessibility.reset(new QSpiAccessibleBridge());
239#else
240 mAccessibility.reset(new QPlatformAccessibility());
241#endif
242 }
243 return mAccessibility.data();
244}
245#endif
246
248{
249 return mDisplay->windowManagerIntegration();
250}
251
253{
254 return mDisplay.data();
255}
256
258{
259 if (auto *seat = mDisplay->currentInputDevice(); seat && seat->keyboardFocus()) {
260 return seat->modifiers();
261 }
262 return Qt::NoModifier;
263}
264
266{
267 if (auto *seat = mDisplay->currentInputDevice())
268 return seat->possibleKeys(event);
269 return {};
270}
271
273{
275}
276
278{
280}
281
282QWaylandScreen *QWaylandIntegration::createPlatformScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id) const
283{
284 return new QWaylandScreen(waylandDisplay, version, id);
285}
286
288{
289 return new QWaylandCursor(display);
290}
291
292#if QT_CONFIG(vulkan)
293QPlatformVulkanInstance *QWaylandIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
294{
296}
297#endif // QT_CONFIG(vulkan)
298
299// May be called from non-GUI threads
301{
302 // Do an inexpensive check first to avoid locking whenever possible
303 if (Q_UNLIKELY(!mClientBufferIntegrationInitialized))
304 const_cast<QWaylandIntegration *>(this)->initializeClientBufferIntegration();
305
306 Q_ASSERT(mClientBufferIntegrationInitialized);
307 return mClientBufferIntegration && mClientBufferIntegration->isValid() ? mClientBufferIntegration.data() : nullptr;
308}
309
311{
312 if (!mServerBufferIntegrationInitialized)
313 const_cast<QWaylandIntegration *>(this)->initializeServerBufferIntegration();
314
315 return mServerBufferIntegration.data();
316}
317
319{
320 if (!mShellIntegrationInitialized)
321 const_cast<QWaylandIntegration *>(this)->initializeShellIntegration();
322
323 return mShellIntegration.data();
324}
325
326// May be called from non-GUI threads
327void QWaylandIntegration::initializeClientBufferIntegration()
328{
329 QMutexLocker lock(&mClientBufferInitLock);
330 if (mClientBufferIntegrationInitialized)
331 return;
332
333 QString targetKey = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION"));
334
335 if (targetKey.isEmpty()) {
336 if (mDisplay->hardwareIntegration()
337 && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("wayland-eglstream-controller")
338 && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("linux-dmabuf-unstable-v1")) {
339 targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration();
340 } else {
341 targetKey = QLatin1String("wayland-egl");
342 }
343 }
344
345 if (targetKey.isEmpty()) {
346 qWarning("Failed to determine what client buffer integration to use");
347 } else {
349 qCDebug(lcQpaWayland) << "Available client buffer integrations:" << keys;
350
351 if (keys.contains(targetKey))
353
355 qCDebug(lcQpaWayland) << "Initializing client buffer integration" << targetKey;
356 mClientBufferIntegration->initialize(mDisplay.data());
357 } else {
358 qCWarning(lcQpaWayland) << "Failed to load client buffer integration:" << targetKey;
359 qCWarning(lcQpaWayland) << "Available client buffer integrations:" << keys;
360 }
361 }
362
363 // This must be set last to make sure other threads don't use the
364 // integration before initialization is complete.
365 mClientBufferIntegrationInitialized = true;
366}
367
368void QWaylandIntegration::initializeServerBufferIntegration()
369{
370 mServerBufferIntegrationInitialized = true;
371
372 QString targetKey = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION"));
373
374 if (targetKey.isEmpty() && mDisplay->hardwareIntegration())
375 targetKey = mDisplay->hardwareIntegration()->serverBufferIntegration();
376
377 if (targetKey.isEmpty()) {
378 qWarning("Failed to determine what server buffer integration to use");
379 return;
380 }
381
383 qCDebug(lcQpaWayland) << "Available server buffer integrations:" << keys;
384
385 if (keys.contains(targetKey))
387
389 qCDebug(lcQpaWayland) << "Initializing server buffer integration" << targetKey;
390 mServerBufferIntegration->initialize(mDisplay.data());
391 } else {
392 qCWarning(lcQpaWayland) << "Failed to load server buffer integration: " << targetKey;
393 qCWarning(lcQpaWayland) << "Available server buffer integrations:" << keys;
394 }
395}
396
397void QWaylandIntegration::initializeShellIntegration()
398{
399 mShellIntegrationInitialized = true;
400
401 QByteArray integrationNames = qgetenv("QT_WAYLAND_SHELL_INTEGRATION");
402 QString targetKeys = QString::fromLocal8Bit(integrationNames);
403
404 QStringList preferredShells;
405 if (!targetKeys.isEmpty()) {
406 preferredShells = targetKeys.split(QLatin1Char(';'));
407 } else {
408 preferredShells << QLatin1String("xdg-shell");
409 preferredShells << QLatin1String("wl-shell") << QLatin1String("ivi-shell");
410 preferredShells << QLatin1String("qt-shell");
411 }
412
413 for (const QString &preferredShell : std::as_const(preferredShells)) {
414 mShellIntegration.reset(createShellIntegration(preferredShell));
415 if (mShellIntegration) {
416 qCDebug(lcQpaWayland, "Using the '%s' shell integration", qPrintable(preferredShell));
417 break;
418 }
419 }
420
421 if (!mShellIntegration) {
422 qCWarning(lcQpaWayland) << "Loading shell integration failed.";
423 qCWarning(lcQpaWayland) << "Attempted to load the following shells" << preferredShells;
424 }
425
427}
428
430{
432 return mInputDeviceIntegration->createInputDevice(display, version, id);
433 }
434 return new QWaylandInputDevice(display, version, id);
435}
436
437void QWaylandIntegration::initializeInputDeviceIntegration()
438{
439 QByteArray integrationName = qgetenv("QT_WAYLAND_INPUTDEVICE_INTEGRATION");
440 QString targetKey = QString::fromLocal8Bit(integrationName);
441
442 if (targetKey.isEmpty()) {
443 return;
444 }
445
447 if (keys.contains(targetKey)) {
449 qDebug("Using the '%s' input device integration", qPrintable(targetKey));
450 } else {
451 qWarning("Wayland inputdevice integration '%s' not found, using default", qPrintable(targetKey));
452 }
453}
454
456{
457 if (!mDisplay) {
458 // This function can be called from QWaylandDisplay::registry_global() when we
459 // are in process of constructing QWaylandDisplay. Configuring input context
460 // in that case is done by calling reconfigureInputContext() from QWaylandIntegration
461 // constructor, after QWaylandDisplay has been constructed.
462 return;
463 }
464
466 if (requested == QLatin1String("qtvirtualkeyboard"))
467 qCWarning(lcQpaWayland) << "qtvirtualkeyboard currently is not supported at client-side,"
468 " use QT_IM_MODULE=qtvirtualkeyboard at compositor-side.";
469
470 if (!mDisplay->isClientSideInputContextRequested()) {
471 if (mDisplay->textInputMethodManager() != nullptr)
473#if QT_WAYLAND_TEXT_INPUT_V4_WIP
474 else if (mDisplay->textInputManagerv1() != nullptr || mDisplay->textInputManagerv2() != nullptr || mDisplay->textInputManagerv4() != nullptr)
475#else // QT_WAYLAND_TEXT_INPUT_V4_WIP
476 else if (mDisplay->textInputManagerv1() != nullptr || mDisplay->textInputManagerv2() != nullptr)
477#endif // QT_WAYLAND_TEXT_INPUT_V4_WIP
479 } else {
481 }
482
483 const QString defaultInputContext(QStringLiteral("compose"));
484 if ((!mInputContext || !mInputContext->isValid()) && requested != defaultInputContext)
486
487#if QT_CONFIG(xkbcommon)
489 if (QWaylandInputContext* waylandInput = qobject_cast<QWaylandInputContext*>(mInputContext.get())) {
490 waylandInput->setXkbContext(mDisplay->xkbContext());
491 }
492#endif
493
494 qCDebug(lcQpaWayland) << "using input method:" << (inputContext() ? inputContext()->metaObject()->className() : "<none>");
495}
496
497QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName)
498{
499 if (QWaylandShellIntegrationFactory::keys().contains(integrationName)) {
500 return QWaylandShellIntegrationFactory::create(integrationName, mDisplay.data());
501 } else {
502 qCWarning(lcQpaWayland) << "No shell integration named" << integrationName << "found";
503 return nullptr;
504 }
505}
506
508{
510 mServerBufferIntegrationInitialized = false;
511
513
515 mClientBufferIntegrationInitialized = false;
516}
517
519{
520 auto unixServices = mDisplay->windowManagerIntegration();
521 unixServices->setApplicationBadge(number);
522}
523}
524
\inmodule QtCore
Definition qbytearray.h:57
static QAbstractEventDispatcher * eventDispatcher
static QAbstractEventDispatcher * eventDispatcher()
Returns a pointer to the event dispatcher object for the main thread.
static QPlatformTheme * createUnixTheme(const QString &name)
Creates a UNIX theme according to the detected desktop environment.
static QStringList themeNames()
The QKeyEvent class describes a key event.
Definition qevent.h:423
Definition qlist.h:74
\inmodule QtCore
Definition qmutex.h:317
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
\inmodule QtGui
The QPlatformBackingStore class provides the drawing area for top-level windows.
The QPlatformClipboard class provides an abstraction for the system clipboard.
The QPlatformDrag class provides an abstraction for drag.
The QPlatformFontDatabase class makes it possible to customize how fonts are discovered and how they ...
static QPlatformInputContext * create()
The QPlatformInputContext class abstracts the input method dependent data and composing state.
virtual bool isValid() const
Returns input context validity.
virtual QVariant styleHint(StyleHint hint) const
virtual bool hasCapability(Capability cap) const
virtual QPlatformOpenGLContext * createPlatformOpenGLContext(QOpenGLContext *context) const
Factory function for QPlatformOpenGLContext.
virtual QPlatformClipboard * clipboard() const
Accessor for the platform integration's clipboard.
Capability
Capabilities are used to determine specific features of a platform integration.
The QPlatformNativeInterface class provides an abstraction for retrieving native resource handles.
The QPlatformOpenGLContext class provides an abstraction for native GL contexts.
The QPlatformServices provides the backend for desktop-related functionality.
The QPlatformTheme class allows customizing the UI based on themes.
The QPlatformVulkanInstance class provides an abstraction for Vulkan instances.
The QPlatformWindow class provides an abstraction for top-level windows.
T * get() const noexcept
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
Definition qstring.cpp:7956
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
@ RasterGLSurface
Definition qsurface.h:33
@ OpenGLSurface
Definition qsurface.h:32
@ VulkanSurface
Definition qsurface.h:35
\inmodule QtCore
Definition qvariant.h:64
The QVulkanInstance class represents a native Vulkan instance, enabling Vulkan rendering onto a QSurf...
\inmodule QtGui
Definition qwindow.h:63
static void setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context)
static QWaylandClientBufferIntegration * create(const QString &name, const QStringList &args)
static QWaylandInputDeviceIntegration * create(const QString &name, const QStringList &args)
QScopedPointer< QWaylandInputDeviceIntegration > mInputDeviceIntegration
QVariant styleHint(StyleHint hint) const override
virtual QWaylandServerBufferIntegration * serverBufferIntegration() const
QPlatformNativeInterface * nativeInterface() const override
QPlatformWindow * createPlatformWindow(QWindow *window) const override
Factory function for QPlatformWindow.
QPlatformFontDatabase * fontDatabase() const override
Accessor for the platform integration's fontdatabase.
bool hasCapability(QPlatformIntegration::Capability cap) const override
QScopedPointer< QWaylandClientBufferIntegration > mClientBufferIntegration
QPlatformTheme * createPlatformTheme(const QString &name) const override
virtual QWaylandCursor * createPlatformCursor(QWaylandDisplay *display) const
virtual QWaylandScreen * createPlatformScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id) const
QStringList themeNames() const override
static QWaylandIntegration * instance()
QScopedPointer< QWaylandDisplay > mDisplay
QPlatformServices * services() const override
QScopedPointer< QWaylandShellIntegration > mShellIntegration
virtual QWaylandShellIntegration * shellIntegration() const
void initialize() override
Performs initialization steps that depend on having an event dispatcher available.
QScopedPointer< QWaylandServerBufferIntegration > mServerBufferIntegration
virtual QWaylandClientBufferIntegration * clientBufferIntegration() const
QPlatformInputContext * inputContext() const override
Returns the platforms input context.
virtual QPlatformNativeInterface * createPlatformNativeInterface()
QList< int > possibleKeys(const QKeyEvent *event) const override
Should be used to obtain a list of possible shortcuts for the given key event.
QPlatformBackingStore * createPlatformBackingStore(QWindow *window) const override
Factory function for QPlatformBackingStore.
QScopedPointer< QPlatformInputContext > mInputContext
virtual QWaylandInputDevice * createInputDevice(QWaylandDisplay *display, int version, uint32_t id) const
Qt::KeyboardModifiers queryKeyboardModifiers() const override
QAbstractEventDispatcher * createEventDispatcher() const override
Factory function for the GUI event dispatcher.
void setApplicationBadge(qint64 number) override
static QWaylandServerBufferIntegration * create(const QString &name, const QStringList &args)
static QWaylandShellIntegration * create(const QString &name, QWaylandDisplay *display, const QStringList &args=QStringList())
struct wl_display * display
Definition linuxdmabuf.h:41
Combined button and popup list for selecting options.
@ NoModifier
static void * context
#define Q_UNLIKELY(x)
QPlatformFontDatabase QGenericUnixFontDatabase
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
#define qCWarning(category,...)
#define qCDebug(category,...)
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLuint name
struct _cl_event * event
GLenum cap
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define qPrintable(string)
Definition qstring.h:1391
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
long long qint64
Definition qtypes.h:55
QStringList keys
QReadWriteLock lock
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
\inmodule QtCore \reentrant
Definition qchar.h:17