Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylandcompositor.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
2// Copyright (C) 2020 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:critical reason:network-protocol
5
9
10#include <QtWaylandCompositor/qwaylandclient.h>
11#include <QtWaylandCompositor/qwaylandseat.h>
12#include <QtWaylandCompositor/qwaylandoutput.h>
13#include <QtWaylandCompositor/qwaylandview.h>
14#include <QtWaylandCompositor/qwaylandclient.h>
15#include <QtWaylandCompositor/qwaylandkeyboard.h>
16#include <QtWaylandCompositor/qwaylandpointer.h>
17#include <QtWaylandCompositor/qwaylandtouch.h>
18#include <QtWaylandCompositor/qwaylandsurfacegrabber.h>
19
20#include <QtWaylandCompositor/private/qwaylandkeyboard_p.h>
21#include <QtWaylandCompositor/private/qwaylandsurface_p.h>
22
23#if QT_CONFIG(wayland_datadevice)
24#include "wayland_wrapper/qwldatadevice_p.h"
25#include "wayland_wrapper/qwldatadevicemanager_p.h"
26#endif
27#include "wayland_wrapper/qwlbuffermanager_p.h"
28
29#include "hardware_integration/qwlclientbufferintegration_p.h"
30#include "hardware_integration/qwlclientbufferintegrationfactory_p.h"
31#include "hardware_integration/qwlserverbufferintegration_p.h"
32#include "hardware_integration/qwlserverbufferintegrationfactory_p.h"
33
34#if QT_CONFIG(opengl)
35#include "hardware_integration/qwlhwintegration_p.h"
36#endif
37
38#include "extensions/qwaylandqtwindowmanager.h"
39
40#include "qwaylandsharedmemoryformathelper_p.h"
41
42#include <QtCore/QCoreApplication>
43#include <QtCore/QStringList>
44#include <QtCore/QSocketNotifier>
45#include <QStandardPaths>
46
47#include <QtGui/QDesktopServices>
48#include <QtGui/QScreen>
49
50#include <QtGui/qpa/qwindowsysteminterface_p.h>
51#include <QtGui/qpa/qplatformnativeinterface.h>
52#include <QtGui/private/qguiapplication_p.h>
53
54#if QT_CONFIG(opengl)
55# include <QOpenGLTextureBlitter>
56# include <QOpenGLTexture>
57# include <QOpenGLContext>
58# include <QOpenGLFramebufferObject>
59# include <QMatrix4x4>
60#endif
61
63
64// These logging categories are public symbols. To remain binary-compatible we cannot hide them in
65// a namespace like we do for all Qt-internal logging categories.
66#define Q_PUBLIC_LOGGING_CATEGORY(name, ...)
67 const QLoggingCategory &name()
68 {
69 static const QLoggingCategory category(__VA_ARGS__);
70 return category;
71 }
72
73Q_PUBLIC_LOGGING_CATEGORY(qLcWaylandCompositor, "qt.waylandcompositor")
74Q_PUBLIC_LOGGING_CATEGORY(qLcWaylandCompositorHardwareIntegration, "qt.waylandcompositor.hardwareintegration")
75Q_PUBLIC_LOGGING_CATEGORY(qLcWaylandCompositorInputMethods, "qt.waylandcompositor.inputmethods")
76Q_PUBLIC_LOGGING_CATEGORY(qLcWaylandCompositorTextInput, "qt.waylandcompositor.textinput")
77
78namespace QtWayland {
79
81{
82public:
83 WindowSystemEventHandler(QWaylandCompositor *c) : compositor(c) {}
84 bool sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) override
85 {
86 if (e->type == QWindowSystemInterfacePrivate::Key) {
87 QWindowSystemInterfacePrivate::KeyEvent *keyEvent = static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e);
88 handleKeyEvent(keyEvent);
89 } else {
90 QWindowSystemEventHandler::sendEvent(e);
91 }
92 return true;
93 }
94
95 void handleKeyEvent(QWindowSystemInterfacePrivate::KeyEvent *ke)
96 {
97 auto *seat = compositor->defaultSeat();
98 if (!seat)
99 return;
100
101 QWaylandKeyboardPrivate *keyb = QWaylandKeyboardPrivate::get(seat->keyboard());
102
103#if defined(Q_OS_QNX)
104 // The QNX platform plugin delivers scan codes that haven't been adjusted to be
105 // xkbcommon compatible. xkbcommon requires that the scan codes be bumped up by
106 // 8 because that's how evdev/XKB deliver scan codes. You might think that it
107 // would've been better to remove this (odd) requirement from xkbcommon on QNX
108 // but it turns out that conforming to it has much less impact.
109 static int offset = QGuiApplication::platformName() == QStringLiteral("qnx") ? 8 : 0;
110 ke->nativeScanCode += offset;
111#endif
112 uint32_t code = ke->nativeScanCode;
113 if (code == 0)
114 code = seat->keyboard()->keyToScanCode(ke->key);
115 bool isDown = ke->keyType == QEvent::KeyPress;
116
117#if QT_CONFIG(xkbcommon)
118 xkb_state *xkbState = keyb->xkbState();
119
120 const xkb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
121 Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(xkbState, sym);
122 int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, xkbState, code);
123 QString text = QXkbCommon::lookupString(xkbState, code);
124
125 ke->key = qtkey;
126 ke->modifiers = modifiers;
127 ke->nativeVirtualKey = sym;
128 ke->nativeModifiers = keyb->xkbModsMask();
129 ke->unicode = text;
130#endif
131 if (!ke->repeat)
132 keyb->keyEvent(code, isDown ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED);
133
134 QWindowSystemEventHandler::sendEvent(ke);
135
136 if (!ke->repeat) {
137 keyb->maybeUpdateKeymap();
138 keyb->updateModifierState(code, isDown ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED);
139 }
140 }
141
142 QWaylandCompositor *compositor = nullptr;
143};
144
145} // namespace
146
147QWaylandCompositorPrivate::QWaylandCompositorPrivate(QWaylandCompositor *compositor)
148{
149 // Create XDG_RUNTIME_DIR, if it does not already exist
150 QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
151
152 if (QGuiApplication::platformNativeInterface())
153 display = static_cast<wl_display*>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("server_wl_display"));
154
155 if (!display) {
156 display = wl_display_create();
157 ownsDisplay = true;
158 }
159
160 eventHandler.reset(new QtWayland::WindowSystemEventHandler(compositor));
161 timer.start();
162
163 QWindowSystemInterfacePrivate::installWindowSystemEventHandler(eventHandler.data());
164
165#if QT_CONFIG(xkbcommon)
166 mXkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
167 if (!mXkbContext) {
168 qWarning("Failed to create a XKB context: keymap will not be supported");
169 return;
170 }
171#endif
172}
173
174void QWaylandCompositorPrivate::init()
175{
176 Q_Q(QWaylandCompositor);
177 QStringList arguments = QCoreApplication::instance()->arguments();
178
179 if (socket_name.isEmpty()) {
180 const int socketArg = arguments.indexOf(QLatin1String("--wayland-socket-name"));
181 if (socketArg != -1 && socketArg + 1 < arguments.size())
182 socket_name = arguments.at(socketArg + 1).toLocal8Bit();
183 if (socket_name.isEmpty())
184 socket_name = qgetenv("WAYLAND_DISPLAY");
185 }
186 wl_compositor::init(display, 5);
187 wl_subcompositor::init(display, 1);
188
189#if QT_CONFIG(wayland_datadevice)
190 data_device_manager = new QtWayland::DataDeviceManager(q);
191#endif
192 buffer_manager = new QtWayland::BufferManager(q);
193
194 wl_display_init_shm(display);
195
196 for (QWaylandCompositor::ShmFormat format : std::as_const(shmFormats))
197 wl_display_add_shm_format(display, wl_shm_format(format));
198
199 if (!socket_name.isEmpty()) {
200 if (wl_display_add_socket(display, socket_name.constData()))
201 qFatal("Fatal: Failed to open server socket: \"%s\". XDG_RUNTIME_DIR is: \"%s\"\n", socket_name.constData(), getenv("XDG_RUNTIME_DIR"));
202 } else {
203 const char *autoSocketName = wl_display_add_socket_auto(display);
204 if (!autoSocketName)
205 qFatal("Fatal: Failed to open default server socket. XDG_RUNTIME_DIR is: \"%s\"\n", getenv("XDG_RUNTIME_DIR"));
206 socket_name = autoSocketName;
207 emit q->socketNameChanged(socket_name);
208 }
209
210 connectToExternalSockets();
211
212 loop = wl_display_get_event_loop(display);
213
214 int fd = wl_event_loop_get_fd(loop);
215
216 QSocketNotifier *sockNot = new QSocketNotifier(fd, QSocketNotifier::Read, q);
217 QObject::connect(sockNot, SIGNAL(activated(QSocketDescriptor)), q, SLOT(processWaylandEvents()));
218
219 QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
220 QObject::connect(dispatcher, SIGNAL(aboutToBlock()), q, SLOT(processWaylandEvents()));
221
222 QObject::connect(static_cast<QGuiApplication *>(QGuiApplication::instance()),
223 &QGuiApplication::applicationStateChanged,
224 q,
225 &QWaylandCompositor::applicationStateChanged);
226
227 initializeHardwareIntegration();
228 initializeSeats();
229
230 initialized = true;
231
232 for (const QPointer<QObject> &object : std::exchange(polish_objects, {})) {
233 if (object) {
234 QEvent polishEvent(QEvent::Polish);
235 QCoreApplication::sendEvent(object.data(), &polishEvent);
236 }
237 }
238
239 emit q->createdChanged();
240}
241
242QWaylandCompositorPrivate::~QWaylandCompositorPrivate()
243{
244 // Take copies, since the lists will get modified as elements are deleted
245 const auto clientsToDelete = clients;
246 qDeleteAll(clientsToDelete);
247
248 const auto outputsToDelete = outputs;
249 qDeleteAll(outputsToDelete);
250
251#if QT_CONFIG(wayland_datadevice)
252 delete data_device_manager;
253#endif
254
255 // Some client buffer integrations need to clean up before the destroying the wl_display
256 qDeleteAll(client_buffer_integrations);
257
258 if (ownsDisplay)
259 wl_display_destroy(display);
260}
261
262void QWaylandCompositorPrivate::preInit()
263{
264 Q_Q(QWaylandCompositor);
265
266 if (preInitialized)
267 return;
268
269 if (seats.empty())
270 seats.append(q->createSeat());
271
272 preInitialized = true;
273}
274
275void QWaylandCompositorPrivate::destroySurface(QWaylandSurface *surface)
276{
277 Q_Q(QWaylandCompositor);
278 q->surfaceAboutToBeDestroyed(surface);
279
280 delete surface;
281}
282
283void QWaylandCompositorPrivate::unregisterSurface(QWaylandSurface *surface)
284{
285 if (!all_surfaces.removeOne(surface))
286 qWarning("%s Unexpected state. Cant find registered surface\n", Q_FUNC_INFO);
287}
288
289void QWaylandCompositorPrivate::feedRetainedSelectionData(QMimeData *data)
290{
291 Q_Q(QWaylandCompositor);
292 if (retainSelection)
293 q->retainedSelectionReceived(data);
294}
295
296void QWaylandCompositorPrivate::addPolishObject(QObject *object)
297{
298 if (initialized) {
299 QCoreApplication::postEvent(object, new QEvent(QEvent::Polish));
300 } else {
301 polish_objects.push_back(object);
302 }
303}
304
305void QWaylandCompositorPrivate::connectToExternalSockets()
306{
307 // Clear out any backlog of user-supplied external socket descriptors
308 for (int fd : std::as_const(externally_added_socket_fds)) {
309 if (wl_display_add_socket_fd(display, fd) != 0)
310 qWarning() << "Failed to integrate user-supplied socket fd into the Wayland event loop";
311 }
312 externally_added_socket_fds.clear();
313}
314
315void QWaylandCompositorPrivate::compositor_create_surface(wl_compositor::Resource *resource, uint32_t id)
316{
317 Q_Q(QWaylandCompositor);
318 QWaylandClient *client = QWaylandClient::fromWlClient(q, resource->client());
319 emit q->surfaceRequested(client, id, resource->version());
320#ifndef QT_NO_DEBUG
321 Q_ASSERT_X(!QWaylandSurfacePrivate::hasUninitializedSurface(), "QWaylandCompositor", QStringLiteral("Found uninitialized QWaylandSurface after emitting QWaylandCompositor::createSurface for id %1. All surfaces has to be initialized immediately after creation. See QWaylandSurface::initialize.").arg(id).toLocal8Bit().constData());
322#endif
323 struct wl_resource *surfResource = wl_client_get_object(client->client(), id);
324
325 QWaylandSurface *surface = nullptr;
326 if (surfResource) {
327 surface = QWaylandSurface::fromResource(surfResource);
328 } else {
329 surface = createDefaultSurface();
330 surface->initialize(q, client, id, resource->version());
331 }
332 Q_ASSERT(surface);
333 all_surfaces.append(surface);
334 emit q->surfaceCreated(surface);
335}
336
337void QWaylandCompositorPrivate::compositor_create_region(wl_compositor::Resource *resource, uint32_t id)
338{
339 new QtWayland::Region(resource->client(), id);
340}
341
342void QWaylandCompositorPrivate::subcompositor_get_subsurface(wl_subcompositor::Resource *resource, uint32_t id, wl_resource *surface, wl_resource *parent)
343{
344 Q_Q(QWaylandCompositor);
345 QWaylandSurface *childSurface = QWaylandSurface::fromResource(surface);
346 QWaylandSurface *parentSurface = QWaylandSurface::fromResource(parent);
347
348 QWaylandSurfacePrivate *childSurface_d = QWaylandSurfacePrivate::get(childSurface);
349 QWaylandSurfacePrivate *parentSurface_d = QWaylandSurfacePrivate::get(parentSurface);
350 Q_ASSERT(childSurface_d != nullptr && parentSurface_d != nullptr);
351
352 // Walk the requested parent's existing ancestor chain and reject if it already includes the
353 // child surface.
354 for (QWaylandSurfacePrivate *ancestor = parentSurface_d;
355 ancestor != nullptr;
356 ancestor = ancestor->parentSurface()) {
357 if (ancestor == childSurface_d) {
358 wl_resource_post_error(resource->handle,
359 WL_SUBCOMPOSITOR_ERROR_BAD_PARENT,
360 "surface cannot be made a transitive parent of itself");
361 return;
362 }
363 }
364
365 QWaylandSurfacePrivate::get(childSurface)->initSubsurface(parentSurface, resource->client(), id, 1);
366 QWaylandSurfacePrivate::get(parentSurface)->subsurfaceChildren.append(childSurface);
367 emit q->subsurfaceChanged(childSurface, parentSurface);
368}
369
370/*!
371 \internal
372 Used to create a fallback QWaylandSurface when no surface was
373 created by emitting the QWaylandCompositor::createSurface signal.
374*/
375QWaylandSurface *QWaylandCompositorPrivate::createDefaultSurface()
376{
377 return new QWaylandSurface();
378}
379
381{
382public:
383 void initializeHardware(wl_display *display) override;
384 QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) override;
385};
386
390
392{
393 if (wl_shm_buffer_get(buffer))
394 return new QtWayland::SharedMemoryBuffer(buffer);
395 return nullptr;
396}
397
398void QWaylandCompositorPrivate::initializeHardwareIntegration()
399{
400 client_buffer_integrations.prepend(new SharedMemoryClientBufferIntegration); // TODO: clean up the opengl dependency
401
402#if QT_CONFIG(opengl)
403 Q_Q(QWaylandCompositor);
404 if (use_hw_integration_extension)
405 hw_integration.reset(new QtWayland::HardwareIntegration(q));
406
407 loadClientBufferIntegration();
408 loadServerBufferIntegration();
409
410 for (auto *integration : std::as_const(client_buffer_integrations))
411 integration->initializeHardware(display);
412#endif
413}
414
415void QWaylandCompositorPrivate::initializeSeats()
416{
417 for (QWaylandSeat *seat : std::as_const(seats))
418 seat->initialize();
419}
420
421void QWaylandCompositorPrivate::loadClientBufferIntegration()
422{
423#if QT_CONFIG(opengl)
424 Q_Q(QWaylandCompositor);
425 QStringList keys = QtWayland::ClientBufferIntegrationFactory::keys();
426 QStringList targetKeys;
427 QByteArray clientBufferIntegration = qgetenv("QT_WAYLAND_HARDWARE_INTEGRATION");
428 if (clientBufferIntegration.isEmpty())
429 clientBufferIntegration = qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION");
430
431 const QList<QByteArray> clientBufferIntegrations = clientBufferIntegration.split(';');
432 for (const auto &b : clientBufferIntegrations) {
433 QString s = QString::fromLocal8Bit(b);
434 if (keys.contains(s))
435 targetKeys.append(s);
436 }
437
438 if (!clientBufferIntegration.isEmpty() && targetKeys.isEmpty()) {
439 qCWarning(qLcWaylandCompositorHardwareIntegration)
440 << "Failed to find any requested client buffer integration:"
441 << clientBufferIntegration
442 << ", available integrations:"
443 << keys;
444 }
445
446 if (targetKeys.isEmpty()) {
447 if (keys.contains(QString::fromLatin1("wayland-egl"))) {
448 targetKeys.append(QString::fromLatin1("wayland-egl"));
449 } else if (!keys.isEmpty()) {
450 targetKeys.append(keys.first());
451 }
452 }
453
454 QString hwIntegrationName;
455
456 for (const auto &targetKey : std::as_const(targetKeys)) {
457 auto *integration = QtWayland::ClientBufferIntegrationFactory::create(targetKey, QStringList());
458 if (integration) {
459 integration->setCompositor(q);
460 client_buffer_integrations.append(integration);
461 if (hwIntegrationName.isEmpty())
462 hwIntegrationName = targetKey;
463 }
464 }
465
466 if (hw_integration && !hwIntegrationName.isEmpty())
467 hw_integration->setClientBufferIntegrationName(hwIntegrationName);
468
469#endif
470}
471
472void QWaylandCompositorPrivate::loadServerBufferIntegration()
473{
474#if QT_CONFIG(opengl)
475 Q_Q(QWaylandCompositor);
476 QStringList keys = QtWayland::ServerBufferIntegrationFactory::keys();
477 QString targetKey;
478 QByteArray serverBufferIntegration = qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION");
479 if (keys.contains(QString::fromLocal8Bit(serverBufferIntegration.constData()))) {
480 targetKey = QString::fromLocal8Bit(serverBufferIntegration.constData());
481 }
482 if (!targetKey.isEmpty()) {
483 server_buffer_integration.reset(QtWayland::ServerBufferIntegrationFactory::create(targetKey, QStringList()));
484 if (server_buffer_integration) {
485 qCDebug(qLcWaylandCompositorHardwareIntegration)
486 << "Loaded server buffer integration:" << targetKey;
487 if (!server_buffer_integration->initializeHardware(q)) {
488 qCWarning(qLcWaylandCompositorHardwareIntegration)
489 << "Failed to initialize hardware for server buffer integration:" << targetKey;
490 server_buffer_integration.reset();
491 }
492 } else {
493 qCWarning(qLcWaylandCompositorHardwareIntegration)
494 << "Failed to load server buffer integration:" << targetKey;
495 }
496 }
497
498 if (server_buffer_integration && hw_integration)
499 hw_integration->setServerBufferIntegrationName(targetKey);
500#endif
501}
502
503QWaylandSeat *QWaylandCompositorPrivate::seatFor(QInputEvent *inputEvent)
504{
505 QWaylandSeat *dev = nullptr;
506 for (int i = 0; i < seats.size(); i++) {
507 QWaylandSeat *candidate = seats.at(i);
508 if (candidate->isOwner(inputEvent)) {
509 dev = candidate;
510 break;
511 }
512 }
513 return dev;
514}
515
516/*!
517 \qmltype WaylandCompositor
518 \nativetype QWaylandCompositor
519 \inqmlmodule QtWayland.Compositor
520 \since 5.8
521 \brief Manages the Wayland display server.
522
523 The WaylandCompositor manages the connections to the clients, as well as the different
524 \l{WaylandOutput}{outputs} and \l{QWaylandSeat}{seats}.
525
526 Normally, a compositor application will have a single WaylandCompositor
527 instance, which can have several outputs as children. When a client
528 requests the compositor to create a surface, the request is handled by
529 the onSurfaceRequested handler.
530
531 Extensions that are supported by the compositor should be instantiated and added to the
532 extensions property or simply as direct children of WaylandCompositor.
533*/
534
535
536/*!
537 \class QWaylandCompositor
538 \inmodule QtWaylandCompositor
539 \since 5.8
540 \brief The QWaylandCompositor class manages the Wayland display server.
541
542 The QWaylandCompositor manages the connections to the clients, as well as the different \l{QWaylandOutput}{outputs}
543 and \l{QWaylandSeat}{seats}.
544
545 Normally, a compositor application will have a single WaylandCompositor
546 instance, which can have several outputs as children.
547*/
548
549/*!
550 \qmlsignal void QtWayland.Compositor::WaylandCompositor::surfaceRequested(WaylandClient client, int id, int version)
551
552 This signal is emitted when a \a client has created a surface with id \a id.
553 The interface \a version is also available.
554
555 The slot connecting to this signal may create and initialize a WaylandSurface
556 instance in the scope of the slot. Otherwise a default surface is created.
557*/
558
559/*!
560 \fn void QWaylandCompositor::surfaceRequested(QWaylandClient *client, uint id, int version)
561
562 This signal is emitted when a \a client has created a surface with id \a id.
563 The interface \a version is also available.
564
565 The slot connecting to this signal may create and initialize a QWaylandSurface
566 instance in the scope of the slot. Otherwise a default surface is created.
567
568 Connections to this signal must be of Qt::DirectConnection connection type.
569*/
570
571/*!
572 \qmlsignal void QtWayland.Compositor::WaylandCompositor::surfaceCreated(WaylandSurface surface)
573
574 This signal is emitted when a new WaylandSurface instance \a surface has been created.
575*/
576
577/*!
578 \fn void QWaylandCompositor::surfaceCreated(QWaylandSurface *surface)
579
580 This signal is emitted when a new QWaylandSurface instance \a surface has been created.
581*/
582
583/*!
584 * Constructs a QWaylandCompositor with the given \a parent.
585 */
586QWaylandCompositor::QWaylandCompositor(QObject *parent)
587 : QWaylandObject(*new QWaylandCompositorPrivate(this), parent)
588{
589}
590
591/*!
592 * \internal
593 * Constructs a QWaylandCompositor with the private object \a dptr and \a parent.
594 */
595QWaylandCompositor::QWaylandCompositor(QWaylandCompositorPrivate &dptr, QObject *parent)
596 : QWaylandObject(dptr, parent)
597{
598}
599
600/*!
601 * Destroys the QWaylandCompositor
602 */
603QWaylandCompositor::~QWaylandCompositor()
604{
605}
606
607/*!
608 * Initializes the QWaylandCompositor.
609 * If you override this function in your subclass, be sure to call the base class implementation.
610 */
611void QWaylandCompositor::create()
612{
613 Q_D(QWaylandCompositor);
614 d->preInit();
615 d->init();
616}
617
618/*!
619 * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::created
620 *
621 * This property is true if WaylandCompositor has been initialized,
622 * otherwise it's false.
623 */
624
625/*!
626 * \property QWaylandCompositor::created
627 *
628 * This property is true if QWaylandCompositor has been initialized,
629 * otherwise it's false.
630 */
631bool QWaylandCompositor::isCreated() const
632{
633 Q_D(const QWaylandCompositor);
634 return d->initialized;
635}
636
637/*!
638 * \qmlproperty string QtWayland.Compositor::WaylandCompositor::socketName
639 *
640 * This property holds the socket name used by WaylandCompositor to communicate with
641 * clients. It must be set before the component is completed.
642 *
643 * If the socketName is empty (the default), the contents of the start argument
644 * \c --wayland-socket-name are used instead. If the argument is not set, the
645 * compositor tries to find a socket name, which is \c{wayland-0} by default.
646 */
647
648/*!
649 * \property QWaylandCompositor::socketName
650 *
651 * This property holds the socket name used by QWaylandCompositor to communicate with
652 * clients. This must be set before the QWaylandCompositor is \l{create()}{created}.
653 *
654 * If the socketName is empty (the default), the contents of the start argument
655 * \c --wayland-socket-name are used instead. If the argument is not set, the
656 * compositor tries to find a socket name, which is \c{wayland-0} by default.
657 */
658void QWaylandCompositor::setSocketName(const QByteArray &name)
659{
660 Q_D(QWaylandCompositor);
661
662 if (d->socket_name == name)
663 return;
664
665 if (d->initialized) {
666 qWarning("%s: Changing socket name after initializing the compositor is not supported.\n", Q_FUNC_INFO);
667 return;
668 }
669
670 d->socket_name = name;
671 emit socketNameChanged(name);
672}
673
674QByteArray QWaylandCompositor::socketName() const
675{
676 Q_D(const QWaylandCompositor);
677 return d->socket_name;
678}
679
680/*!
681 * \qmlmethod void QtWayland.Compositor::WaylandCompositor::addSocketDescriptor(fd)
682 * \since 5.12
683 *
684 * Listen for client connections on a file descriptor, \a fd, referring to a
685 * server socket already bound and listening.
686 *
687 * Does not take ownership of the file descriptor; it must be closed
688 * explicitly if needed.
689 *
690 * \note This method is only available with libwayland 1.10.0 or
691 * newer. If built against an earlier libwayland runtime, this
692 * method is a noop.
693 */
694
695/*!
696 * Listen for client connections on a file descriptor, \a fd, referring to a
697 * server socket already bound and listening.
698 *
699 * Does not take ownership of the file descriptor; it must be closed
700 * explicitly if needed.
701 *
702 * \note This method is only available with libwayland 1.10.0 or
703 * newer. If built against an earlier libwayland runtime, this
704 * method is a noop.
705 *
706 * \since 5.12
707 */
708void QWaylandCompositor::addSocketDescriptor(int fd)
709{
710 Q_D(QWaylandCompositor);
711 d->externally_added_socket_fds.append(fd);
712 if (isCreated())
713 d->connectToExternalSockets();
714}
715
716/*!
717 * \internal
718 */
719struct wl_display *QWaylandCompositor::display() const
720{
721 Q_D(const QWaylandCompositor);
722 return d->display;
723}
724
725/*!
726 * \internal
727 */
728uint32_t QWaylandCompositor::nextSerial()
729{
730 Q_D(QWaylandCompositor);
731 return wl_display_next_serial(d->display);
732}
733
734/*!
735 * \internal
736 */
737QList<QWaylandClient *>QWaylandCompositor::clients() const
738{
739 Q_D(const QWaylandCompositor);
740 return d->clients;
741}
742
743/*!
744 * \qmlmethod void QtWayland.Compositor::WaylandCompositor::destroyClientForSurface(surface)
745 *
746 * From the compositor side, destroys the client to which the WaylandSurface \a surface belongs
747 * by disconnecting from it.
748 */
749
750/*!
751 * Destroys the client for the \a surface.
752 */
753void QWaylandCompositor::destroyClientForSurface(QWaylandSurface *surface)
754{
755 destroyClient(surface->client());
756}
757
758/*!
759 * \qmlmethod void QtWayland.Compositor::WaylandCompositor::destroyClient(client)
760 *
761 * From the compositor side, destroys the given WaylandClient \a client by disconnecting from it.
762 */
763
764/*!
765 * Destroys the \a client.
766 */
767void QWaylandCompositor::destroyClient(QWaylandClient *client)
768{
769 if (!client)
770 return;
771
772 QWaylandQtWindowManager *wmExtension = QWaylandQtWindowManager::findIn(this);
773 if (wmExtension)
774 wmExtension->sendQuitMessage(client);
775
776 wl_client_destroy(client->client());
777}
778
779/*!
780 * \internal
781 */
782QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(QWaylandClient* client) const
783{
784 Q_D(const QWaylandCompositor);
785 QList<QWaylandSurface *> surfs;
786 for (QWaylandSurface *surface : d->all_surfaces) {
787 if (surface->client() == client)
788 surfs.append(surface);
789 }
790 return surfs;
791}
792
793/*!
794 * \internal
795 */
796QList<QWaylandSurface *> QWaylandCompositor::surfaces() const
797{
798 Q_D(const QWaylandCompositor);
799 return d->all_surfaces;
800}
801
802/*!
803 * Returns the QWaylandOutput that is connected to the given \a window.
804 */
805QWaylandOutput *QWaylandCompositor::outputFor(QWindow *window) const
806{
807 Q_D(const QWaylandCompositor);
808 for (QWaylandOutput *output : d->outputs) {
809 if (output->window() == window)
810 return output;
811 }
812
813 return nullptr;
814}
815
816/*!
817 * \qmlproperty WaylandOutput QtWayland.Compositor::WaylandCompositor::defaultOutput
818 *
819 * This property contains the first in the list of outputs added to the
820 * WaylandCompositor, or null if no outputs have been added.
821 *
822 * Setting a new default output prepends it to the output list, making
823 * it the new default, but the previous default is not removed from
824 * the list.
825 */
826/*!
827 * \property QWaylandCompositor::defaultOutput
828 *
829 * This property contains the first in the list of outputs added to the
830 * QWaylandCompositor, or null if no outputs have been added.
831 *
832 * Setting a new default output prepends it to the output list, making
833 * it the new default, but the previous default is not removed from
834 * the list. If the new default output was already in the list of outputs,
835 * it is moved to the beginning of the list.
836 */
837QWaylandOutput *QWaylandCompositor::defaultOutput() const
838{
839 Q_D(const QWaylandCompositor);
840 return d->defaultOutput();
841}
842
843void QWaylandCompositor::setDefaultOutput(QWaylandOutput *output)
844{
845 Q_D(QWaylandCompositor);
846 if (Q_UNLIKELY(!output)) {
847 qWarning("Changing default output to null is not supported");
848 return;
849 }
850 if (d->outputs.size() && d->outputs.first() == output)
851 return;
852 bool alreadyAdded = d->outputs.removeOne(output);
853 d->outputs.prepend(output);
854 if (!alreadyAdded)
855 emit outputAdded(output);
856 emit defaultOutputChanged();
857}
858
859/*!
860 * \internal
861 */
862QList<QWaylandOutput *> QWaylandCompositor::outputs() const
863{
864 Q_D(const QWaylandCompositor);
865 return d->outputs;
866}
867
868/*!
869 * \internal
870 */
871uint QWaylandCompositor::currentTimeMsecs() const
872{
873 Q_D(const QWaylandCompositor);
874 return d->timer.elapsed();
875}
876
877/*!
878 * \internal
879 */
880void QWaylandCompositor::processWaylandEvents()
881{
882 Q_D(QWaylandCompositor);
883 int ret = wl_event_loop_dispatch(d->loop, 0);
884 if (ret)
885 fprintf(stderr, "wl_event_loop_dispatch error: %d\n", ret);
886 wl_display_flush_clients(d->display);
887}
888
889/*!
890 * \internal
891 */
892QWaylandSeat *QWaylandCompositor::createSeat()
893{
894 return new QWaylandSeat(this);
895}
896
897/*!
898 * \internal
899 */
900QWaylandPointer *QWaylandCompositor::createPointerDevice(QWaylandSeat *seat)
901{
902 return new QWaylandPointer(seat);
903}
904
905/*!
906 * \internal
907 */
908QWaylandKeyboard *QWaylandCompositor::createKeyboardDevice(QWaylandSeat *seat)
909{
910 return new QWaylandKeyboard(seat);
911}
912
913/*!
914 * \internal
915 */
916QWaylandTouch *QWaylandCompositor::createTouchDevice(QWaylandSeat *seat)
917{
918 return new QWaylandTouch(seat);
919}
920
921/*!
922 * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::retainedSelection
923 * \default false
924 *
925 * This property controls whether the compositor retains a copy of clipboard selection data.
926 * When \c true, the compositor eagerly reads and caches all clipboard data from the owning client.
927 * This incurs a performance cost.
928 */
929
930/*!
931 * \property QWaylandCompositor::retainedSelection
932 *
933 * This property controls whether the compositor retains a copy of clipboard selection data.
934 * When \c true, the compositor eagerly reads and caches all clipboard data from the owning client.
935 * This incurs a performance cost. The default is \c false.
936 *
937 * \sa QWaylandCompositor::retainedSelectionReceived(), QWaylandSurface::updateSelection()
938 */
939void QWaylandCompositor::setRetainedSelectionEnabled(bool enabled)
940{
941 Q_D(QWaylandCompositor);
942
943 if (d->retainSelection == enabled)
944 return;
945
946 d->retainSelection = enabled;
947 emit retainedSelectionChanged(enabled);
948}
949
950bool QWaylandCompositor::retainedSelectionEnabled() const
951{
952 Q_D(const QWaylandCompositor);
953 return d->retainSelection;
954}
955
956/*!
957 * \internal
958 */
959void QWaylandCompositor::retainedSelectionReceived(QMimeData *)
960{
961}
962
963/*!
964 * \internal
965 */
966void QWaylandCompositor::overrideSelection(const QMimeData *data)
967{
968 Q_D(QWaylandCompositor);
969#if QT_CONFIG(wayland_datadevice)
970 d->data_device_manager->overrideSelection(*data);
971#endif
972}
973
974/*!
975 * \qmlproperty WaylandSeat QtWayland.Compositor::WaylandCompositor::defaultSeat
976 *
977 * This property contains the default seat for this
978 * WaylandCompositor.
979 */
980
981/*!
982 * \property QWaylandCompositor::defaultSeat
983 *
984 * This property contains the default seat for this
985 * QWaylandCompositor.
986 */
987QWaylandSeat *QWaylandCompositor::defaultSeat() const
988{
989 Q_D(const QWaylandCompositor);
990 if (d->seats.size())
991 return d->seats.first();
992 return nullptr;
993}
994
995/*!
996 * Select the seat for a given input event \a inputEvent.
997 * Currently, Qt only supports a single seat.
998 */
999QWaylandSeat *QWaylandCompositor::seatFor(QInputEvent *inputEvent)
1000{
1001 Q_D(QWaylandCompositor);
1002 return d->seatFor(inputEvent);
1003}
1004
1005/*!
1006 * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::useHardwareIntegrationExtension
1007 * \default true
1008 *
1009 * This property holds whether the hardware integration extension should be enabled for
1010 * this WaylandCompositor.
1011 *
1012 * This property must be set before the compositor component is completed.
1013 */
1014
1015/*!
1016 * \property QWaylandCompositor::useHardwareIntegrationExtension
1017 *
1018 * This property holds whether the hardware integration extension should be enabled for
1019 * this QWaylandCompositor.
1020 *
1021 * This property must be set before the compositor is \l{create()}{created}.
1022 */
1023bool QWaylandCompositor::useHardwareIntegrationExtension() const
1024{
1025#if QT_CONFIG(opengl)
1026 Q_D(const QWaylandCompositor);
1027 return d->use_hw_integration_extension;
1028#else
1029 return false;
1030#endif
1031}
1032
1033void QWaylandCompositor::setUseHardwareIntegrationExtension(bool use)
1034{
1035#if QT_CONFIG(opengl)
1036 Q_D(QWaylandCompositor);
1037 if (use == d->use_hw_integration_extension)
1038 return;
1039
1040 if (d->initialized)
1041 qWarning("Setting QWaylandCompositor::useHardwareIntegrationExtension after initialization has no effect");
1042
1043 d->use_hw_integration_extension = use;
1044 useHardwareIntegrationExtensionChanged();
1045#else
1046 if (use)
1047 qWarning() << "Hardware integration not supported without OpenGL support";
1048#endif
1049}
1050
1051/*!
1052 * Grab the surface content from the given \a buffer.
1053 * The default implementation requires a OpenGL context to be bound to the current thread
1054 * to work. If this is not possible, reimplement this function in your compositor subclass
1055 * to implement custom logic.
1056 * The default implementation only grabs shared memory and OpenGL buffers, reimplement this in your
1057 * compositor subclass to handle more buffer types.
1058 * \note You should not call this manually, but rather use QWaylandSurfaceGrabber (\a grabber).
1059 */
1060void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWaylandBufferRef &buffer)
1061{
1062 if (buffer.isSharedMemory()) {
1063 emit grabber->success(buffer.image());
1064 } else {
1065#if QT_CONFIG(opengl)
1066 if (QOpenGLContext::currentContext()) {
1067 QOpenGLFramebufferObject fbo(buffer.size());
1068 fbo.bind();
1069 QOpenGLTextureBlitter blitter;
1070 blitter.create();
1071
1072
1073 glViewport(0, 0, buffer.size().width(), buffer.size().height());
1074
1075 QOpenGLTextureBlitter::Origin surfaceOrigin =
1076 buffer.origin() == QWaylandSurface::OriginTopLeft
1077 ? QOpenGLTextureBlitter::OriginTopLeft
1078 : QOpenGLTextureBlitter::OriginBottomLeft;
1079
1080 auto texture = buffer.toOpenGLTexture();
1081 blitter.bind(texture->target());
1082 blitter.blit(texture->textureId(), QMatrix4x4(), surfaceOrigin);
1083 blitter.release();
1084
1085 emit grabber->success(fbo.toImage());
1086 } else
1087#endif
1088 emit grabber->failed(QWaylandSurfaceGrabber::UnknownBufferType);
1089 }
1090}
1091
1092/*!
1093 * \qmlproperty list<enum> QtWayland.Compositor::WaylandCompositor::additionalShmFormats
1094 *
1095 * This property holds the list of additional wl_shm formats advertised as supported by the
1096 * compositor.
1097 *
1098 * By default, only the required ShmFormat_ARGB8888 and ShmFormat_XRGB8888 are listed and this
1099 * list will be empty. Additional formats may require conversion internally and can thus affect
1100 * performance.
1101 *
1102 * This property must be set before the compositor component is completed. Subsequent changes
1103 * will have no effect.
1104 *
1105 * \since 6.0
1106 */
1107
1108/*!
1109 * \property QWaylandCompositor::additionalShmFormats
1110 *
1111 * This property holds the list of additional wl_shm formats advertised as supported by the
1112 * compositor.
1113 *
1114 * By default, only the required ShmFormat_ARGB8888 and ShmFormat_XRGB8888 are listed and this
1115 * list will be empty.
1116 *
1117 * This property must be set before the compositor is \l{create()}{created}. Subsequent changes
1118 * will have no effect.
1119 *
1120 * \since 6.0
1121 */
1122void QWaylandCompositor::setAdditionalShmFormats(const QVector<ShmFormat> &additionalShmFormats)
1123{
1124 Q_D(QWaylandCompositor);
1125 if (d->initialized)
1126 qCWarning(qLcWaylandCompositorHardwareIntegration) << "Setting QWaylandCompositor::additionalShmFormats after initialization has no effect";
1127
1128 d->shmFormats = additionalShmFormats;
1129 emit additionalShmFormatsChanged();
1130}
1131
1132QVector<QWaylandCompositor::ShmFormat> QWaylandCompositor::additionalShmFormats() const
1133{
1134 Q_D(const QWaylandCompositor);
1135 return d->shmFormats;
1136}
1137
1138void QWaylandCompositor::applicationStateChanged(Qt::ApplicationState state)
1139{
1140#if QT_CONFIG(xkbcommon)
1141 if (state == Qt::ApplicationInactive) {
1142 auto *seat = defaultSeat();
1143 if (seat != nullptr) {
1144 QWaylandKeyboardPrivate *keyb = QWaylandKeyboardPrivate::get(seat->keyboard());
1145 keyb->resetKeyboardState();
1146 }
1147 }
1148#else
1149 Q_UNUSED(state);
1150#endif
1151}
1152
1153QT_END_NAMESPACE
1154
1155#include "moc_qwaylandcompositor.cpp"
void handleKeyEvent(QWindowSystemInterfacePrivate::KeyEvent *ke)
bool sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) override
WindowSystemEventHandler(QWaylandCompositor *c)
QtWayland::ClientBuffer * createBufferFor(wl_resource *buffer) override
void initializeHardware(wl_display *display) override
Combined button and popup list for selecting options.
#define Q_PUBLIC_LOGGING_CATEGORY(name,...)
const QLoggingCategory & qLcWaylandCompositorTextInput()
const QLoggingCategory & qLcWaylandCompositorInputMethods()