1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qwaylanddisplay_p.h"
41 
42 #include "qwaylandintegration_p.h"
43 #include "qwaylandwindow_p.h"
44 #include "qwaylandsurface_p.h"
45 #include "qwaylandabstractdecoration_p.h"
46 #include "qwaylandscreen_p.h"
47 #include "qwaylandcursor_p.h"
48 #include "qwaylandinputdevice_p.h"
49 #if QT_CONFIG(clipboard)
50 #include "qwaylandclipboard_p.h"
51 #endif
52 #if QT_CONFIG(wayland_datadevice)
53 #include "qwaylanddatadevicemanager_p.h"
54 #include "qwaylanddatadevice_p.h"
55 #endif // QT_CONFIG(wayland_datadevice)
56 #if QT_CONFIG(wayland_client_primary_selection)
57 #include "qwaylandprimaryselectionv1_p.h"
58 #endif // QT_CONFIG(wayland_client_primary_selection)
59 #if QT_CONFIG(cursor)
60 #include <wayland-cursor.h>
61 #endif
62 #include "qwaylandhardwareintegration_p.h"
63 #include "qwaylandinputcontext_p.h"
64 
65 #include "qwaylandwindowmanagerintegration_p.h"
66 #include "qwaylandshellintegration_p.h"
67 #include "qwaylandclientbufferintegration_p.h"
68 
69 #include "qwaylandextendedsurface_p.h"
70 #include "qwaylandsubsurface_p.h"
71 #include "qwaylandtouch_p.h"
72 #include "qwaylandtabletv2_p.h"
73 #include "qwaylandqtkey_p.h"
74 
75 #include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
76 #include <QtWaylandClient/private/qwayland-wp-primary-selection-unstable-v1.h>
77 
78 #include <QtCore/private/qcore_unix_p.h>
79 
80 #include <QtCore/QAbstractEventDispatcher>
81 #include <QtGui/qpa/qwindowsysteminterface.h>
82 #include <QtGui/private/qguiapplication_p.h>
83 
84 #include <QtCore/QDebug>
85 
86 #include <errno.h>
87 
88 QT_BEGIN_NAMESPACE
89 
90 namespace QtWaylandClient {
91 
92 Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging
93 
createSurface(void * handle)94 struct wl_surface *QWaylandDisplay::createSurface(void *handle)
95 {
96     struct wl_surface *surface = mCompositor.create_surface();
97     wl_surface_set_user_data(surface, handle);
98     return surface;
99 }
100 
createRegion(const QRegion & qregion)101 struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
102 {
103     struct ::wl_region *region = mCompositor.create_region();
104 
105     for (const QRect &rect : qregion)
106         wl_region_add(region, rect.x(), rect.y(), rect.width(), rect.height());
107 
108     return region;
109 }
110 
createSubSurface(QWaylandWindow * window,QWaylandWindow * parent)111 ::wl_subsurface *QWaylandDisplay::createSubSurface(QWaylandWindow *window, QWaylandWindow *parent)
112 {
113     if (!mSubCompositor) {
114         qCWarning(lcQpaWayland) << "Can't create subsurface, not supported by the compositor.";
115         return nullptr;
116     }
117 
118     // Make sure we don't pass NULL surfaces to libwayland (crashes)
119     Q_ASSERT(parent->wlSurface());
120     Q_ASSERT(window->wlSurface());
121 
122     return mSubCompositor->get_subsurface(window->wlSurface(), parent->wlSurface());
123 }
124 
shellIntegration() const125 QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const
126 {
127     return mWaylandIntegration->shellIntegration();
128 }
129 
clientBufferIntegration() const130 QWaylandClientBufferIntegration * QWaylandDisplay::clientBufferIntegration() const
131 {
132     return mWaylandIntegration->clientBufferIntegration();
133 }
134 
windowManagerIntegration() const135 QWaylandWindowManagerIntegration *QWaylandDisplay::windowManagerIntegration() const
136 {
137     return mWindowManagerIntegration.data();
138 }
139 
QWaylandDisplay(QWaylandIntegration * waylandIntegration)140 QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration)
141     : mWaylandIntegration(waylandIntegration)
142 {
143     qRegisterMetaType<uint32_t>("uint32_t");
144 
145     mDisplay = wl_display_connect(nullptr);
146     if (!mDisplay) {
147         qErrnoWarning(errno, "Failed to create wl_display");
148         return;
149     }
150 
151     struct ::wl_registry *registry = wl_display_get_registry(mDisplay);
152     init(registry);
153 
154     mWindowManagerIntegration.reset(new QWaylandWindowManagerIntegration(this));
155 
156 #if QT_CONFIG(xkbcommon)
157     mXkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
158     if (!mXkbContext)
159         qCWarning(lcQpaWayland, "failed to create xkb context");
160 #endif
161 
162     forceRoundTrip();
163 
164     if (!mWaitingScreens.isEmpty()) {
165         // Give wl_output.done and zxdg_output_v1.done events a chance to arrive
166         forceRoundTrip();
167     }
168 }
169 
~QWaylandDisplay(void)170 QWaylandDisplay::~QWaylandDisplay(void)
171 {
172     if (mSyncCallback)
173         wl_callback_destroy(mSyncCallback);
174 
175     qDeleteAll(qExchange(mInputDevices, {}));
176 
177     for (QWaylandScreen *screen : qExchange(mScreens, {})) {
178         QWindowSystemInterface::handleScreenRemoved(screen);
179     }
180     qDeleteAll(mWaitingScreens);
181 
182 #if QT_CONFIG(wayland_datadevice)
183     delete mDndSelectionHandler.take();
184 #endif
185 #if QT_CONFIG(cursor)
186     qDeleteAll(mCursorThemes);
187 #endif
188     if (mDisplay)
189         wl_display_disconnect(mDisplay);
190 }
191 
ensureScreen()192 void QWaylandDisplay::ensureScreen()
193 {
194     if (!mScreens.empty() || mPlaceholderScreen)
195         return; // There are real screens or we already have a fake one
196 
197     qCInfo(lcQpaWayland) << "Creating a fake screen in order for Qt not to crash";
198 
199     mPlaceholderScreen = new QPlatformPlaceholderScreen();
200     QWindowSystemInterface::handleScreenAdded(mPlaceholderScreen);
201     Q_ASSERT(!QGuiApplication::screens().empty());
202 }
203 
checkError() const204 void QWaylandDisplay::checkError() const
205 {
206     int ecode = wl_display_get_error(mDisplay);
207     if ((ecode == EPIPE || ecode == ECONNRESET)) {
208         // special case this to provide a nicer error
209         qWarning("The Wayland connection broke. Did the Wayland compositor die?");
210     } else {
211         qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode));
212     }
213     _exit(1);
214 }
215 
flushRequests()216 void QWaylandDisplay::flushRequests()
217 {
218     if (wl_display_prepare_read(mDisplay) == 0) {
219         wl_display_read_events(mDisplay);
220     }
221 
222     if (wl_display_dispatch_pending(mDisplay) < 0)
223         checkError();
224 
225     {
226         QReadLocker locker(&m_frameQueueLock);
227         for (const FrameQueue &q : mExternalQueues) {
228             QMutexLocker locker(q.mutex);
229             while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0)
230                 wl_display_dispatch_queue_pending(mDisplay, q.queue);
231             wl_display_read_events(mDisplay);
232             wl_display_dispatch_queue_pending(mDisplay, q.queue);
233         }
234     }
235 
236     wl_display_flush(mDisplay);
237 }
238 
blockingReadEvents()239 void QWaylandDisplay::blockingReadEvents()
240 {
241     if (wl_display_dispatch(mDisplay) < 0)
242         checkError();
243 }
244 
destroyFrameQueue(const QWaylandDisplay::FrameQueue & q)245 void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q)
246 {
247     QWriteLocker locker(&m_frameQueueLock);
248     auto it = std::find_if(mExternalQueues.begin(),
249                            mExternalQueues.end(),
250                            [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; });
251     Q_ASSERT(it != mExternalQueues.end());
252     mExternalQueues.erase(it);
253     if (q.queue != nullptr)
254         wl_event_queue_destroy(q.queue);
255     delete q.mutex;
256 }
257 
createFrameQueue()258 QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue()
259 {
260     QWriteLocker locker(&m_frameQueueLock);
261     FrameQueue q{createEventQueue()};
262     mExternalQueues.append(q);
263     return q;
264 }
265 
createEventQueue()266 wl_event_queue *QWaylandDisplay::createEventQueue()
267 {
268     return wl_display_create_queue(mDisplay);
269 }
270 
dispatchQueueWhile(wl_event_queue * queue,std::function<bool ()> condition,int timeout)271 void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
272 {
273     if (!condition())
274         return;
275 
276     QElapsedTimer timer;
277     timer.start();
278     struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
279     while (timeout == -1 || timer.elapsed() < timeout) {
280         while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
281             wl_display_dispatch_queue_pending(mDisplay, queue);
282 
283         wl_display_flush(mDisplay);
284 
285         const int remaining = qMax(timeout - timer.elapsed(), 0ll);
286         const int pollTimeout = timeout == -1 ? -1 : remaining;
287         if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
288             wl_display_read_events(mDisplay);
289         else
290             wl_display_cancel_read(mDisplay);
291 
292         if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0)
293             checkError();
294 
295         if (!condition())
296             break;
297     }
298 }
299 
screenForOutput(struct wl_output * output) const300 QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
301 {
302     for (auto screen : qAsConst(mScreens)) {
303         if (screen->output() == output)
304             return screen;
305     }
306     return nullptr;
307 }
308 
handleScreenInitialized(QWaylandScreen * screen)309 void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
310 {
311     if (!mWaitingScreens.removeOne(screen))
312         return;
313     mScreens.append(screen);
314     QWindowSystemInterface::handleScreenAdded(screen);
315     if (mPlaceholderScreen) {
316         QWindowSystemInterface::handleScreenRemoved(mPlaceholderScreen);
317         // handleScreenRemoved deletes the platform screen
318         mPlaceholderScreen = nullptr;
319     }
320 }
321 
waitForScreens()322 void QWaylandDisplay::waitForScreens()
323 {
324     flushRequests();
325 
326     while (true) {
327         bool screensReady = !mScreens.isEmpty();
328 
329         for (int ii = 0; screensReady && ii < mScreens.count(); ++ii) {
330             if (mScreens.at(ii)->geometry() == QRect(0, 0, 0, 0))
331                 screensReady = false;
332         }
333 
334         if (!screensReady)
335             blockingReadEvents();
336         else
337             return;
338     }
339 }
340 
registry_global(uint32_t id,const QString & interface,uint32_t version)341 void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uint32_t version)
342 {
343     struct ::wl_registry *registry = object();
344 
345     if (interface == QStringLiteral("wl_output")) {
346         mWaitingScreens << new QWaylandScreen(this, version, id);
347     } else if (interface == QStringLiteral("wl_compositor")) {
348         mCompositorVersion = qMin((int)version, 3);
349         mCompositor.init(registry, id, mCompositorVersion);
350     } else if (interface == QStringLiteral("wl_shm")) {
351         mShm.reset(new QWaylandShm(this, version, id));
352     } else if (interface == QStringLiteral("wl_seat")) {
353         QWaylandInputDevice *inputDevice = mWaylandIntegration->createInputDevice(this, version, id);
354         mInputDevices.append(inputDevice);
355 #if QT_CONFIG(wayland_datadevice)
356     } else if (interface == QStringLiteral("wl_data_device_manager")) {
357         mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id));
358 #endif
359     } else if (interface == QStringLiteral("qt_surface_extension")) {
360         mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1));
361     } else if (interface == QStringLiteral("wl_subcompositor")) {
362         mSubCompositor.reset(new QtWayland::wl_subcompositor(registry, id, 1));
363     } else if (interface == QStringLiteral("qt_touch_extension")) {
364         mTouchExtension.reset(new QWaylandTouchExtension(this, id));
365     } else if (interface == QStringLiteral("zqt_key_v1")) {
366         mQtKeyExtension.reset(new QWaylandQtKeyExtension(this, id));
367     } else if (interface == QStringLiteral("zwp_tablet_manager_v2")) {
368         mTabletManager.reset(new QWaylandTabletManagerV2(this, id, qMin(1, int(version))));
369 #if QT_CONFIG(wayland_client_primary_selection)
370     } else if (interface == QStringLiteral("zwp_primary_selection_device_manager_v1")) {
371         mPrimarySelectionManager.reset(new QWaylandPrimarySelectionDeviceManagerV1(this, id, 1));
372 #endif
373     } else if (interface == QStringLiteral("zwp_text_input_manager_v2") && !mClientSideInputContextRequested) {
374         mTextInputManager.reset(new QtWayland::zwp_text_input_manager_v2(registry, id, 1));
375         for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
376             inputDevice->setTextInput(new QWaylandTextInput(this, mTextInputManager->get_text_input(inputDevice->wl_seat())));
377         mWaylandIntegration->reconfigureInputContext();
378     } else if (interface == QStringLiteral("qt_hardware_integration")) {
379         bool disableHardwareIntegration = qEnvironmentVariableIntValue("QT_WAYLAND_DISABLE_HW_INTEGRATION");
380         if (!disableHardwareIntegration) {
381             mHardwareIntegration.reset(new QWaylandHardwareIntegration(registry, id));
382             // make a roundtrip here since we need to receive the events sent by
383             // qt_hardware_integration before creating windows
384             forceRoundTrip();
385         }
386     } else if (interface == QLatin1String("zxdg_output_manager_v1")) {
387         mXdgOutputManager.reset(new QWaylandXdgOutputManagerV1(this, id, version));
388         for (auto *screen : qAsConst(mWaitingScreens))
389             screen->initXdgOutput(xdgOutputManager());
390         forceRoundTrip();
391     }
392 
393     mGlobals.append(RegistryGlobal(id, interface, version, registry));
394 
395     const auto copy = mRegistryListeners; // be prepared for listeners unregistering on notification
396     for (Listener l : copy)
397         (*l.listener)(l.data, registry, id, interface, version);
398 }
399 
registry_global_remove(uint32_t id)400 void QWaylandDisplay::registry_global_remove(uint32_t id)
401 {
402     for (int i = 0, ie = mGlobals.count(); i != ie; ++i) {
403         RegistryGlobal &global = mGlobals[i];
404         if (global.id == id) {
405             if (global.interface == QStringLiteral("wl_output")) {
406                 for (auto *screen : mWaitingScreens) {
407                     if (screen->outputId() == id) {
408                         mWaitingScreens.removeOne(screen);
409                         delete screen;
410                         break;
411                     }
412                 }
413 
414                 for (QWaylandScreen *screen : qAsConst(mScreens)) {
415                     if (screen->outputId() == id) {
416                         mScreens.removeOne(screen);
417                         // If this is the last screen, we have to add a fake screen, or Qt will break.
418                         ensureScreen();
419                         QWindowSystemInterface::handleScreenRemoved(screen);
420                         break;
421                     }
422                 }
423             }
424             if (global.interface == QStringLiteral("zwp_text_input_manager_v2")) {
425                 mTextInputManager.reset();
426                 for (QWaylandInputDevice *inputDevice : qAsConst(mInputDevices))
427                     inputDevice->setTextInput(nullptr);
428                 mWaylandIntegration->reconfigureInputContext();
429             }
430             mGlobals.removeAt(i);
431             break;
432         }
433     }
434 }
435 
hasRegistryGlobal(QStringView interfaceName) const436 bool QWaylandDisplay::hasRegistryGlobal(QStringView interfaceName) const
437 {
438     for (const RegistryGlobal &global : mGlobals)
439         if (global.interface == interfaceName)
440             return true;
441 
442     return false;
443 }
444 
addRegistryListener(RegistryListener listener,void * data)445 void QWaylandDisplay::addRegistryListener(RegistryListener listener, void *data)
446 {
447     Listener l = { listener, data };
448     mRegistryListeners.append(l);
449     for (int i = 0, ie = mGlobals.count(); i != ie; ++i)
450         (*l.listener)(l.data, mGlobals[i].registry, mGlobals[i].id, mGlobals[i].interface, mGlobals[i].version);
451 }
452 
removeListener(RegistryListener listener,void * data)453 void QWaylandDisplay::removeListener(RegistryListener listener, void *data)
454 {
455     auto iter = std::remove_if(mRegistryListeners.begin(), mRegistryListeners.end(), [=](Listener l){
456         return (l.listener == listener && l.data == data);
457     });
458     mRegistryListeners.erase(iter, mRegistryListeners.end());
459 }
460 
currentTimeMillisec()461 uint32_t QWaylandDisplay::currentTimeMillisec()
462 {
463     //### we throw away the time information
464     struct timeval tv;
465     int ret = gettimeofday(&tv, nullptr);
466     if (ret == 0)
467         return tv.tv_sec*1000 + tv.tv_usec/1000;
468     return 0;
469 }
470 
471 static void
sync_callback(void * data,struct wl_callback * callback,uint32_t serial)472 sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
473 {
474     Q_UNUSED(serial)
475     bool *done = static_cast<bool *>(data);
476 
477     *done = true;
478 
479     // If the wl_callback done event is received after the condition check in the while loop in
480     // forceRoundTrip(), but before the call to processEvents, the call to processEvents may block
481     // forever if no more events are posted (eventhough the callback is handled in response to the
482     // aboutToBlock signal). Hence, we wake up the event dispatcher so forceRoundTrip may return.
483     // (QTBUG-64696)
484     if (auto *dispatcher = QThread::currentThread()->eventDispatcher())
485         dispatcher->wakeUp();
486 
487     wl_callback_destroy(callback);
488 }
489 
490 static const struct wl_callback_listener sync_listener = {
491     sync_callback
492 };
493 
forceRoundTrip()494 void QWaylandDisplay::forceRoundTrip()
495 {
496     // wl_display_roundtrip() works on the main queue only,
497     // but we use a separate one, so basically reimplement it here
498     int ret = 0;
499     bool done = false;
500     wl_callback *callback = wl_display_sync(mDisplay);
501     wl_callback_add_listener(callback, &sync_listener, &done);
502     flushRequests();
503     if (QThread::currentThread()->eventDispatcher()) {
504         while (!done && ret >= 0) {
505             QThread::currentThread()->eventDispatcher()->processEvents(QEventLoop::WaitForMoreEvents);
506             ret = wl_display_dispatch_pending(mDisplay);
507         }
508     } else {
509         while (!done && ret >= 0)
510             ret = wl_display_dispatch(mDisplay);
511     }
512 
513     if (ret == -1 && !done)
514         wl_callback_destroy(callback);
515 }
516 
supportsWindowDecoration() const517 bool QWaylandDisplay::supportsWindowDecoration() const
518 {
519     static bool disabled = qgetenv("QT_WAYLAND_DISABLE_WINDOWDECORATION").toInt();
520     // Stop early when disabled via the environment. Do not try to load the integration in
521     // order to play nice with SHM-only, buffer integration-less systems.
522     if (disabled)
523         return false;
524 
525     static bool integrationSupport = clientBufferIntegration() && clientBufferIntegration()->supportsWindowDecoration();
526     return integrationSupport;
527 }
528 
lastInputWindow() const529 QWaylandWindow *QWaylandDisplay::lastInputWindow() const
530 {
531     return mLastInputWindow.data();
532 }
533 
setLastInputDevice(QWaylandInputDevice * device,uint32_t serial,QWaylandWindow * win)534 void QWaylandDisplay::setLastInputDevice(QWaylandInputDevice *device, uint32_t serial, QWaylandWindow *win)
535 {
536     mLastInputDevice = device;
537     mLastInputSerial = serial;
538     mLastInputWindow = win;
539 }
540 
isWindowActivated(const QWaylandWindow * window)541 bool QWaylandDisplay::isWindowActivated(const QWaylandWindow *window)
542 {
543     return mActiveWindows.contains(const_cast<QWaylandWindow *>(window));
544 }
545 
handleWindowActivated(QWaylandWindow * window)546 void QWaylandDisplay::handleWindowActivated(QWaylandWindow *window)
547 {
548     if (mActiveWindows.contains(window))
549         return;
550 
551     mActiveWindows.append(window);
552     requestWaylandSync();
553 
554     if (auto *decoration = window->decoration())
555         decoration->update();
556 }
557 
handleWindowDeactivated(QWaylandWindow * window)558 void QWaylandDisplay::handleWindowDeactivated(QWaylandWindow *window)
559 {
560     Q_ASSERT(!mActiveWindows.empty());
561 
562     if (mActiveWindows.last() == window)
563         requestWaylandSync();
564 
565     mActiveWindows.removeOne(window);
566 
567     if (auto *decoration = window->decoration())
568         decoration->update();
569 }
570 
handleKeyboardFocusChanged(QWaylandInputDevice * inputDevice)571 void QWaylandDisplay::handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice)
572 {
573     QWaylandWindow *keyboardFocus = inputDevice->keyboardFocus();
574 
575     if (mLastKeyboardFocus == keyboardFocus)
576         return;
577 
578     if (keyboardFocus)
579         handleWindowActivated(keyboardFocus);
580     if (mLastKeyboardFocus)
581         handleWindowDeactivated(mLastKeyboardFocus);
582 
583     mLastKeyboardFocus = keyboardFocus;
584 }
585 
handleWindowDestroyed(QWaylandWindow * window)586 void QWaylandDisplay::handleWindowDestroyed(QWaylandWindow *window)
587 {
588     if (mActiveWindows.contains(window))
589         handleWindowDeactivated(window);
590 }
591 
handleWaylandSync()592 void QWaylandDisplay::handleWaylandSync()
593 {
594     // This callback is used to set the window activation because we may get an activate/deactivate
595     // pair, and the latter one would be lost in the QWindowSystemInterface queue, if we issue the
596     // handleWindowActivated() calls immediately.
597     QWindow *activeWindow = mActiveWindows.empty() ? nullptr : mActiveWindows.last()->window();
598     if (activeWindow != QGuiApplication::focusWindow())
599         QWindowSystemInterface::handleWindowActivated(activeWindow);
600 
601     if (!activeWindow) {
602         if (lastInputDevice()) {
603 #if QT_CONFIG(clipboard)
604             if (auto *dataDevice = lastInputDevice()->dataDevice())
605                 dataDevice->invalidateSelectionOffer();
606 #endif
607 #if QT_CONFIG(wayland_client_primary_selection)
608             if (auto *device = lastInputDevice()->primarySelectionDevice())
609                 device->invalidateSelectionOffer();
610 #endif
611         }
612     }
613 }
614 
615 const wl_callback_listener QWaylandDisplay::syncCallbackListener = {
__anon66e06cf20302()616     [](void *data, struct wl_callback *callback, uint32_t time){
617         Q_UNUSED(time);
618         wl_callback_destroy(callback);
619         QWaylandDisplay *display = static_cast<QWaylandDisplay *>(data);
620         display->mSyncCallback = nullptr;
621         display->handleWaylandSync();
622     }
623 };
624 
requestWaylandSync()625 void QWaylandDisplay::requestWaylandSync()
626 {
627     if (mSyncCallback)
628         return;
629 
630     mSyncCallback = wl_display_sync(mDisplay);
631     wl_callback_add_listener(mSyncCallback, &syncCallbackListener, this);
632 }
633 
defaultInputDevice() const634 QWaylandInputDevice *QWaylandDisplay::defaultInputDevice() const
635 {
636     return mInputDevices.isEmpty() ? 0 : mInputDevices.first();
637 }
638 
isKeyboardAvailable() const639 bool QWaylandDisplay::isKeyboardAvailable() const
640 {
641     return std::any_of(
642             mInputDevices.constBegin(), mInputDevices.constEnd(),
643             [this](const QWaylandInputDevice *device) { return device->keyboard() != nullptr; });
644 }
645 
646 #if QT_CONFIG(cursor)
647 
waylandCursor()648 QWaylandCursor *QWaylandDisplay::waylandCursor()
649 {
650     if (!mCursor)
651         mCursor.reset(new QWaylandCursor(this));
652     return mCursor.data();
653 }
654 
loadCursorTheme(const QString & name,int pixelSize)655 QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int pixelSize)
656 {
657     if (auto *theme = mCursorThemes.value({name, pixelSize}, nullptr))
658         return theme;
659 
660     if (auto *theme = QWaylandCursorTheme::create(shm(), pixelSize, name)) {
661         mCursorThemes[{name, pixelSize}] = theme;
662         return theme;
663     }
664 
665     return nullptr;
666 }
667 
668 #endif // QT_CONFIG(cursor)
669 
670 } // namespace QtWaylandClient
671 
672 QT_END_NAMESPACE
673