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 QWaylandSurfacePrivate::get(childSurface)->initSubsurface(parentSurface, resource->client(), id, 1);
348 QWaylandSurfacePrivate::get(parentSurface)->subsurfaceChildren.append(childSurface);
349 emit q->subsurfaceChanged(childSurface, parentSurface);
350}
351
352/*!
353 \internal
354 Used to create a fallback QWaylandSurface when no surface was
355 created by emitting the QWaylandCompositor::createSurface signal.
356*/
357QWaylandSurface *QWaylandCompositorPrivate::createDefaultSurface()
358{
359 return new QWaylandSurface();
360}
361
363{
364public:
365 void initializeHardware(wl_display *display) override;
366 QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) override;
367};
368
372
374{
375 if (wl_shm_buffer_get(buffer))
376 return new QtWayland::SharedMemoryBuffer(buffer);
377 return nullptr;
378}
379
380void QWaylandCompositorPrivate::initializeHardwareIntegration()
381{
382 client_buffer_integrations.prepend(new SharedMemoryClientBufferIntegration); // TODO: clean up the opengl dependency
383
384#if QT_CONFIG(opengl)
385 Q_Q(QWaylandCompositor);
386 if (use_hw_integration_extension)
387 hw_integration.reset(new QtWayland::HardwareIntegration(q));
388
389 loadClientBufferIntegration();
390 loadServerBufferIntegration();
391
392 for (auto *integration : std::as_const(client_buffer_integrations))
393 integration->initializeHardware(display);
394#endif
395}
396
397void QWaylandCompositorPrivate::initializeSeats()
398{
399 for (QWaylandSeat *seat : std::as_const(seats))
400 seat->initialize();
401}
402
403void QWaylandCompositorPrivate::loadClientBufferIntegration()
404{
405#if QT_CONFIG(opengl)
406 Q_Q(QWaylandCompositor);
407 QStringList keys = QtWayland::ClientBufferIntegrationFactory::keys();
408 QStringList targetKeys;
409 QByteArray clientBufferIntegration = qgetenv("QT_WAYLAND_HARDWARE_INTEGRATION");
410 if (clientBufferIntegration.isEmpty())
411 clientBufferIntegration = qgetenv("QT_WAYLAND_CLIENT_BUFFER_INTEGRATION");
412
413 const QList<QByteArray> clientBufferIntegrations = clientBufferIntegration.split(';');
414 for (const auto &b : clientBufferIntegrations) {
415 QString s = QString::fromLocal8Bit(b);
416 if (keys.contains(s))
417 targetKeys.append(s);
418 }
419
420 if (!clientBufferIntegration.isEmpty() && targetKeys.isEmpty()) {
421 qCWarning(qLcWaylandCompositorHardwareIntegration)
422 << "Failed to find any requested client buffer integration:"
423 << clientBufferIntegration
424 << ", available integrations:"
425 << keys;
426 }
427
428 if (targetKeys.isEmpty()) {
429 if (keys.contains(QString::fromLatin1("wayland-egl"))) {
430 targetKeys.append(QString::fromLatin1("wayland-egl"));
431 } else if (!keys.isEmpty()) {
432 targetKeys.append(keys.first());
433 }
434 }
435
436 QString hwIntegrationName;
437
438 for (const auto &targetKey : std::as_const(targetKeys)) {
439 auto *integration = QtWayland::ClientBufferIntegrationFactory::create(targetKey, QStringList());
440 if (integration) {
441 integration->setCompositor(q);
442 client_buffer_integrations.append(integration);
443 if (hwIntegrationName.isEmpty())
444 hwIntegrationName = targetKey;
445 }
446 }
447
448 if (hw_integration && !hwIntegrationName.isEmpty())
449 hw_integration->setClientBufferIntegrationName(hwIntegrationName);
450
451#endif
452}
453
454void QWaylandCompositorPrivate::loadServerBufferIntegration()
455{
456#if QT_CONFIG(opengl)
457 Q_Q(QWaylandCompositor);
458 QStringList keys = QtWayland::ServerBufferIntegrationFactory::keys();
459 QString targetKey;
460 QByteArray serverBufferIntegration = qgetenv("QT_WAYLAND_SERVER_BUFFER_INTEGRATION");
461 if (keys.contains(QString::fromLocal8Bit(serverBufferIntegration.constData()))) {
462 targetKey = QString::fromLocal8Bit(serverBufferIntegration.constData());
463 }
464 if (!targetKey.isEmpty()) {
465 server_buffer_integration.reset(QtWayland::ServerBufferIntegrationFactory::create(targetKey, QStringList()));
466 if (server_buffer_integration) {
467 qCDebug(qLcWaylandCompositorHardwareIntegration)
468 << "Loaded server buffer integration:" << targetKey;
469 if (!server_buffer_integration->initializeHardware(q)) {
470 qCWarning(qLcWaylandCompositorHardwareIntegration)
471 << "Failed to initialize hardware for server buffer integration:" << targetKey;
472 server_buffer_integration.reset();
473 }
474 } else {
475 qCWarning(qLcWaylandCompositorHardwareIntegration)
476 << "Failed to load server buffer integration:" << targetKey;
477 }
478 }
479
480 if (server_buffer_integration && hw_integration)
481 hw_integration->setServerBufferIntegrationName(targetKey);
482#endif
483}
484
485QWaylandSeat *QWaylandCompositorPrivate::seatFor(QInputEvent *inputEvent)
486{
487 QWaylandSeat *dev = nullptr;
488 for (int i = 0; i < seats.size(); i++) {
489 QWaylandSeat *candidate = seats.at(i);
490 if (candidate->isOwner(inputEvent)) {
491 dev = candidate;
492 break;
493 }
494 }
495 return dev;
496}
497
498/*!
499 \qmltype WaylandCompositor
500 \nativetype QWaylandCompositor
501 \inqmlmodule QtWayland.Compositor
502 \since 5.8
503 \brief Manages the Wayland display server.
504
505 The WaylandCompositor manages the connections to the clients, as well as the different
506 \l{WaylandOutput}{outputs} and \l{QWaylandSeat}{seats}.
507
508 Normally, a compositor application will have a single WaylandCompositor
509 instance, which can have several outputs as children. When a client
510 requests the compositor to create a surface, the request is handled by
511 the onSurfaceRequested handler.
512
513 Extensions that are supported by the compositor should be instantiated and added to the
514 extensions property or simply as direct children of WaylandCompositor.
515*/
516
517
518/*!
519 \class QWaylandCompositor
520 \inmodule QtWaylandCompositor
521 \since 5.8
522 \brief The QWaylandCompositor class manages the Wayland display server.
523
524 The QWaylandCompositor manages the connections to the clients, as well as the different \l{QWaylandOutput}{outputs}
525 and \l{QWaylandSeat}{seats}.
526
527 Normally, a compositor application will have a single WaylandCompositor
528 instance, which can have several outputs as children.
529*/
530
531/*!
532 \qmlsignal void QtWayland.Compositor::WaylandCompositor::surfaceRequested(WaylandClient client, int id, int version)
533
534 This signal is emitted when a \a client has created a surface with id \a id.
535 The interface \a version is also available.
536
537 The slot connecting to this signal may create and initialize a WaylandSurface
538 instance in the scope of the slot. Otherwise a default surface is created.
539*/
540
541/*!
542 \fn void QWaylandCompositor::surfaceRequested(QWaylandClient *client, uint id, int version)
543
544 This signal is emitted when a \a client has created a surface with id \a id.
545 The interface \a version is also available.
546
547 The slot connecting to this signal may create and initialize a QWaylandSurface
548 instance in the scope of the slot. Otherwise a default surface is created.
549
550 Connections to this signal must be of Qt::DirectConnection connection type.
551*/
552
553/*!
554 \qmlsignal void QtWayland.Compositor::WaylandCompositor::surfaceCreated(WaylandSurface surface)
555
556 This signal is emitted when a new WaylandSurface instance \a surface has been created.
557*/
558
559/*!
560 \fn void QWaylandCompositor::surfaceCreated(QWaylandSurface *surface)
561
562 This signal is emitted when a new QWaylandSurface instance \a surface has been created.
563*/
564
565/*!
566 * Constructs a QWaylandCompositor with the given \a parent.
567 */
568QWaylandCompositor::QWaylandCompositor(QObject *parent)
569 : QWaylandObject(*new QWaylandCompositorPrivate(this), parent)
570{
571}
572
573/*!
574 * \internal
575 * Constructs a QWaylandCompositor with the private object \a dptr and \a parent.
576 */
577QWaylandCompositor::QWaylandCompositor(QWaylandCompositorPrivate &dptr, QObject *parent)
578 : QWaylandObject(dptr, parent)
579{
580}
581
582/*!
583 * Destroys the QWaylandCompositor
584 */
585QWaylandCompositor::~QWaylandCompositor()
586{
587}
588
589/*!
590 * Initializes the QWaylandCompositor.
591 * If you override this function in your subclass, be sure to call the base class implementation.
592 */
593void QWaylandCompositor::create()
594{
595 Q_D(QWaylandCompositor);
596 d->preInit();
597 d->init();
598}
599
600/*!
601 * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::created
602 *
603 * This property is true if WaylandCompositor has been initialized,
604 * otherwise it's false.
605 */
606
607/*!
608 * \property QWaylandCompositor::created
609 *
610 * This property is true if QWaylandCompositor has been initialized,
611 * otherwise it's false.
612 */
613bool QWaylandCompositor::isCreated() const
614{
615 Q_D(const QWaylandCompositor);
616 return d->initialized;
617}
618
619/*!
620 * \qmlproperty string QtWayland.Compositor::WaylandCompositor::socketName
621 *
622 * This property holds the socket name used by WaylandCompositor to communicate with
623 * clients. It must be set before the component is completed.
624 *
625 * If the socketName is empty (the default), the contents of the start argument
626 * \c --wayland-socket-name are used instead. If the argument is not set, the
627 * compositor tries to find a socket name, which is \c{wayland-0} by default.
628 */
629
630/*!
631 * \property QWaylandCompositor::socketName
632 *
633 * This property holds the socket name used by QWaylandCompositor to communicate with
634 * clients. This must be set before the QWaylandCompositor is \l{create()}{created}.
635 *
636 * If the socketName is empty (the default), the contents of the start argument
637 * \c --wayland-socket-name are used instead. If the argument is not set, the
638 * compositor tries to find a socket name, which is \c{wayland-0} by default.
639 */
640void QWaylandCompositor::setSocketName(const QByteArray &name)
641{
642 Q_D(QWaylandCompositor);
643
644 if (d->socket_name == name)
645 return;
646
647 if (d->initialized) {
648 qWarning("%s: Changing socket name after initializing the compositor is not supported.\n", Q_FUNC_INFO);
649 return;
650 }
651
652 d->socket_name = name;
653 emit socketNameChanged(name);
654}
655
656QByteArray QWaylandCompositor::socketName() const
657{
658 Q_D(const QWaylandCompositor);
659 return d->socket_name;
660}
661
662/*!
663 * \qmlmethod void QtWayland.Compositor::WaylandCompositor::addSocketDescriptor(fd)
664 * \since 5.12
665 *
666 * Listen for client connections on a file descriptor, \a fd, referring to a
667 * server socket already bound and listening.
668 *
669 * Does not take ownership of the file descriptor; it must be closed
670 * explicitly if needed.
671 *
672 * \note This method is only available with libwayland 1.10.0 or
673 * newer. If built against an earlier libwayland runtime, this
674 * method is a noop.
675 */
676
677/*!
678 * Listen for client connections on a file descriptor, \a fd, referring to a
679 * server socket already bound and listening.
680 *
681 * Does not take ownership of the file descriptor; it must be closed
682 * explicitly if needed.
683 *
684 * \note This method is only available with libwayland 1.10.0 or
685 * newer. If built against an earlier libwayland runtime, this
686 * method is a noop.
687 *
688 * \since 5.12
689 */
690void QWaylandCompositor::addSocketDescriptor(int fd)
691{
692 Q_D(QWaylandCompositor);
693 d->externally_added_socket_fds.append(fd);
694 if (isCreated())
695 d->connectToExternalSockets();
696}
697
698/*!
699 * \internal
700 */
701struct wl_display *QWaylandCompositor::display() const
702{
703 Q_D(const QWaylandCompositor);
704 return d->display;
705}
706
707/*!
708 * \internal
709 */
710uint32_t QWaylandCompositor::nextSerial()
711{
712 Q_D(QWaylandCompositor);
713 return wl_display_next_serial(d->display);
714}
715
716/*!
717 * \internal
718 */
719QList<QWaylandClient *>QWaylandCompositor::clients() const
720{
721 Q_D(const QWaylandCompositor);
722 return d->clients;
723}
724
725/*!
726 * \qmlmethod void QtWayland.Compositor::WaylandCompositor::destroyClientForSurface(surface)
727 *
728 * From the compositor side, destroys the client to which the WaylandSurface \a surface belongs
729 * by disconnecting from it.
730 */
731
732/*!
733 * Destroys the client for the \a surface.
734 */
735void QWaylandCompositor::destroyClientForSurface(QWaylandSurface *surface)
736{
737 destroyClient(surface->client());
738}
739
740/*!
741 * \qmlmethod void QtWayland.Compositor::WaylandCompositor::destroyClient(client)
742 *
743 * From the compositor side, destroys the given WaylandClient \a client by disconnecting from it.
744 */
745
746/*!
747 * Destroys the \a client.
748 */
749void QWaylandCompositor::destroyClient(QWaylandClient *client)
750{
751 if (!client)
752 return;
753
754 QWaylandQtWindowManager *wmExtension = QWaylandQtWindowManager::findIn(this);
755 if (wmExtension)
756 wmExtension->sendQuitMessage(client);
757
758 wl_client_destroy(client->client());
759}
760
761/*!
762 * \internal
763 */
764QList<QWaylandSurface *> QWaylandCompositor::surfacesForClient(QWaylandClient* client) const
765{
766 Q_D(const QWaylandCompositor);
767 QList<QWaylandSurface *> surfs;
768 for (QWaylandSurface *surface : d->all_surfaces) {
769 if (surface->client() == client)
770 surfs.append(surface);
771 }
772 return surfs;
773}
774
775/*!
776 * \internal
777 */
778QList<QWaylandSurface *> QWaylandCompositor::surfaces() const
779{
780 Q_D(const QWaylandCompositor);
781 return d->all_surfaces;
782}
783
784/*!
785 * Returns the QWaylandOutput that is connected to the given \a window.
786 */
787QWaylandOutput *QWaylandCompositor::outputFor(QWindow *window) const
788{
789 Q_D(const QWaylandCompositor);
790 for (QWaylandOutput *output : d->outputs) {
791 if (output->window() == window)
792 return output;
793 }
794
795 return nullptr;
796}
797
798/*!
799 * \qmlproperty WaylandOutput QtWayland.Compositor::WaylandCompositor::defaultOutput
800 *
801 * This property contains the first in the list of outputs added to the
802 * WaylandCompositor, or null if no outputs have been added.
803 *
804 * Setting a new default output prepends it to the output list, making
805 * it the new default, but the previous default is not removed from
806 * the list.
807 */
808/*!
809 * \property QWaylandCompositor::defaultOutput
810 *
811 * This property contains the first in the list of outputs added to the
812 * QWaylandCompositor, or null if no outputs have been added.
813 *
814 * Setting a new default output prepends it to the output list, making
815 * it the new default, but the previous default is not removed from
816 * the list. If the new default output was already in the list of outputs,
817 * it is moved to the beginning of the list.
818 */
819QWaylandOutput *QWaylandCompositor::defaultOutput() const
820{
821 Q_D(const QWaylandCompositor);
822 return d->defaultOutput();
823}
824
825void QWaylandCompositor::setDefaultOutput(QWaylandOutput *output)
826{
827 Q_D(QWaylandCompositor);
828 if (Q_UNLIKELY(!output)) {
829 qWarning("Changing default output to null is not supported");
830 return;
831 }
832 if (d->outputs.size() && d->outputs.first() == output)
833 return;
834 bool alreadyAdded = d->outputs.removeOne(output);
835 d->outputs.prepend(output);
836 if (!alreadyAdded)
837 emit outputAdded(output);
838 emit defaultOutputChanged();
839}
840
841/*!
842 * \internal
843 */
844QList<QWaylandOutput *> QWaylandCompositor::outputs() const
845{
846 Q_D(const QWaylandCompositor);
847 return d->outputs;
848}
849
850/*!
851 * \internal
852 */
853uint QWaylandCompositor::currentTimeMsecs() const
854{
855 Q_D(const QWaylandCompositor);
856 return d->timer.elapsed();
857}
858
859/*!
860 * \internal
861 */
862void QWaylandCompositor::processWaylandEvents()
863{
864 Q_D(QWaylandCompositor);
865 int ret = wl_event_loop_dispatch(d->loop, 0);
866 if (ret)
867 fprintf(stderr, "wl_event_loop_dispatch error: %d\n", ret);
868 wl_display_flush_clients(d->display);
869}
870
871/*!
872 * \internal
873 */
874QWaylandSeat *QWaylandCompositor::createSeat()
875{
876 return new QWaylandSeat(this);
877}
878
879/*!
880 * \internal
881 */
882QWaylandPointer *QWaylandCompositor::createPointerDevice(QWaylandSeat *seat)
883{
884 return new QWaylandPointer(seat);
885}
886
887/*!
888 * \internal
889 */
890QWaylandKeyboard *QWaylandCompositor::createKeyboardDevice(QWaylandSeat *seat)
891{
892 return new QWaylandKeyboard(seat);
893}
894
895/*!
896 * \internal
897 */
898QWaylandTouch *QWaylandCompositor::createTouchDevice(QWaylandSeat *seat)
899{
900 return new QWaylandTouch(seat);
901}
902
903/*!
904 * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::retainedSelection
905 * \default false
906 *
907 * This property controls whether the compositor retains a copy of clipboard selection data.
908 * When \c true, the compositor eagerly reads and caches all clipboard data from the owning client.
909 * This incurs a performance cost.
910 */
911
912/*!
913 * \property QWaylandCompositor::retainedSelection
914 *
915 * This property controls whether the compositor retains a copy of clipboard selection data.
916 * When \c true, the compositor eagerly reads and caches all clipboard data from the owning client.
917 * This incurs a performance cost. The default is \c false.
918 *
919 * \sa QWaylandCompositor::retainedSelectionReceived(), QWaylandSurface::updateSelection()
920 */
921void QWaylandCompositor::setRetainedSelectionEnabled(bool enabled)
922{
923 Q_D(QWaylandCompositor);
924
925 if (d->retainSelection == enabled)
926 return;
927
928 d->retainSelection = enabled;
929 emit retainedSelectionChanged(enabled);
930}
931
932bool QWaylandCompositor::retainedSelectionEnabled() const
933{
934 Q_D(const QWaylandCompositor);
935 return d->retainSelection;
936}
937
938/*!
939 * \internal
940 */
941void QWaylandCompositor::retainedSelectionReceived(QMimeData *)
942{
943}
944
945/*!
946 * \internal
947 */
948void QWaylandCompositor::overrideSelection(const QMimeData *data)
949{
950 Q_D(QWaylandCompositor);
951#if QT_CONFIG(wayland_datadevice)
952 d->data_device_manager->overrideSelection(*data);
953#endif
954}
955
956/*!
957 * \qmlproperty WaylandSeat QtWayland.Compositor::WaylandCompositor::defaultSeat
958 *
959 * This property contains the default seat for this
960 * WaylandCompositor.
961 */
962
963/*!
964 * \property QWaylandCompositor::defaultSeat
965 *
966 * This property contains the default seat for this
967 * QWaylandCompositor.
968 */
969QWaylandSeat *QWaylandCompositor::defaultSeat() const
970{
971 Q_D(const QWaylandCompositor);
972 if (d->seats.size())
973 return d->seats.first();
974 return nullptr;
975}
976
977/*!
978 * Select the seat for a given input event \a inputEvent.
979 * Currently, Qt only supports a single seat.
980 */
981QWaylandSeat *QWaylandCompositor::seatFor(QInputEvent *inputEvent)
982{
983 Q_D(QWaylandCompositor);
984 return d->seatFor(inputEvent);
985}
986
987/*!
988 * \qmlproperty bool QtWayland.Compositor::WaylandCompositor::useHardwareIntegrationExtension
989 * \default true
990 *
991 * This property holds whether the hardware integration extension should be enabled for
992 * this WaylandCompositor.
993 *
994 * This property must be set before the compositor component is completed.
995 */
996
997/*!
998 * \property QWaylandCompositor::useHardwareIntegrationExtension
999 *
1000 * This property holds whether the hardware integration extension should be enabled for
1001 * this QWaylandCompositor.
1002 *
1003 * This property must be set before the compositor is \l{create()}{created}.
1004 */
1005bool QWaylandCompositor::useHardwareIntegrationExtension() const
1006{
1007#if QT_CONFIG(opengl)
1008 Q_D(const QWaylandCompositor);
1009 return d->use_hw_integration_extension;
1010#else
1011 return false;
1012#endif
1013}
1014
1015void QWaylandCompositor::setUseHardwareIntegrationExtension(bool use)
1016{
1017#if QT_CONFIG(opengl)
1018 Q_D(QWaylandCompositor);
1019 if (use == d->use_hw_integration_extension)
1020 return;
1021
1022 if (d->initialized)
1023 qWarning("Setting QWaylandCompositor::useHardwareIntegrationExtension after initialization has no effect");
1024
1025 d->use_hw_integration_extension = use;
1026 useHardwareIntegrationExtensionChanged();
1027#else
1028 if (use)
1029 qWarning() << "Hardware integration not supported without OpenGL support";
1030#endif
1031}
1032
1033/*!
1034 * Grab the surface content from the given \a buffer.
1035 * The default implementation requires a OpenGL context to be bound to the current thread
1036 * to work. If this is not possible, reimplement this function in your compositor subclass
1037 * to implement custom logic.
1038 * The default implementation only grabs shared memory and OpenGL buffers, reimplement this in your
1039 * compositor subclass to handle more buffer types.
1040 * \note You should not call this manually, but rather use QWaylandSurfaceGrabber (\a grabber).
1041 */
1042void QWaylandCompositor::grabSurface(QWaylandSurfaceGrabber *grabber, const QWaylandBufferRef &buffer)
1043{
1044 if (buffer.isSharedMemory()) {
1045 emit grabber->success(buffer.image());
1046 } else {
1047#if QT_CONFIG(opengl)
1048 if (QOpenGLContext::currentContext()) {
1049 QOpenGLFramebufferObject fbo(buffer.size());
1050 fbo.bind();
1051 QOpenGLTextureBlitter blitter;
1052 blitter.create();
1053
1054
1055 glViewport(0, 0, buffer.size().width(), buffer.size().height());
1056
1057 QOpenGLTextureBlitter::Origin surfaceOrigin =
1058 buffer.origin() == QWaylandSurface::OriginTopLeft
1059 ? QOpenGLTextureBlitter::OriginTopLeft
1060 : QOpenGLTextureBlitter::OriginBottomLeft;
1061
1062 auto texture = buffer.toOpenGLTexture();
1063 blitter.bind(texture->target());
1064 blitter.blit(texture->textureId(), QMatrix4x4(), surfaceOrigin);
1065 blitter.release();
1066
1067 emit grabber->success(fbo.toImage());
1068 } else
1069#endif
1070 emit grabber->failed(QWaylandSurfaceGrabber::UnknownBufferType);
1071 }
1072}
1073
1074/*!
1075 * \qmlproperty list<enum> QtWayland.Compositor::WaylandCompositor::additionalShmFormats
1076 *
1077 * This property holds the list of additional wl_shm formats advertised as supported by the
1078 * compositor.
1079 *
1080 * By default, only the required ShmFormat_ARGB8888 and ShmFormat_XRGB8888 are listed and this
1081 * list will be empty. Additional formats may require conversion internally and can thus affect
1082 * performance.
1083 *
1084 * This property must be set before the compositor component is completed. Subsequent changes
1085 * will have no effect.
1086 *
1087 * \since 6.0
1088 */
1089
1090/*!
1091 * \property QWaylandCompositor::additionalShmFormats
1092 *
1093 * This property holds the list of additional wl_shm formats advertised as supported by the
1094 * compositor.
1095 *
1096 * By default, only the required ShmFormat_ARGB8888 and ShmFormat_XRGB8888 are listed and this
1097 * list will be empty.
1098 *
1099 * This property must be set before the compositor is \l{create()}{created}. Subsequent changes
1100 * will have no effect.
1101 *
1102 * \since 6.0
1103 */
1104void QWaylandCompositor::setAdditionalShmFormats(const QVector<ShmFormat> &additionalShmFormats)
1105{
1106 Q_D(QWaylandCompositor);
1107 if (d->initialized)
1108 qCWarning(qLcWaylandCompositorHardwareIntegration) << "Setting QWaylandCompositor::additionalShmFormats after initialization has no effect";
1109
1110 d->shmFormats = additionalShmFormats;
1111 emit additionalShmFormatsChanged();
1112}
1113
1114QVector<QWaylandCompositor::ShmFormat> QWaylandCompositor::additionalShmFormats() const
1115{
1116 Q_D(const QWaylandCompositor);
1117 return d->shmFormats;
1118}
1119
1120void QWaylandCompositor::applicationStateChanged(Qt::ApplicationState state)
1121{
1122#if QT_CONFIG(xkbcommon)
1123 if (state == Qt::ApplicationInactive) {
1124 auto *seat = defaultSeat();
1125 if (seat != nullptr) {
1126 QWaylandKeyboardPrivate *keyb = QWaylandKeyboardPrivate::get(seat->keyboard());
1127 keyb->resetKeyboardState();
1128 }
1129 }
1130#else
1131 Q_UNUSED(state);
1132#endif
1133}
1134
1135QT_END_NAMESPACE
1136
1137#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()