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