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