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

source code of qtwayland/src/compositor/compositor_api/qwaylandcompositor.cpp