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
5
23
24#include <QtCore/QFileInfo>
25#include <QtCore/QPointer>
26#include <QtCore/QRegularExpression>
27#include <QtGui/QWindow>
28
29#include <QGuiApplication>
30#include <qpa/qwindowsysteminterface.h>
31#include <QtGui/private/qguiapplication_p.h>
32#include <QtGui/private/qwindow_p.h>
33
34#include <QtCore/QDebug>
35#include <QtCore/QThread>
36#include <QtCore/private/qthread_p.h>
37
38#include <QtWaylandClient/private/qwayland-fractional-scale-v1.h>
39
41
42using namespace Qt::StringLiterals;
43
44namespace QtWaylandClient {
45
46Q_LOGGING_CATEGORY(lcWaylandBackingstore, "qt.qpa.wayland.backingstore")
47
50
73
75{
77 reset();
78
79 const QWindow *parent = window();
80 const auto tlw = QGuiApplication::topLevelWindows();
81 for (QWindow *w : tlw) {
82 if (w->transientParent() == parent)
84 }
85
86 if (mMouseGrab == this) {
87 mMouseGrab = nullptr;
88 }
89}
90
98
100{
101 /**
102 * Cleanup window state just before showing.
103 * This is necessary because a render could still have been running and commit
104 * after the window was last hidden and the last null was attached
105 *
106 * When we port to synchronous delivery it should be possible to drop this
107 */
108 mSurface->attach(nullptr, 0, 0);
109 mSurface->commit();
111
112 if (window()->type() == Qt::Desktop)
113 return;
114
117
118 auto *parent = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
119 if (!parent->mSurface)
121 if (parent->wlSurface()) {
124 }
125 } else if (shouldCreateShellSurface()) {
129 if (mTransientParent) {
130 if (window()->type() == Qt::Popup) {
132 qCWarning(lcQpaWayland) << "Creating a popup with a parent," << mTransientParent->window()
133 << "which does not match the current topmost grabbing popup,"
134 << mTopPopup->window() << "With some shell surface protocols, this"
135 << "is not allowed. The wayland QPA plugin is currently handling"
136 << "it by setting the parent to the topmost grabbing popup."
137 << "Note, however, that this may cause positioning errors and"
138 << "popups closing unxpectedly. Please fix the transient parent of the popup.";
140 }
141 mTopPopup = this;
142 }
143 }
144
146 if (mShellSurface) {
147 if (mTransientParent) {
148 if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup)
150 }
151
152 // Set initial surface title
155
156 // The appId is the desktop entry identifier that should follow the
157 // reverse DNS convention (see
158 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html). According
159 // to xdg-shell the appId is only the name, without the .desktop suffix.
160 //
161 // If the application specifies the desktop file name use that,
162 // otherwise fall back to the executable name and prepend the
163 // reversed organization domain when available.
166 } else {
171
172 if (domainName.isEmpty()) {
174 } else {
176 for (int i = 0; i < domainName.size(); ++i)
180 }
181 }
182 // the user may have already set some window properties, so make sure to send them out
183 for (auto it = m_properties.cbegin(); it != m_properties.cend(); ++it)
185
187 } else {
188 qWarning("Could not create a shell surface object.");
189 }
190 }
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
203 if (geometry.width() <= 0)
205 if (geometry.height() <= 0)
207
209 setMask(window()->mask());
210 if (mShellSurface)
213 mFlags = window()->flags();
214
215 mSurface->commit();
216}
217
219{
221}
222
224{
226 {
235 mSurface->m_window = this;
236 }
238
241
244 }
245 // The fractional scale manager check is needed to work around Gnome < 36 where viewports don't work
246 // Right now viewports are only necessary when a fractional scale manager is used
249 }
250
253 // TODO try a similar (same primaries + supported transfer function) color space if this fails?
260 } else {
261 qCWarning(lcQpaWayland) << "couldn't create image description for requested color space" << requestedColorSpace;
262 }
263 }
264}
265
272
274{
276 if (mShellSurface) {
277 qCWarning(lcQpaWayland) << "Cannot set shell integration while there's already a shell surface created";
278 return;
279 }
281}
282
284{
285 if (!shellIntegration())
286 return false;
287
289 return false;
290
291 if (window()->inherits("QShapedPixmapWindow"))
292 return false;
293
294 if (qEnvironmentVariableIsSet("QT_WAYLAND_USE_BYPASSWINDOWMANAGERHINT"))
295 return !(window()->flags() & Qt::BypassWindowManagerHint);
296
297 return true;
298}
299
301{
302 return QPlatformWindow::parent() != nullptr;
303}
304
310
312{
314 mInFrameRender = false;
315}
316
344
346{
347 // Old Reset
349
350 if (mTopPopup == this)
354 mTransientParent = nullptr;
355 delete std::exchange(mShellSurface, nullptr);
356 delete std::exchange(mSubSurfaceWindow, nullptr);
358
360 mInFrameRender = false;
362 mExposed = false;
363}
364
366{
367 {
369 if (mFrameCallback) {
371 mFrameCallback = nullptr;
372 }
375 }
379 }
381}
382
384{
386 return s->m_window;
387 return nullptr;
388}
389
391{
392 return reinterpret_cast<WId>(wlSurface());
393}
394
396{
397 if (lastParent == parent)
398 return;
399
400 if (mSubSurfaceWindow && parent) { // new parent, but we were a subsurface already
401 delete mSubSurfaceWindow;
402 QWaylandWindow *p = const_cast<QWaylandWindow *>(static_cast<const QWaylandWindow *>(parent));
404 } else if ((!lastParent && parent) || (lastParent && !parent)) {
405 // we're changing role, need to make a new wl_surface
406 reset();
408 if (window()->isVisible()) {
409 initWindow();
410 }
411 }
413}
414
416{
417 return mWindowTitle;
418}
419
421{
422 const QString separator = QString::fromUtf8(" \xe2\x80\x94 "); // unicode character U+2014, EM DASH
424
425 const int libwaylandMaxBufferSize = 4096;
426 // Some parts of the buffer is used for metadata, so subtract 100 to be on the safe side.
427 // Also, QString is in utf-16, which means that in the worst case each character will be
428 // three bytes when converted to utf-8 (which is what libwayland uses), so divide by three.
429 const int maxLength = libwaylandMaxBufferSize / 3 - 100;
430
432 if (truncated.size() < formatted.size()) {
433 qCWarning(lcQpaWayland) << "Window titles longer than" << maxLength << "characters are not supported."
434 << "Truncating window title (from" << formatted.size() << "chars)";
435 }
436
438
439 if (mShellSurface)
441
444}
445
455
457{
458 return QRect(QPoint(), QSize(500,500));
459}
460
462{
464 if (mViewport)
466
467 if (mSubSurfaceWindow) {
470
475 }
476 }
477}
478
517
519{
520 if (!mSurface)
521 return;
522
524
528
530 return;
531
534
536 mSurface->set_input_region(nullptr);
537 } else {
541 }
542}
543
545{
546 if (!surfaceSize().isEmpty())
548}
549
564
575
588
590{
594 }
595 else
596 qCDebug(lcQpaWayland) << "sendExposeEvent: intercepted by shell extension, not sending";
597}
598
600{
602 if (mSurface) {
603 if (auto *screen = mSurface->oldestEnteredScreen())
604 return screen;
605 }
606 return QPlatformWindow::screen();
607}
608
610{
611 // Workaround for issue where setVisible may be called with the same value twice
612 if (lastVisible == visible)
613 return;
615
616 if (visible) {
617 initWindow();
618
621 // Don't flush the events here, or else the newly visible window may start drawing, but since
622 // there was no frame before it will be stuck at the waitForFrameSync() in
623 // QWaylandShmBackingStore::beginPaint().
624
625 if (mShellSurface)
627 } else {
628 // make sure isExposed is false during the next event dispatch
629 mExposed = false;
632 mSurface->attach(nullptr, 0, 0);
633 mSurface->commit();
634 }
635}
636
637
639{
640 if (mShellSurface)
642}
643
644
646{
647 if (mShellSurface)
649}
650
652{
654 if (!mSurface)
655 return;
656
657 if (mMask == mask)
658 return;
659
660 mMask = mask;
661
663
664 if (isOpaque()) {
665 if (mMask.isEmpty())
667 else
669 }
670}
671
677
679{
680 if (mShellSurface)
681 return mShellSurface->isAlertState();
682
683 return false;
684}
685
693
695{
697 return;
698
700 "QWaylandWindow::applyConfigure", "not called from main thread");
701
702 // If we're mid paint, use an exposeEvent to flush the current frame.
703 // When this completes we know that no other frames will be rendering.
704 // This could be improved in future as we 're blocking for not just the frame to finish but one additional extra frame.
705 if (mInFrameRender)
707 if (mShellSurface)
709
714}
715
717{
719 if (mSurface == nullptr)
720 return;
721
722 if (buffer) {
724 handleUpdate();
725 buffer->setBusy(true);
727 mSurface->offset(x, y);
728 mSurface->attach(buffer->buffer(), 0, 0);
729 } else {
731 }
732 } else {
733 mSurface->attach(nullptr, 0, 0);
734 }
735}
736
742
744{
746 if (mSurface == nullptr)
747 return;
748
749 const qreal s = scale();
750 if (mSurface->version() >= 4) {
751 const QRect bufferRect =
752 QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
753 .toAlignedRect();
756 } else {
758 }
759}
760
762{
763 if (isExposed()) {
765 } else {
766 buffer->setBusy(false);
767 }
768}
769
774
776{
778 if (buffer->committed()) {
779 mSurface->commit();
780 qCDebug(lcWaylandBackingstore) << "Buffer already committed, not attaching.";
781 return;
782 }
783
785 if (!mSurface)
786 return;
787
789 if (mSurface->version() >= 4) {
790 const qreal s = scale();
791 for (const QRect &rect : damage) {
792 const QRect bufferRect =
793 QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
794 .toAlignedRect();
797 }
798 } else {
799 for (const QRect &rect: damage)
801 }
804 mSurface->commit();
805}
806
808{
810 if (mSurface != nullptr)
811 mSurface->commit();
812}
813
815 [](void *data, wl_callback *callback, uint32_t time) {
816 Q_UNUSED(time);
817 auto *window = static_cast<QWaylandWindow*>(data);
819 }
820};
821
823{
825 if (!mFrameCallback) {
826 // This means the callback is already unset by QWaylandWindow::reset.
827 // The wl_callback object will be destroyed there too.
828 return;
829 }
832 mFrameCallback = nullptr;
833
836
837 // The rest can wait until we can run it on the correct thread
839 // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
840 // in the single-threaded case.
842 }
844}
845
847{
849 bool wasExposed = isExposed();
851 // Did setting mFrameCallbackTimedOut make the window exposed?
855
856}
857
859{
861
864
866 qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
868 mWaitingForUpdate = false;
870 }
871
873}
874
884
889
896
897/*!
898 * Size, with decorations (including including eventual shadows) in wl_surface coordinates
899 */
904
917
918/*!
919 * Window geometry as defined by the xdg-shell spec (in wl_surface coordinates)
920 * topLeft is where the shadow stops and the decorations border start.
921 */
927
928/*!
929 * Converts from wl_surface coordinates to Qt window coordinates. Qt window
930 * coordinates start inside (not including) the window decorations, while
931 * wl_surface coordinates start at the first pixel of the buffer. Potentially,
932 * this should be in the window shadow, although we don't have those. So for
933 * now, it's the first pixel of the decorations.
934 */
940
942{
944 return mSurface ? mSurface->object() : nullptr;
945}
946
951
953{
955 return mSubSurfaceWindow->object();
956 if (mShellSurface)
957 return mShellSurface->surfaceRole();
958 return {};
959}
960
965
967{
971 return nullptr;
972 return static_cast<QWaylandScreen *>(platformScreen);
973}
974
980
982{
984 if (mSurface == nullptr || mSurface->version() < 2)
985 return;
986
989
990 if (mSurface->version() >= 6) {
992 if (auto screen = waylandScreen())
994 } else {
995 if (auto screen = window()->screen())
997 }
998
1000
1002 case Qt::PrimaryOrientation:
1004 break;
1007 break;
1008 case Qt::PortraitOrientation:
1010 break;
1013 break;
1016 break;
1017 default:
1018 Q_UNREACHABLE();
1019 }
1021}
1022
1028
1034
1046
1048{
1050 "QWaylandWindow::createDecoration", "not called from main thread");
1051 // TODO: client side decorations do not work with Vulkan backend.
1053 return false;
1055 return false;
1056
1057 static bool decorationPluginFailed = false;
1058 bool decoration = false;
1059 switch (window()->type()) {
1060 case Qt::Window:
1061 case Qt::Widget:
1062 case Qt::Dialog:
1063 case Qt::Tool:
1064 case Qt::Drawer:
1065 decoration = true;
1066 break;
1067 default:
1068 break;
1069 }
1071 decoration = false;
1073 decoration = false;
1075 decoration = false;
1077 decoration = false;
1078
1082 if (mWindowDecoration) {
1084 }
1085
1087 if (decorations.empty()) {
1088 qWarning() << "No decoration plugins available. Running with no decorations.";
1090 return false;
1091 }
1092
1094 QByteArray decorationPluginName = qgetenv("QT_WAYLAND_DECORATION");
1098 qWarning() << "Requested decoration " << targetKey << " not found, falling back to default";
1099 targetKey = QString(); // fallthrough
1100 }
1101 }
1102
1103 if (targetKey.isEmpty()) {
1104 auto unixServices = dynamic_cast<QDesktopUnixServices *>(
1107 if (desktopNames.contains("GNOME")) {
1108 if (decorations.contains("adwaita"_L1))
1109 targetKey = "adwaita"_L1;
1110 else if (decorations.contains("gnome"_L1))
1111 targetKey = "gnome"_L1;
1112 } else {
1113 // Do not use Adwaita/GNOME decorations on other DEs
1114 decorations.removeAll("adwaita"_L1);
1115 decorations.removeAll("gnome"_L1);
1116 }
1117 }
1118
1119 if (targetKey.isEmpty())
1120 targetKey = decorations.first(); // first come, first served.
1121
1123 if (!mWindowDecoration) {
1124 qWarning() << "Could not create decoration from factory! Running with no decorations.";
1126 return false;
1127 }
1130 }
1131 } else {
1133 }
1134
1139 subsurf->set_position(pos.x() + m.left(), pos.y() + m.top());
1140 }
1142
1143 // creating a decoration changes our margins which in turn change size hints
1145
1146 // This is a special case where the buffer is recreated, but since
1147 // the content rect remains the same, the widgets remain the same
1148 // size and are not redrawn, leaving the new buffer empty. As a simple
1149 // work-around, we trigger a full extra update whenever the client-side
1150 // window decorations are toggled while the window is showing.
1151 window()->requestUpdate();
1152 }
1153
1154 return mWindowDecoration.get();
1155}
1156
1161
1162static QWaylandWindow *closestShellSurfaceWindow(QWindow *window)
1163{
1164 while (window) {
1165 auto w = static_cast<QWaylandWindow *>(window->handle());
1166 if (w && w->shellSurface())
1167 return w;
1168 window = window->transientParent() ? window->transientParent() : window->parent();
1169 }
1170 return nullptr;
1171}
1172
1177
1179{
1180 // Take the closest window with a shell surface, since the transient parent may be a
1181 // QWidgetWindow or some other window without a shell surface, which is then not able to
1182 // get mouse events.
1184 return transientParent;
1185
1186 if (window()->type() == Qt::Popup) {
1187 if (mTopPopup)
1188 return mTopPopup;
1189 }
1190
1191 if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup) {
1192 if (auto lastInputWindow = display()->lastInputWindow())
1194 }
1195
1196 return nullptr;
1197}
1198
1200{
1201 // There's currently no way to get info about the actual hardware device in use.
1202 // At least we get the correct seat.
1204 if (e.type == QEvent::Leave) {
1208 } else {
1210 }
1211#if QT_CONFIG(cursor)
1213#endif
1214 return;
1215 }
1216
1219 } else {
1220 switch (e.type) {
1221 case QEvent::Enter:
1223#if QT_CONFIG(cursor)
1225#endif
1226 break;
1229 case QEvent::MouseMove:
1231 break;
1232 case QEvent::Wheel:
1235 e.phase, e.source, e.inverted);
1236 break;
1237 default:
1238 Q_UNREACHABLE();
1239 }
1240 }
1241
1242#if QT_CONFIG(cursor)
1243 if (e.type == QEvent::Enter) {
1247 }
1248#endif
1249}
1250
1251#ifndef QT_NO_GESTURES
1254{
1255 switch (e.state) {
1256 case Qt::GestureStarted:
1258 qCWarning(lcQpaWaylandInput) << "Unexpected GestureStarted while already active";
1259
1261 // whole gesture sequence will be ignored
1263 return;
1264 }
1265
1270 e.local, e.global, e.fingers);
1271 break;
1272 case Qt::GestureUpdated:
1274 return;
1275
1276 if (!e.delta.isNull()) {
1280 0, e.delta, e.local, e.global, e.fingers);
1281 }
1282 break;
1283 case Qt::GestureFinished:
1284 case Qt::GestureCanceled:
1287 return;
1288 }
1289
1291 qCWarning(lcQpaWaylandInput) << "Unexpected" << (e.state == Qt::GestureFinished ? "GestureFinished" : "GestureCanceled");
1292
1294
1295 // There's currently no way to expose cancelled gestures to the rest of Qt, so
1296 // this part of information is lost.
1300 e.local, e.global, e.fingers);
1301 break;
1302 default:
1303 break;
1304 }
1305}
1306
1309{
1310 switch (e.state) {
1311 case Qt::GestureStarted:
1313 qCWarning(lcQpaWaylandInput) << "Unexpected GestureStarted while already active";
1314
1316 // whole gesture sequence will be ignored
1318 return;
1319 }
1320
1325 e.local, e.global, e.fingers);
1326 break;
1327 case Qt::GestureUpdated:
1329 return;
1330
1331 if (!e.delta.isNull()) {
1335 0, e.delta, e.local, e.global, e.fingers);
1336 }
1337 if (e.rotation_delta != 0) {
1342 e.local, e.global, e.fingers);
1343 }
1344 if (e.scale_delta != 0) {
1348 e.scale_delta,
1349 e.local, e.global, e.fingers);
1350 }
1351 break;
1352 case Qt::GestureFinished:
1353 case Qt::GestureCanceled:
1356 return;
1357 }
1358
1360 qCWarning(lcQpaWaylandInput) << "Unexpected" << (e.state == Qt::GestureFinished ? "GestureFinished" : "GestureCanceled");
1361
1363
1364 // There's currently no way to expose cancelled gestures to the rest of Qt, so
1365 // this part of information is lost.
1369 e.local, e.global, e.fingers);
1370 break;
1371 default:
1372 break;
1373 }
1374}
1375#endif // #ifndef QT_NO_GESTURES
1376
1377
1384
1394
1396{
1397 // There's currently no way to get info about the actual hardware device in use.
1398 // At least we get the correct seat.
1405 }
1406 return;
1407 }
1408
1410 QRect windowRect(0 + marg.left(),
1411 0 + marg.top(),
1412 geometry().size().width(),
1413 geometry().size().height());
1420#if QT_CONFIG(cursor)
1422#endif
1424 }
1425
1426 switch (e.type) {
1427 case QEvent::Enter:
1429#if QT_CONFIG(cursor)
1431#endif
1432 break;
1435 case QEvent::MouseMove:
1437 break;
1438 case QEvent::Wheel: {
1442 e.phase, e.source, e.inverted);
1443 break;
1444 }
1445 default:
1446 Q_UNREACHABLE();
1447 }
1448
1451 } else {
1455 }
1456 }
1457}
1458
1460{
1462
1463 if (!newScreen || newScreen->screen() == window()->screen())
1464 return;
1465
1467
1469 && window()->type() != Qt::ToolTip
1470 && geometry().topLeft() != newScreen->geometry().topLeft()) {
1471 auto geometry = this->geometry();
1474 }
1475
1476 updateScale();
1478}
1479
1481{
1482 if (mFractionalScale) {
1487 return;
1488 }
1489
1490 if (mSurface && mSurface->version() >= 6) {
1494 return;
1495 }
1496
1497 int scale = screen()->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(screen())->scale();
1498 setScale(scale);
1499}
1500
1502{
1504 return;
1505 mScale = newScale;
1506
1507 if (mSurface) {
1508 if (mViewport)
1510 else if (mSurface->version() >= 3)
1512 }
1513 ensureSize();
1514
1516 if (isExposed()) {
1517 // redraw at the new DPR
1518 window()->requestUpdate();
1520 }
1521}
1522
1523#if QT_CONFIG(cursor)
1525{
1528}
1529
1531{
1534 else
1536}
1537#endif
1538
1544
1546{
1547 if (!window()->isVisible())
1548 return false;
1549
1551 return false;
1552
1553 if (mShellSurface)
1554 return mShellSurface->isExposed();
1555
1557 return mSubSurfaceWindow->parent()->isExposed();
1558
1560}
1561
1563{
1564 bool exposed = calculateExposure();
1565 if (exposed == mExposed)
1566 return;
1567
1568 mExposed = exposed;
1569
1570 if (!exposed)
1572 else
1574
1576 auto subWindow = subSurface->window();
1578 }
1579}
1580
1582{
1583 return mExposed;
1584}
1585
1587{
1588 return mDisplay->isWindowActivated(this);
1589}
1590
1592{
1593 return devicePixelRatio();
1594}
1595
1600
1602{
1603 if (window()->type() != Qt::Popup) {
1604 qWarning("This plugin supports grabbing the mouse only for popup windows");
1605 return false;
1606 }
1607
1608 mMouseGrab = grab ? this : nullptr;
1609 return true;
1610}
1611
1616
1621
1626
1636
1646
1654
1656{
1657 return m_properties;
1658}
1659
1664
1669
1670#ifdef QT_PLATFORM_WINDOW_HAS_VIRTUAL_SET_BACKING_STORE
1672{
1673 mBackingStore = dynamic_cast<QWaylandShmBackingStore *>(store);
1674}
1675#endif
1676
1678{
1680 return;
1681
1682 {
1684
1690 }
1692 return;
1693 }
1695 }
1696
1697 qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
1699 mWaitingForUpdate = false;
1701}
1702
1704{
1705 qCDebug(lcWaylandBackingstore) << "requestUpdate";
1706 Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
1707
1708 // If we have a frame callback all is good and will be taken care of there
1709 {
1712 return;
1713 }
1714
1715 // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
1716 // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log
1717 // here so we can get this information when debugging update/frame callback issues.
1718 // Continue as nothing happened, though.
1720 qCDebug(lcWaylandBackingstore) << "requestUpdate called twice without committing anything";
1721
1722 // Some applications (such as Qt Quick) depend on updates being delivered asynchronously,
1723 // so use invokeMethod to delay the delivery a bit.
1724 QMetaObject::invokeMethod(this, [this] {
1725 // Things might have changed in the meantime
1726 {
1729 return;
1730 }
1733 }, Qt::QueuedConnection);
1734}
1735
1736// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly
1737// with eglSwapBuffers) to know when it's time to commit the next one.
1738// Can be called from the render thread (without locking anything) so make sure to not make races in this method.
1740{
1741 qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
1742
1743 // TODO: Should sync subsurfaces avoid requesting frame callbacks?
1745 if (!mSurface)
1746 return;
1747
1750 return;
1751
1752 struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
1758 mWaitingForUpdate = false;
1759
1760 // Start a timer for handling the case when the compositor stops sending frame callbacks.
1761 if (mFrameCallbackTimeout > 0) {
1762 QMetaObject::invokeMethod(this, [this] {
1764
1769 }
1770 }, Qt::QueuedConnection);
1771 }
1772}
1773
1775{
1776 qCDebug(lcWaylandBackingstore) << "deliverUpdateRequest";
1777 mWaitingForUpdate = true;
1779}
1780
1782{
1783 mOffset += point;
1784}
1785
1791
1793{
1794 if (auto *seat = display()->lastInputDevice()) {
1797 return rc;
1798 }
1799 return false;
1800}
1801
1803{
1804 if (auto seat = display()->lastInputDevice()) {
1807 return rc;
1808 }
1809 return false;
1810}
1811
1812bool QWaylandWindow::isOpaque() const
1813{
1814 return window()->requestedFormat().alphaBufferSize() <= 0;
1815}
1816
1818{
1820
1822 return;
1823
1825
1829}
1830
1832{
1833 if (!mShellSurface) {
1834 qCWarning(lcQpaWayland) << "requestXdgActivationToken is called with no surface role created, emitting synthetic signal";
1836 return;
1837 }
1839}
1840
1842{
1843 if (mShellSurface)
1845 else
1846 qCWarning(lcQpaWayland) << "setXdgActivationToken is called with no surface role created, token" << token << "discarded";
1847}
1848
1850{
1851 if (mShellSurface)
1854}
1855
1857{
1858 if (mShellSurface)
1861}
1862
1864 while (!mChildPopups.isEmpty()) {
1865 auto popup = mChildPopups.takeLast();
1867 }
1868}
1869
1871{
1872 if (window()->isVisible()) {
1873 initWindow();
1876 }
1877}
1878
1889
1891{
1892 return mSurfaceFormat;
1893}
1894
1895}
1896
1897QT_END_NAMESPACE
1898
1899#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)