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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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