Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylandwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
26
27#include <QtCore/QFileInfo>
28#include <QtCore/QPointer>
29#include <QtCore/QRegularExpression>
30#include <QtGui/QWindow>
31
32#include <QGuiApplication>
33#include <qpa/qwindowsysteminterface.h>
34#include <QtGui/private/qguiapplication_p.h>
35#include <QtGui/private/qwindow_p.h>
36
37#include <QtCore/QDebug>
38#include <QtCore/QThread>
39
40#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
41
43
44using namespace Qt::StringLiterals;
45
46namespace QtWaylandClient {
47
48Q_LOGGING_CATEGORY(lcWaylandBackingstore, "qt.qpa.wayland.backingstore")
49
52
53/*!
54 \class QtWaylandClient::QWaylandWindow
55 \internal
56*/
83
85{
86 reset();
87
88 const QWindow *parent = window();
89 const auto tlw = QGuiApplication::topLevelWindows();
90 for (QWindow *w : tlw) {
91 if (w->transientParent() == parent)
93 }
94
95 if (mMouseGrab == this) {
96 mMouseGrab = nullptr;
97 }
98}
99
107
109{
111
114
115 auto *parent = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
116 if (!parent->mSurface)
118 if (parent->wlSurface()) {
121 }
122 } else if (shouldCreateShellSurface()) {
126 if (mTransientParent) {
127 if (window()->type() == Qt::Popup) {
129 qCWarning(lcQpaWayland) << "Creating a popup with a parent," << mTransientParent->window()
130 << "which does not match the current topmost grabbing popup,"
131 << mTopPopup->window() << "With some shell surface protocols, this"
132 << "is not allowed. The wayland QPA plugin is currently handling"
133 << "it by setting the parent to the topmost grabbing popup."
134 << "Note, however, that this may cause positioning errors and"
135 << "popups closing unxpectedly. Please fix the transient parent of the popup.";
137 }
138 mTopPopup = this;
139 }
140 }
141
143 if (mShellSurface) {
144 if (mTransientParent) {
145 if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup || window()->type() == Qt::Tool)
147 }
148
149 // Set initial surface title
152
153 // The appId is the desktop entry identifier that should follow the
154 // reverse DNS convention (see
155 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html). According
156 // to xdg-shell the appId is only the name, without the .desktop suffix.
157 //
158 // If the application specifies the desktop file name use that,
159 // otherwise fall back to the executable name and prepend the
160 // reversed organization domain when available.
163 } else {
168
169 if (domainName.isEmpty()) {
171 } else {
173 for (int i = 0; i < domainName.size(); ++i)
177 }
178 }
179 // the user may have already set some window properties, so make sure to send them out
180 for (auto it = m_properties.cbegin(); it != m_properties.cend(); ++it)
182
184 } else {
185 qWarning("Could not create a shell surface object.");
186 }
187 }
188
191
192 // Enable high-dpi rendering. Scale() returns the screen scale factor and will
193 // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
194 // to inform the compositor that high-resolution buffers will be provided.
195 if (mViewport)
197 else if (mSurface->version() >= 3)
199
202 if (geometry.width() <= 0)
204 if (geometry.height() <= 0)
206
208 setMask(window()->mask());
209 if (mShellSurface) {
212 }
214
216 mSurface->commit();
217
220 }
221}
222
224{
226}
227
260
277
284
286{
288 if (mShellSurface) {
289 qCWarning(lcQpaWayland) << "Cannot set shell integration while there's already a shell surface created";
290 return;
291 }
293}
294
296{
297 if (!shellIntegration())
298 return false;
299
301 return false;
302
303 if (window()->inherits("QShapedPixmapWindow"))
304 return false;
305
306 if (qEnvironmentVariableIsSet("QT_WAYLAND_USE_BYPASSWINDOWMANAGERHINT"))
307 return !(window()->flags() & Qt::BypassWindowManagerHint);
308
309 return true;
310}
311
313{
314 return QPlatformWindow::parent() != nullptr;
315}
316
322
324{
326 mInFrameRender = false;
327}
328
330{
332
335
336 if (mSurface) {
337 {
344
345 // Destroy surface last.
346 // Some compositors (e.g. ChromeOS Sommelier) crash if they receive
347 // destroy requests for these objects after the associated surface
348 // has already been destroyed.
349 mSurface.reset();
350 }
352 }
353
354 mScale = std::nullopt;
356 mMask = QRegion();
357
361
363}
364
366{
367 // Old Reset
369
370 if (mTopPopup == this)
374 mTransientParent = nullptr;
375 delete std::exchange(mShellSurface, nullptr);
376 delete std::exchange(mSubSurfaceWindow, nullptr);
378
380 mInFrameRender = false;
382 mExposed = false;
383}
384
386{
387 {
389 if (mFrameCallback) {
391 mFrameCallback = nullptr;
392 }
395 }
399 }
401}
402
404{
406 return s->waylandWindow();
407 return nullptr;
408}
410{
411 return reinterpret_cast<WId>(wlSurface());
412}
413
415{
416 if (lastParent == parent)
417 return;
418
419 if (mSubSurfaceWindow && parent) { // new parent, but we were a subsurface already
420 delete mSubSurfaceWindow;
421 QWaylandWindow *p = const_cast<QWaylandWindow *>(static_cast<const QWaylandWindow *>(parent));
423 } else if ((!lastParent && parent) || (lastParent && !parent)) {
424 // we're changing role, need to make a new wl_surface
425 reset();
427 if (window()->isVisible()) {
428 initWindow();
429 }
430 }
432}
433
435{
436 return mWindowTitle;
437}
438
440{
441 const QString separator = QString::fromUtf8(" \xe2\x80\x94 "); // unicode character U+2014, EM DASH
443
444 const int libwaylandMaxBufferSize = 4096;
445 // Some parts of the buffer is used for metadata, so subtract 100 to be on the safe side.
446 // Also, QString is in utf-16, which means that in the worst case each character will be
447 // three bytes when converted to utf-8 (which is what libwayland uses), so divide by three.
448 const int maxLength = libwaylandMaxBufferSize / 3 - 100;
449
451 if (truncated.size() < formatted.size()) {
452 qCWarning(lcQpaWayland) << "Window titles longer than" << maxLength << "characters are not supported."
453 << "Truncating window title (from" << formatted.size() << "chars)";
454 }
455
457
458 if (mShellSurface)
460
461 if (auto *dec = decoration(); dec && window()->isVisible())
462 dec->update();
463}
464
466{
468
469 if (auto *dec = decoration(); dec && window()->isVisible())
470 dec->update();
471 if (mShellSurface)
473}
474
476{
477 return QRect(QPoint(), QSize(500,500));
478}
479
481{
483 if (mViewport)
485
486 if (mSubSurfaceWindow) {
488
490 if (parentWindow)
492 }
493}
494
496{
497 auto rect = r;
499 && window()->type() != Qt::ToolTip && window()->type() != Qt::Tool) {
501 }
503
508 else
510 }
511
512 if (mShellSurface)
514
515 if (isOpaque() && mMask.isEmpty())
517
518
519 if (window()->isVisible() && rect.isValid()) {
520 ensureSize();
521 if (auto *dec = decoration())
522 dec->update();
523
525 }
526
527 // Wayland has no concept of areas being exposed or not, only the entire window, when our geometry changes, we need to flag the new area as exposed
528 // On other platforms (X11) the expose event would be received deferred from the X server
529 // we want our behaviour to match, and only run after control has returned to the event loop
531}
532
534{
535 if (!isExposed())
536 return;
539 return;
540
542}
543
545{
546 if (!mSurface)
547 return;
548
550
554
556 return;
557
560
562 mSurface->set_input_region(nullptr);
563 } else {
567 }
568}
569
571{
572 const QSize size = geometry().size();
573 if (!size.isEmpty())
575}
576
591
602
615
617{
618 static bool sQtTestMode = qEnvironmentVariableIsSet("QT_QTESTLIB_RUNNING");
620
621 if (decoration())
623
624 if (sQtTestMode) {
626 }
628
629 /**
630 * If an expose is not handled by application code, explicitly attach a buffer
631 * This primarily is a workaround for Qt unit tests using QWindow directly and
632 * wanting focus.
633 */
637 commit(&buffer, QRegion());
638 }
639}
640
642{
644 if (mSurface) {
645 if (auto *screen = mSurface->oldestEnteredScreen())
646 return screen;
647 }
648 return QPlatformWindow::screen();
649}
650
652{
653 // Workaround for issue where setVisible may be called with the same value twice
654 if (lastVisible == visible)
655 return;
657
658 if (visible) {
660 initWindow();
662 if (mShellSurface)
664 } else {
665 // make sure isExposed is false during the next event dispatch
666 mExposed = false;
669 mSurface->attach(nullptr, 0, 0);
670 mSurface->commit();
671 }
672}
673
674
676{
677 if (mShellSurface)
679}
680
681
683{
684 if (mShellSurface)
686}
687
689{
691 if (!mSurface)
692 return;
693
694 if (mMask == mask)
695 return;
696
697 mMask = mask;
698
700
701 if (isOpaque()) {
702 if (mMask.isEmpty())
704 else
706 }
707}
708
714
716{
717 if (mShellSurface)
718 return mShellSurface->isAlertState();
719
720 return false;
721}
722
730
732{
734 return;
735
737 "QWaylandWindow::applyConfigure", "not called from main thread");
738
739 // If we're mid paint, use an exposeEvent to flush the current frame.
740 // When this completes we know that no other frames will be rendering.
741 // This could be improved in future as we 're blocking for not just the frame to finish but one additional extra frame.
742 if (mInFrameRender)
744 if (mShellSurface)
746
748 if (mExposed)
750 else
751 // we still need to commit the configured ack for a hidden surface
752 commit();
753}
754
756{
758 if (mSurface == nullptr)
759 return;
760
761 if (buffer) {
763 handleUpdate();
764 buffer->setBusy(true);
766 mSurface->offset(x, y);
767 mSurface->attach(buffer->buffer(), 0, 0);
768 } else {
770 }
771 } else {
772 mSurface->attach(nullptr, 0, 0);
773 }
774}
775
781
783{
785 if (mSurface == nullptr)
786 return;
787
788 const qreal s = scale();
789 if (mSurface->version() >= 4) {
790 const QRect bufferRect =
791 QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
792 .toAlignedRect();
795 } else {
797 }
798}
799
801{
802 if (isExposed()) {
804 } else if (!buffer->committed()) {
805 buffer->setBusy(false);
806 }
807}
808
813
815{
817
819 if (buffer->committed()) {
820 mSurface->commit();
821 qCDebug(lcWaylandBackingstore) << "Buffer already committed, not attaching.";
822 return;
823 }
824
825 if (!mSurface)
826 return;
827
829 if (mSurface->version() >= 4) {
830 const qreal s = scale();
831 for (const QRect &rect : damage) {
832 const QRect bufferRect =
833 QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
834 .toAlignedRect();
837 }
838 } else {
839 for (const QRect &rect: damage)
841 }
844 mSurface->commit();
845}
846
848{
850 if (mSurface != nullptr)
851 mSurface->commit();
852}
853
855 [](void *data, wl_callback *callback, uint32_t time) {
856 Q_UNUSED(time);
857 auto *window = static_cast<QWaylandWindow*>(data);
859 }
860};
861
863{
865 if (mFrameCallback != callback) {
866 // This means the callback is already unset by QWaylandWindow::reset.
867 // The wl_callback object will be destroyed there too.
868 return;
869 }
871 mFrameCallback = nullptr;
873
874 // The rest can wait until we can run it on the correct thread
876 // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
877 // in the single-threaded case.
879 }
881}
882
884{
886 bool wasExposed = isExposed();
888 // Did setting mFrameCallbackTimedOut make the window exposed?
892
893}
894
896{
898
901
902 if (mFrameCallback) {
903 qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
906 }
907
908 return !mFrameCallback;
909}
910
912{
913 if (auto *dec = decoration())
914 return dec->margins();
915 else if (mShellSurface)
917 else
919}
920
922{
923 if (auto *dec = decoration())
924 return dec->margins();
925 return QMargins{};
926}
927
934
947
948/*!
949 * Window geometry as defined by the xdg-shell spec (in wl_surface coordinates)
950 * topLeft is where the shadow stops and the decorations border start.
951 */
958
963
969
971{
973 return mSurface ? mSurface->object() : nullptr;
974}
975
980
982{
984 return mSubSurfaceWindow->object();
985 if (mShellSurface)
986 return mShellSurface->surfaceRole();
987 return {};
988}
989
994
996{
1000 return nullptr;
1001 return static_cast<QWaylandScreen *>(platformScreen);
1002}
1003
1009
1011{
1013 if (mSurface == nullptr || mSurface->version() < 2)
1014 return;
1015
1018
1019 if (mSurface->version() >= 6) {
1021 if (auto screen = waylandScreen())
1023 } else {
1024 if (auto screen = window()->screen())
1026 }
1027
1029
1031 case Qt::PrimaryOrientation:
1033 break;
1036 break;
1037 case Qt::PortraitOrientation:
1039 break;
1042 break;
1045 break;
1046 default:
1047 Q_UNREACHABLE();
1048 }
1050}
1051
1057
1063
1065{
1066 const bool wasPopup = mFlags.testFlag(Qt::Popup);
1067 const bool isPopup = flags.testFlag(Qt::Popup);
1068
1069 mFlags = flags;
1070 // changing role is not allowed on XdgShell on the same wl_surface
1071 if (wasPopup != isPopup) {
1072 reset();
1074 if (window()->isVisible()) {
1075 initWindow();
1076 }
1077 } else {
1078 if (mShellSurface)
1080 }
1081
1083
1087 m_cutouts.reset();
1089 }
1090
1093}
1094
1096{
1097 return mFlags;
1098}
1099
1110
1115
1116static QWaylandWindow *closestShellSurfaceWindow(QWindow *window)
1117{
1118 while (window) {
1119 auto w = static_cast<QWaylandWindow *>(window->handle());
1120 if (w && w->shellSurface())
1121 return w;
1122 window = window->transientParent() ? window->transientParent() : window->parent();
1123 }
1124 return nullptr;
1125}
1126
1131
1133{
1134 // Take the closest window with a shell surface, since the transient parent may be a
1135 // QWidgetWindow or some other window without a shell surface, which is then not able to
1136 // get mouse events.
1138 return transientParent;
1139
1140 if (window()->type() == Qt::Popup) {
1141 if (mTopPopup)
1142 return mTopPopup;
1143 }
1144
1145 if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup) {
1146 if (auto lastInputWindow = display()->lastInputWindow())
1148 }
1149
1150 return nullptr;
1151}
1152
1154{
1155 // There's currently no way to get info about the actual hardware device in use.
1156 // At least we get the correct seat.
1158 if (e.type == QEvent::Leave) {
1160#if QT_CONFIG(cursor)
1162#endif
1163 return;
1164 }
1165
1166#if QT_CONFIG(cursor)
1167 if (e.type == QEvent::Enter) {
1169 }
1170#endif
1171
1172 switch (e.type) {
1173 case QEvent::Enter:
1175#if QT_CONFIG(cursor)
1177#endif
1178 break;
1181 case QEvent::MouseMove:
1183 break;
1184 case QEvent::Wheel:
1187 e.phase, e.source, e.inverted);
1188 break;
1189 default:
1190 Q_UNREACHABLE();
1191 }
1192
1193}
1194
1195#ifndef QT_NO_GESTURES
1198{
1199 switch (e.state) {
1200 case Qt::GestureStarted:
1202 qCWarning(lcQpaWaylandInput) << "Unexpected GestureStarted while already active";
1203
1204
1209 e.local, e.global, e.fingers);
1210 break;
1211 case Qt::GestureUpdated:
1213 return;
1214
1215 if (!e.delta.isNull()) {
1219 0, e.delta, e.local, e.global, e.fingers);
1220 }
1221 break;
1222 case Qt::GestureFinished:
1223 case Qt::GestureCanceled:
1224
1226 qCWarning(lcQpaWaylandInput) << "Unexpected" << (e.state == Qt::GestureFinished ? "GestureFinished" : "GestureCanceled");
1227
1229
1230 // There's currently no way to expose cancelled gestures to the rest of Qt, so
1231 // this part of information is lost.
1235 e.local, e.global, e.fingers);
1236 break;
1237 default:
1238 break;
1239 }
1240}
1241
1244{
1245 switch (e.state) {
1246 case Qt::GestureStarted:
1248 qCWarning(lcQpaWaylandInput) << "Unexpected GestureStarted while already active";
1249
1254 e.local, e.global, e.fingers);
1255 break;
1256 case Qt::GestureUpdated:
1258 return;
1259
1260 if (!e.delta.isNull()) {
1264 0, e.delta, e.local, e.global, e.fingers);
1265 }
1266 if (e.rotation_delta != 0) {
1271 e.local, e.global, e.fingers);
1272 }
1273 if (e.scale_delta != 0) {
1277 e.scale_delta,
1278 e.local, e.global, e.fingers);
1279 }
1280 break;
1281 case Qt::GestureFinished:
1282 case Qt::GestureCanceled:
1284 qCWarning(lcQpaWaylandInput) << "Unexpected" << (e.state == Qt::GestureFinished ? "GestureFinished" : "GestureCanceled");
1285
1287
1288 // There's currently no way to expose cancelled gestures to the rest of Qt, so
1289 // this part of information is lost.
1293 e.local, e.global, e.fingers);
1294 break;
1295 default:
1296 break;
1297 }
1298}
1299
1300#endif // #ifndef QT_NO_GESTURES
1301
1302
1307
1309{
1311
1312 if (!newScreen || newScreen->screen() == window()->screen())
1313 return;
1314
1316
1318 && window()->type() != Qt::ToolTip && window()->type() != Qt::Tool
1319 && geometry().topLeft() != newScreen->geometry().topLeft()) {
1320 auto geometry = this->geometry();
1323 }
1324
1325 updateScale();
1327}
1328
1330{
1331 if (mFractionalScale) {
1336 return;
1337 }
1338
1339 if (mSurface && mSurface->version() >= 6) {
1343 return;
1344 }
1345
1346 int scale = screen()->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(screen())->scale();
1347 setScale(scale);
1348}
1349
1351{
1353 return;
1354 mScale = newScale;
1355
1356 if (mSurface) {
1357 if (mViewport)
1359 else if (mSurface->version() >= 3)
1361 }
1362 ensureSize();
1363
1365 if (isExposed()) {
1366 // redraw at the new DPR
1367 window()->requestUpdate();
1369 }
1370}
1371
1372#if QT_CONFIG(cursor)
1374{
1377 } else if (mHasStoredCursor) {
1379 } else {
1381 }
1382}
1383
1385{
1386 mHasStoredCursor = false;
1387}
1388
1389// Keep track of application set cursors on each window
1392 mHasStoredCursor = true;
1393}
1394
1396 if (!device || !device->pointer() || device->pointer()->focusSurface() != waylandSurface())
1397 return;
1398
1401}
1402#endif
1403
1405{
1406 QWaylandWindow *toplevel = this;
1407 while (auto parent = static_cast<QWaylandWindow *>(toplevel->QPlatformWindow::parent()))
1408 toplevel = parent;
1409
1410 if (toplevel != this) {
1413 return;
1414 }
1415
1418 mDisplay->setActiveSubSurface(nullptr);
1419 return;
1420 }
1421
1422 if (mShellSurface)
1424}
1425
1427{
1428 if (!window()->isVisible())
1429 return false;
1430
1432 return false;
1433
1434 if (mShellSurface)
1435 return mShellSurface->isExposed();
1436
1438 return mSubSurfaceWindow->parent()->isExposed();
1439
1441}
1442
1444{
1445 bool exposed = calculateExposure();
1446 if (exposed == mExposed)
1447 return;
1448
1449 mExposed = exposed;
1450
1451 if (!exposed)
1453 else
1455
1457 auto subWindow = subSurface->window();
1459 }
1460}
1461
1463{
1464 return mExposed;
1465}
1466
1468{
1469 return mDisplay->isWindowActivated(this);
1470}
1471
1473{
1474 return devicePixelRatio();
1475}
1476
1481
1483{
1484 if (window()->type() != Qt::Popup) {
1485 qWarning("This plugin supports grabbing the mouse only for popup windows");
1486 return false;
1487 }
1488
1489 mMouseGrab = grab ? this : nullptr;
1490 return true;
1491}
1492
1497
1502
1507
1517
1527
1535
1537{
1538 return m_properties;
1539}
1540
1545
1550
1551#ifdef QT_PLATFORM_WINDOW_HAS_VIRTUAL_SET_BACKING_STORE
1553{
1554 mBackingStore = dynamic_cast<QWaylandShmBackingStore *>(store);
1555}
1556#endif
1557
1559{
1561 return;
1562
1563 {
1565
1571 }
1573 return;
1574 }
1576 }
1577
1578 qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
1581}
1582
1584{
1585 qCDebug(lcWaylandBackingstore) << "requestUpdate";
1586 Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
1587
1588 // If we have a frame callback all is good and will be taken care of there
1589 {
1591 if (mFrameCallback)
1592 return;
1593 }
1594
1595 // Some applications (such as Qt Quick) depend on updates being delivered asynchronously,
1596 // so use invokeMethod to delay the delivery a bit.
1597 QMetaObject::invokeMethod(this, [this] {
1598 // Things might have changed in the meantime
1599 {
1601 if (mFrameCallback)
1602 return;
1603 }
1606 }, Qt::QueuedConnection);
1607}
1608
1609// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly
1610// with eglSwapBuffers) to know when it's time to commit the next one.
1611// Can be called from the render thread (without locking anything) so make sure to not make races in this method.
1613{
1615 qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
1616
1617 // TODO: Should sync subsurfaces avoid requesting frame callbacks?
1619 if (!mSurface)
1620 return;
1621
1623 if (mFrameCallback)
1624 return;
1625
1626 struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
1631
1632 // Start a timer for handling the case when the compositor stops sending frame callbacks.
1633 if (mFrameCallbackTimeout > 0) {
1634 QMetaObject::invokeMethod(this, [this] {
1636
1637 if (mFrameCallback) {
1641 }
1642 }, Qt::QueuedConnection);
1643 }
1644}
1645
1651
1653{
1654 qCDebug(lcWaylandBackingstore) << "deliverUpdateRequest";
1655 if (decoration())
1658
1659 // an update request doesn't always force a commit if the window isn't damaged, so also force it
1661 mPendingForcedUpdate = false;
1664 }
1665}
1666
1668{
1669 mOffset += point;
1670}
1671
1677
1679{
1680 if (auto *seat = display()->lastInputDevice()) {
1683 return rc;
1684 }
1685 return false;
1686}
1687
1689{
1690 if (auto seat = display()->lastInputDevice()) {
1693 return rc;
1694 }
1695 return false;
1696}
1697
1698bool QWaylandWindow::isOpaque() const
1699{
1700 return window()->requestedFormat().alphaBufferSize() <= 0;
1701}
1702
1704{
1705 if (opaqueArea == mOpaqueArea || !mSurface)
1706 return;
1707
1709
1713}
1714
1716{
1717 if (!mShellSurface) {
1718 qCWarning(lcQpaWayland) << "requestXdgActivationToken is called with no surface role created, emitting synthetic signal";
1720 return;
1721 }
1723}
1724
1726{
1727 if (mShellSurface)
1729 else
1730 qCWarning(lcQpaWayland) << "setXdgActivationToken is called with no surface role created, token" << token << "discarded";
1731}
1732
1734{
1735 if (mShellSurface)
1738}
1739
1741{
1742 if (mShellSurface)
1745}
1746
1748 while (!mChildPopups.isEmpty()) {
1749 auto popup = mChildPopups.takeLast();
1751 }
1752}
1753
1755{
1756 if (window()->isVisible()) {
1757 initWindow();
1760 }
1761}
1762
1764{
1767 if (auto *dec = decoration(); dec && window()->isVisible())
1768 dec->update();
1769 } else if (event->type() == QEvent::WindowUnblocked) {
1770 // QtGui sends leave event to window under cursor when modal window opens, so we have
1771 // to send enter event when modal closes and window has cursor and gets unblocked.
1773 const auto pos = mDisplay->waylandCursor()->pos();
1775 }
1776 }
1777
1779}
1780
1782{
1783 return mSurfaceFormat;
1784}
1785
1790
1795
1799
1804
1811
1816
1818{
1819 if (!window() || window()->flags() & Qt::WindowDoesNotAcceptFocus)
1820 return;
1821
1823 const bool isSubsurface = !!subSurfaceWindow();
1824
1825 auto toplevelIsActive = [&](QWaylandWindow *w) -> bool {
1826 while (w && w->subSurfaceWindow())
1827 w = static_cast<QWaylandWindow *>(w->QPlatformWindow::parent());
1828 return mDisplay->isWindowActivated(w);
1829 };
1830
1834 mDisplay->setActiveSubSurface(nullptr);
1835}
1836
1837}
1838
1839QT_END_NAMESPACE
1840
1841#include "moc_qwaylandwindow_p.cpp"
Combined button and popup list for selecting options.
Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland")
static QWaylandWindow * closestShellSurfaceWindow(QWindow *window)