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