Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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"
19#include "qwaylandscreen_p.h"
20#include "qwaylandcursor_p.h"
21
22#if defined(Q_OS_MACOS)
23# include <QtGui/private/qcoretextfontdatabase_p.h>
24# include <QtGui/private/qfontengine_coretext_p.h>
25#else
26# include <QtGui/private/qgenericunixfontdatabase_p.h>
27#endif
28#include <QtGui/private/qgenericunixeventdispatcher_p.h>
29#include <QtGui/private/qgenericunixthemes_p.h>
30
31#include <QtGui/private/qguiapplication_p.h>
32
33#include <qpa/qwindowsysteminterface.h>
34#include <qpa/qplatformcursor.h>
35#include <QtGui/QSurfaceFormat>
36#if QT_CONFIG(opengl)
37#include <QtGui/QOpenGLContext>
38#endif // QT_CONFIG(opengl)
39#include <QSocketNotifier>
40
41#include <qpa/qplatforminputcontextfactory_p.h>
42#include <qpa/qplatformaccessibility.h>
43#include <qpa/qplatforminputcontext.h>
44
48
52
55
58#include "qwaylandwindow_p.h"
59
60#if QT_CONFIG(accessibility_atspi_bridge)
61#include <QtGui/private/qspiaccessiblebridge_p.h>
62#endif
63
64#if QT_CONFIG(xkbcommon)
65#include <QtGui/private/qxkbcommon_p.h>
66#endif
67
68#if QT_CONFIG(vulkan)
71#endif
72
74
75namespace QtWaylandClient {
76
77QWaylandIntegration *QWaylandIntegration::sInstance = nullptr;
78
80#if defined(Q_OS_MACOS)
81 : mFontDb(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>)
82#else
83 : mFontDb(new QGenericUnixFontDatabase())
84#endif
85{
86 mDisplay.reset(new QWaylandDisplay(this));
87 mPlatformServices.reset(new QWaylandPlatformServices(mDisplay.data()));
88
90 !qEnvironmentVariableIsSet("QT_WAYLAND_DISABLE_FIXED_POSITIONS");
91
92 sInstance = this;
93}
94
96{
97 sInstance = nullptr;
98}
99
101{
102 return mDisplay->initialize();
103}
104
106{
107 return mNativeInterface.data();
108}
109
111{
112 switch (cap) {
113 case ThreadedPixmaps: return true;
114 case OpenGL:
115 return mDisplay->clientBufferIntegration();
116 case ThreadedOpenGL:
117 return mDisplay->clientBufferIntegration() && mDisplay->clientBufferIntegration()->supportsThreadedOpenGL();
119 return true;
120 case MultipleWindows:
122 return true;
123 case RasterGLSurface:
124 return true;
125 case WindowActivation:
126 return false;
127 case ScreenWindowGrabbing: // whether QScreen::grabWindow() is supported
128 return false;
130 }
131}
132
134{
135 if ((window->surfaceType() == QWindow::OpenGLSurface || window->surfaceType() == QWindow::RasterGLSurface)
136 && mDisplay->clientBufferIntegration())
137 return mDisplay->clientBufferIntegration()->createEglWindow(window);
138
139#if QT_CONFIG(vulkan)
140 if (window->surfaceType() == QSurface::VulkanSurface)
141 return new QWaylandVulkanWindow(window, mDisplay.data());
142#endif // QT_CONFIG(vulkan)
143
144 return new QWaylandShmWindow(window, mDisplay.data());
145}
146
147#if QT_CONFIG(opengl)
149{
150 if (mDisplay->clientBufferIntegration())
151 return mDisplay->clientBufferIntegration()->createPlatformOpenGLContext(context->format(), context->shareHandle());
152 return nullptr;
153}
154#endif // opengl
155
160
162{
163 return createUnixEventDispatcher();
164}
165
170
171// Support platform specific initialization
172void QWaylandIntegration::initializePlatform()
173{
174 mDisplay->initEventThread();
175
176 mNativeInterface.reset(createPlatformNativeInterface());
177 initializeInputDeviceIntegration();
178#if QT_CONFIG(clipboard)
179 mClipboard.reset(new QWaylandClipboard(mDisplay.data()));
180#endif
181#if QT_CONFIG(draganddrop)
182 mDrag.reset(new QWaylandDrag(mDisplay.data()));
183#endif
184
186}
187
189{
190 initializePlatform();
191
192 // Call this after initializing event thread for QWaylandDisplay::flushRequests()
194 QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests()));
195 QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests()));
196
197 // Qt does not support running with no screens
198 mDisplay->ensureScreen();
199}
200
202{
203 return mFontDb.data();
204}
205
206#if QT_CONFIG(clipboard)
208{
209 return mClipboard.data();
210}
211#endif
212
213#if QT_CONFIG(draganddrop)
214QPlatformDrag *QWaylandIntegration::drag() const
215{
216 return mDrag.data();
217}
218#endif // draganddrop
219
224
226{
227 if (hint == ShowIsFullScreen && mDisplay->windowManagerIntegration())
228 return mDisplay->windowManagerIntegration()->showIsFullScreen();
229
231}
232
233#if QT_CONFIG(accessibility)
234QPlatformAccessibility *QWaylandIntegration::accessibility() const
235{
236 if (!mAccessibility) {
237#if QT_CONFIG(accessibility_atspi_bridge)
238 Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QWaylandIntegration",
239 "Initializing accessibility without event-dispatcher!");
240 mAccessibility.reset(new QSpiAccessibleBridge());
241#else
242 mAccessibility.reset(new QPlatformAccessibility());
243#endif
244 }
245 return mAccessibility.data();
246}
247#endif
248
250{
251 return mPlatformServices.data();
252}
253
255{
256 return mDisplay.data();
257}
258
260{
261 if (auto *seat = mDisplay->currentInputDevice(); seat && seat->keyboardFocus()) {
262 return seat->modifiers();
263 }
264 return Qt::NoModifier;
265}
266
268{
269 if (auto *seat = mDisplay->currentInputDevice())
270 return seat->possibleKeys(event);
271 return {};
272}
273
278
283
284QWaylandScreen *QWaylandIntegration::createPlatformScreen(QWaylandDisplay *waylandDisplay, int version, uint32_t id) const
285{
286 return new QWaylandScreen(waylandDisplay, version, id);
287}
288
290{
291 return new QWaylandCursor(display);
292}
293
294#if QT_CONFIG(vulkan)
295QPlatformVulkanInstance *QWaylandIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
296{
298}
299#endif // QT_CONFIG(vulkan)
300
301// May be called from non-GUI threads
303{
304 // Do an inexpensive check first to avoid locking whenever possible
305 if (Q_UNLIKELY(!mClientBufferIntegrationInitialized))
306 const_cast<QWaylandIntegration *>(this)->initializeClientBufferIntegration();
307
308 Q_ASSERT(mClientBufferIntegrationInitialized);
309 return mClientBufferIntegration && mClientBufferIntegration->isValid() ? mClientBufferIntegration.data() : nullptr;
310}
311
313{
314 if (!mServerBufferIntegrationInitialized)
315 const_cast<QWaylandIntegration *>(this)->initializeServerBufferIntegration();
316
317 return mServerBufferIntegration.data();
318}
319
321{
322 if (!mShellIntegrationInitialized)
323 const_cast<QWaylandIntegration *>(this)->initializeShellIntegration();
324
325 return mShellIntegration.data();
326}
327
328// May be called from non-GUI threads
329void QWaylandIntegration::initializeClientBufferIntegration()
330{
331 QMutexLocker lock(&mClientBufferInitLock);
332 if (mClientBufferIntegrationInitialized)
333 return;
334
335 QString targetKey = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION"));
336
337 if (targetKey.isEmpty()) {
338 if (mDisplay->hardwareIntegration()
339 && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("wayland-eglstream-controller")
340 && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("linux-dmabuf-unstable-v1")) {
341 targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration();
342 } else {
343 targetKey = QLatin1String("wayland-egl");
344 }
345 }
346
347 if (targetKey.isEmpty()) {
348 qWarning("Failed to determine what client buffer integration to use");
349 } else {
351 qCDebug(lcQpaWayland) << "Available client buffer integrations:" << keys;
352
353 if (keys.contains(targetKey))
355
357 qCDebug(lcQpaWayland) << "Initializing client buffer integration" << targetKey;
358 mClientBufferIntegration->initialize(mDisplay.data());
359 } else {
360 qCWarning(lcQpaWayland) << "Failed to load client buffer integration:" << targetKey;
361 qCWarning(lcQpaWayland) << "Available client buffer integrations:" << keys;
362 }
363 }
364
365 // This must be set last to make sure other threads don't use the
366 // integration before initialization is complete.
367 mClientBufferIntegrationInitialized = true;
368}
369
370void QWaylandIntegration::initializeServerBufferIntegration()
371{
372 mServerBufferIntegrationInitialized = true;
373
374 QString targetKey = QString::fromLocal8Bit(qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION"));
375
376 if (targetKey.isEmpty() && mDisplay->hardwareIntegration())
377 targetKey = mDisplay->hardwareIntegration()->serverBufferIntegration();
378
379 if (targetKey.isEmpty()) {
380 qWarning("Failed to determine what server buffer integration to use");
381 return;
382 }
383
385 qCDebug(lcQpaWayland) << "Available server buffer integrations:" << keys;
386
387 if (keys.contains(targetKey))
389
391 qCDebug(lcQpaWayland) << "Initializing server buffer integration" << targetKey;
392 mServerBufferIntegration->initialize(mDisplay.data());
393 } else {
394 qCWarning(lcQpaWayland) << "Failed to load server buffer integration: " << targetKey;
395 qCWarning(lcQpaWayland) << "Available server buffer integrations:" << keys;
396 }
397}
398
399void QWaylandIntegration::initializeShellIntegration()
400{
401 mShellIntegrationInitialized = true;
402
403 QByteArray integrationNames = qgetenv("QT_WAYLAND_SHELL_INTEGRATION");
404 QString targetKeys = QString::fromLocal8Bit(integrationNames);
405
406 QStringList preferredShells;
407 if (!targetKeys.isEmpty()) {
408 preferredShells = targetKeys.split(QLatin1Char(';'));
409 } else {
410 preferredShells << QLatin1String("xdg-shell");
411 preferredShells << QLatin1String("wl-shell") << QLatin1String("ivi-shell");
412 preferredShells << QLatin1String("qt-shell");
413 }
414
415 for (const QString &preferredShell : std::as_const(preferredShells)) {
416 mShellIntegration.reset(createShellIntegration(preferredShell));
417 if (mShellIntegration) {
418 qCDebug(lcQpaWayland, "Using the '%s' shell integration", qPrintable(preferredShell));
419 break;
420 }
421 }
422
423 if (!mShellIntegration) {
424 qCWarning(lcQpaWayland) << "Loading shell integration failed.";
425 qCWarning(lcQpaWayland) << "Attempted to load the following shells" << preferredShells;
426 }
427
429}
430
432{
434 return mInputDeviceIntegration->createInputDevice(display, version, id);
435 }
436 return new QWaylandInputDevice(display, version, id);
437}
438
439void QWaylandIntegration::initializeInputDeviceIntegration()
440{
441 QByteArray integrationName = qgetenv("QT_WAYLAND_INPUTDEVICE_INTEGRATION");
442 QString targetKey = QString::fromLocal8Bit(integrationName);
443
444 if (targetKey.isEmpty()) {
445 return;
446 }
447
449 if (keys.contains(targetKey)) {
451 qDebug("Using the '%s' input device integration", qPrintable(targetKey));
452 } else {
453 qWarning("Wayland inputdevice integration '%s' not found, using default", qPrintable(targetKey));
454 }
455}
456
458{
459 if (!mDisplay) {
460 // This function can be called from QWaylandDisplay::registry_global() when we
461 // are in process of constructing QWaylandDisplay. Configuring input context
462 // in that case is done by calling reconfigureInputContext() from QWaylandIntegration
463 // constructor, after QWaylandDisplay has been constructed.
464 return;
465 }
466
468 if (requested.contains(QLatin1String("qtvirtualkeyboard")))
469 qCWarning(lcQpaWayland) << "qtvirtualkeyboard currently is not supported at client-side,"
470 " use QT_IM_MODULES=qtvirtualkeyboard at compositor-side.";
471
472 if (mDisplay->isWaylandInputContextRequested()
473 && !requested.contains(QLatin1String(WAYLAND_IM_KEY)))
474 requested.append(QLatin1String(WAYLAND_IM_KEY));
475
476 const QString defaultInputContext(QStringLiteral("compose"));
477 if (!requested.contains(defaultInputContext))
478 requested.append(defaultInputContext);
479
480 for (const QString &imKey : requested) {
481 if (imKey == QLatin1String(WAYLAND_IM_KEY)) {
482 Q_ASSERT(mDisplay->isWaylandInputContextRequested());
483 if (mDisplay->textInputMethodManager() != nullptr)
485 else if (mDisplay->textInputManagerv1() != nullptr
486 || mDisplay->textInputManagerv2() != nullptr
487 || mDisplay->textInputManagerv3() != nullptr)
489 } else {
491 }
492
494 break;
495 }
496
497#if QT_CONFIG(xkbcommon)
499 if (QWaylandInputContext* waylandInput = qobject_cast<QWaylandInputContext*>(mInputContext.get())) {
500 waylandInput->setXkbContext(mDisplay->xkbContext());
501 }
502#endif
503
504 qCDebug(lcQpaWayland) << "using input method:" << (inputContext() ? inputContext()->metaObject()->className() : "<none>");
505}
506
507QWaylandShellIntegration *QWaylandIntegration::createShellIntegration(const QString &integrationName)
508{
509 if (QWaylandShellIntegrationFactory::keys().contains(integrationName)) {
510 return QWaylandShellIntegrationFactory::create(integrationName, mDisplay.data());
511 } else {
512 qCWarning(lcQpaWayland) << "No shell integration named" << integrationName << "found";
513 return nullptr;
514 }
515}
516
518{
520 mServerBufferIntegrationInitialized = false;
521
523
525 mClientBufferIntegrationInitialized = false;
526}
527
529{
530 mPlatformServices->setApplicationBadge(number);
531}
532}
533
\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:424
\inmodule QtCore
Definition qmutex.h:313
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\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:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
@ RasterGLSurface
Definition qsurface.h:33
@ OpenGLSurface
Definition qsurface.h:32
@ VulkanSurface
Definition qsurface.h:35
\inmodule QtCore
Definition qvariant.h:65
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)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
QPlatformFontDatabase QGenericUnixFontDatabase
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
#define qCDebug(category,...)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
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:1531
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:60
#define WAYLAND_IM_KEY
QStringList keys
QReadWriteLock lock
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
\inmodule QtCore \reentrant
Definition qchar.h:18