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();
110
111 if (window()->type() == Qt::Desktop)
112 return;
113
116
117 auto *parent = static_cast<QWaylandWindow *>(QPlatformWindow::parent());
118 if (!parent->mSurface)
120 if (parent->wlSurface()) {
123 }
124 } else if (shouldCreateShellSurface()) {
128 if (mTransientParent) {
129 if (window()->type() == Qt::Popup) {
131 qCWarning(lcQpaWayland) << "Creating a popup with a parent," << mTransientParent->window()
132 << "which does not match the current topmost grabbing popup,"
133 << mTopPopup->window() << "With some shell surface protocols, this"
134 << "is not allowed. The wayland QPA plugin is currently handling"
135 << "it by setting the parent to the topmost grabbing popup."
136 << "Note, however, that this may cause positioning errors and"
137 << "popups closing unxpectedly. Please fix the transient parent of the popup.";
139 }
140 mTopPopup = this;
141 }
142 }
143
145 if (mShellSurface) {
146 if (mTransientParent) {
147 if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup)
149 }
150
151 // Set initial surface title
154
155 // The appId is the desktop entry identifier that should follow the
156 // reverse DNS convention (see
157 // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html). According
158 // to xdg-shell the appId is only the name, without the .desktop suffix.
159 //
160 // If the application specifies the desktop file name use that,
161 // otherwise fall back to the executable name and prepend the
162 // reversed organization domain when available.
165 } else {
170
171 if (domainName.isEmpty()) {
173 } else {
175 for (int i = 0; i < domainName.size(); ++i)
179 }
180 }
181 // the user may have already set some window properties, so make sure to send them out
182 for (auto it = m_properties.cbegin(); it != m_properties.cend(); ++it)
184
186 } else {
187 qWarning("Could not create a shell surface object.");
188 }
189 }
190
191 // Enable high-dpi rendering. Scale() returns the screen scale factor and will
192 // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
193 // to inform the compositor that high-resolution buffers will be provided.
194 if (mViewport)
196 else if (mSurface->version() >= 3)
198
202 if (geometry.width() <= 0)
204 if (geometry.height() <= 0)
206
208 setMask(window()->mask());
209 if (mShellSurface)
212 mFlags = window()->flags();
213
214 mSurface->commit();
215}
216
218{
220}
221
223{
225 {
234 mSurface->m_window = this;
235 }
237
240
243 }
244 // The fractional scale manager check is needed to work around Gnome < 36 where viewports don't work
245 // Right now viewports are only necessary when a fractional scale manager is used
248 }
249
252 // TODO try a similar (same primaries + supported transfer function) color space if this fails?
259 } else {
260 qCWarning(lcQpaWayland) << "couldn't create image description for requested color space" << requestedColorSpace;
261 }
262 }
263}
264
271
273{
275 if (mShellSurface) {
276 qCWarning(lcQpaWayland) << "Cannot set shell integration while there's already a shell surface created";
277 return;
278 }
280}
281
283{
284 if (!shellIntegration())
285 return false;
286
288 return false;
289
290 if (window()->inherits("QShapedPixmapWindow"))
291 return false;
292
293 if (qEnvironmentVariableIsSet("QT_WAYLAND_USE_BYPASSWINDOWMANAGERHINT"))
294 return !(window()->flags() & Qt::BypassWindowManagerHint);
295
296 return true;
297}
298
300{
301 return QPlatformWindow::parent() != nullptr;
302}
303
309
311{
313 mInFrameRender = false;
314}
315
343
345{
346 // Old Reset
348
349 if (mTopPopup == this)
353 mTransientParent = nullptr;
354 delete std::exchange(mShellSurface, nullptr);
355 delete std::exchange(mSubSurfaceWindow, nullptr);
357 {
359 if (mFrameCallback) {
361 mFrameCallback = nullptr;
362 }
365 }
369 }
370 mInFrameRender = false;
373 mExposed = false;
374}
375
377{
379 return s->m_window;
380 return nullptr;
381}
382
384{
385 return reinterpret_cast<WId>(wlSurface());
386}
387
389{
390 if (lastParent == parent)
391 return;
392
393 if (mSubSurfaceWindow && parent) { // new parent, but we were a subsurface already
394 delete mSubSurfaceWindow;
395 QWaylandWindow *p = const_cast<QWaylandWindow *>(static_cast<const QWaylandWindow *>(parent));
397 } else if ((!lastParent && parent) || (lastParent && !parent)) {
398 // we're changing role, need to make a new wl_surface
399 reset();
401 if (window()->isVisible()) {
402 initWindow();
403 }
404 }
406}
407
409{
410 return mWindowTitle;
411}
412
414{
415 const QString separator = QString::fromUtf8(" \xe2\x80\x94 "); // unicode character U+2014, EM DASH
417
418 const int libwaylandMaxBufferSize = 4096;
419 // Some parts of the buffer is used for metadata, so subtract 100 to be on the safe side.
420 // Also, QString is in utf-16, which means that in the worst case each character will be
421 // three bytes when converted to utf-8 (which is what libwayland uses), so divide by three.
422 const int maxLength = libwaylandMaxBufferSize / 3 - 100;
423
425 if (truncated.size() < formatted.size()) {
426 qCWarning(lcQpaWayland) << "Window titles longer than" << maxLength << "characters are not supported."
427 << "Truncating window title (from" << formatted.size() << "chars)";
428 }
429
431
432 if (mShellSurface)
434
437}
438
448
450{
451 return QRect(QPoint(), QSize(500,500));
452}
453
455{
457 if (mViewport)
459
460 if (mSubSurfaceWindow) {
463
468 }
469 }
470}
471
510
512{
513 if (!mSurface)
514 return;
515
517
521
523 return;
524
527
529 mSurface->set_input_region(nullptr);
530 } else {
534 }
535}
536
538{
539 if (!surfaceSize().isEmpty())
541}
542
557
568
581
583{
587 }
588 else
589 qCDebug(lcQpaWayland) << "sendExposeEvent: intercepted by shell extension, not sending";
590}
591
593{
595 if (mSurface) {
596 if (auto *screen = mSurface->oldestEnteredScreen())
597 return screen;
598 }
599 return QPlatformWindow::screen();
600}
601
603{
604 // Workaround for issue where setVisible may be called with the same value twice
605 if (lastVisible == visible)
606 return;
608
609 if (visible) {
610 initWindow();
611
614 // Don't flush the events here, or else the newly visible window may start drawing, but since
615 // there was no frame before it will be stuck at the waitForFrameSync() in
616 // QWaylandShmBackingStore::beginPaint().
617
618 if (mShellSurface)
620 } else {
621 // make sure isExposed is false during the next event dispatch
622 mExposed = false;
625 mSurface->attach(nullptr, 0, 0);
626 mSurface->commit();
627 }
628}
629
630
632{
633 if (mShellSurface)
635}
636
637
639{
640 if (mShellSurface)
642}
643
645{
647 if (!mSurface)
648 return;
649
650 if (mMask == mask)
651 return;
652
653 mMask = mask;
654
656
657 if (isOpaque()) {
658 if (mMask.isEmpty())
660 else
662 }
663}
664
670
672{
673 if (mShellSurface)
674 return mShellSurface->isAlertState();
675
676 return false;
677}
678
686
688{
690 return;
691
693 "QWaylandWindow::applyConfigure", "not called from main thread");
694
695 // If we're mid paint, use an exposeEvent to flush the current frame.
696 // When this completes we know that no other frames will be rendering.
697 // This could be improved in future as we 're blocking for not just the frame to finish but one additional extra frame.
698 if (mInFrameRender)
701 if (mShellSurface)
703
708}
709
711{
713 if (mSurface == nullptr)
714 return;
715
716 if (buffer) {
718 handleUpdate();
719 buffer->setBusy(true);
721 mSurface->offset(x, y);
722 mSurface->attach(buffer->buffer(), 0, 0);
723 } else {
725 }
726 } else {
727 mSurface->attach(nullptr, 0, 0);
728 }
729}
730
736
738{
740 if (mSurface == nullptr)
741 return;
742
743 const qreal s = scale();
744 if (mSurface->version() >= 4) {
745 const QRect bufferRect =
746 QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
747 .toAlignedRect();
750 } else {
752 }
753}
754
756{
757 if (isExposed()) {
759 } else {
760 buffer->setBusy(false);
761 }
762}
763
768
770{
772 if (buffer->committed()) {
773 mSurface->commit();
774 qCDebug(lcWaylandBackingstore) << "Buffer already committed, not attaching.";
775 return;
776 }
777
779 if (!mSurface)
780 return;
781
783 if (mSurface->version() >= 4) {
784 const qreal s = scale();
785 for (const QRect &rect : damage) {
786 const QRect bufferRect =
787 QRectF(s * rect.x(), s * rect.y(), s * rect.width(), s * rect.height())
788 .toAlignedRect();
791 }
792 } else {
793 for (const QRect &rect: damage)
795 }
798 mSurface->commit();
799}
800
802{
804 if (mSurface != nullptr)
805 mSurface->commit();
806}
807
809 [](void *data, wl_callback *callback, uint32_t time) {
810 Q_UNUSED(time);
811 auto *window = static_cast<QWaylandWindow*>(data);
813 }
814};
815
817{
819 if (!mFrameCallback) {
820 // This means the callback is already unset by QWaylandWindow::reset.
821 // The wl_callback object will be destroyed there too.
822 return;
823 }
826 mFrameCallback = nullptr;
827
830
831 // The rest can wait until we can run it on the correct thread
833 // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
834 // in the single-threaded case.
836 }
838}
839
841{
843 bool wasExposed = isExposed();
845 // Did setting mFrameCallbackTimedOut make the window exposed?
849
850}
851
853{
855
858
860 qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
862 mWaitingForUpdate = false;
864 }
865
867}
868
878
883
890
891/*!
892 * Size, with decorations (including including eventual shadows) in wl_surface coordinates
893 */
898
911
912/*!
913 * Window geometry as defined by the xdg-shell spec (in wl_surface coordinates)
914 * topLeft is where the shadow stops and the decorations border start.
915 */
921
922/*!
923 * Converts from wl_surface coordinates to Qt window coordinates. Qt window
924 * coordinates start inside (not including) the window decorations, while
925 * wl_surface coordinates start at the first pixel of the buffer. Potentially,
926 * this should be in the window shadow, although we don't have those. So for
927 * now, it's the first pixel of the decorations.
928 */
934
936{
938 return mSurface ? mSurface->object() : nullptr;
939}
940
945
947{
949 return mSubSurfaceWindow->object();
950 if (mShellSurface)
951 return mShellSurface->surfaceRole();
952 return {};
953}
954
959
961{
965 return nullptr;
966 return static_cast<QWaylandScreen *>(platformScreen);
967}
968
974
976{
978 if (mSurface == nullptr || mSurface->version() < 2)
979 return;
980
983
984 if (mSurface->version() >= 6) {
986 if (auto screen = waylandScreen())
988 } else {
989 if (auto screen = window()->screen())
991 }
992
994
998 break;
1001 break;
1002 case Qt::PortraitOrientation:
1004 break;
1007 break;
1010 break;
1011 default:
1012 Q_UNREACHABLE();
1013 }
1015}
1016
1022
1028
1040
1042{
1044 "QWaylandWindow::createDecoration", "not called from main thread");
1045 // TODO: client side decorations do not work with Vulkan backend.
1047 return false;
1049 return false;
1050
1051 static bool decorationPluginFailed = false;
1052 bool decoration = false;
1053 switch (window()->type()) {
1054 case Qt::Window:
1055 case Qt::Widget:
1056 case Qt::Dialog:
1057 case Qt::Tool:
1058 case Qt::Drawer:
1059 decoration = true;
1060 break;
1061 default:
1062 break;
1063 }
1065 decoration = false;
1067 decoration = false;
1069 decoration = false;
1071 decoration = false;
1072
1076 if (mWindowDecoration) {
1078 }
1079
1081 if (decorations.empty()) {
1082 qWarning() << "No decoration plugins available. Running with no decorations.";
1084 return false;
1085 }
1086
1088 QByteArray decorationPluginName = qgetenv("QT_WAYLAND_DECORATION");
1092 qWarning() << "Requested decoration " << targetKey << " not found, falling back to default";
1093 targetKey = QString(); // fallthrough
1094 }
1095 }
1096
1097 if (targetKey.isEmpty()) {
1098 auto unixServices = dynamic_cast<QDesktopUnixServices *>(
1101 if (desktopNames.contains("GNOME")) {
1102 if (decorations.contains("adwaita"_L1))
1103 targetKey = "adwaita"_L1;
1104 else if (decorations.contains("gnome"_L1))
1105 targetKey = "gnome"_L1;
1106 } else {
1107 // Do not use Adwaita/GNOME decorations on other DEs
1108 decorations.removeAll("adwaita"_L1);
1109 decorations.removeAll("gnome"_L1);
1110 }
1111 }
1112
1113 if (targetKey.isEmpty())
1114 targetKey = decorations.first(); // first come, first served.
1115
1117 if (!mWindowDecoration) {
1118 qWarning() << "Could not create decoration from factory! Running with no decorations.";
1120 return false;
1121 }
1124 }
1125 } else {
1127 }
1128
1133 subsurf->set_position(pos.x() + m.left(), pos.y() + m.top());
1134 }
1136
1137 // creating a decoration changes our margins which in turn change size hints
1139
1140 // This is a special case where the buffer is recreated, but since
1141 // the content rect remains the same, the widgets remain the same
1142 // size and are not redrawn, leaving the new buffer empty. As a simple
1143 // work-around, we trigger a full extra update whenever the client-side
1144 // window decorations are toggled while the window is showing.
1145 window()->requestUpdate();
1146 }
1147
1148 return mWindowDecoration.get();
1149}
1150
1155
1156static QWaylandWindow *closestShellSurfaceWindow(QWindow *window)
1157{
1158 while (window) {
1159 auto w = static_cast<QWaylandWindow *>(window->handle());
1160 if (w && w->shellSurface())
1161 return w;
1162 window = window->transientParent() ? window->transientParent() : window->parent();
1163 }
1164 return nullptr;
1165}
1166
1171
1173{
1174 // Take the closest window with a shell surface, since the transient parent may be a
1175 // QWidgetWindow or some other window without a shell surface, which is then not able to
1176 // get mouse events.
1178 return transientParent;
1179
1180 if (window()->type() == Qt::Popup) {
1181 if (mTopPopup)
1182 return mTopPopup;
1183 }
1184
1185 if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup) {
1186 if (auto lastInputWindow = display()->lastInputWindow())
1188 }
1189
1190 return nullptr;
1191}
1192
1194{
1195 // There's currently no way to get info about the actual hardware device in use.
1196 // At least we get the correct seat.
1198 if (e.type == QEvent::Leave) {
1202 } else {
1204 }
1205#if QT_CONFIG(cursor)
1207#endif
1208 return;
1209 }
1210
1213 } else {
1214 switch (e.type) {
1215 case QEvent::Enter:
1217#if QT_CONFIG(cursor)
1219#endif
1220 break;
1223 case QEvent::MouseMove:
1225 break;
1226 case QEvent::Wheel:
1229 e.phase, e.source, e.inverted);
1230 break;
1231 default:
1232 Q_UNREACHABLE();
1233 }
1234 }
1235
1236#if QT_CONFIG(cursor)
1237 if (e.type == QEvent::Enter) {
1241 }
1242#endif
1243}
1244
1245#ifndef QT_NO_GESTURES
1248{
1249 switch (e.state) {
1250 case Qt::GestureStarted:
1252 qCWarning(lcQpaWaylandInput) << "Unexpected GestureStarted while already active";
1253
1255 // whole gesture sequence will be ignored
1257 return;
1258 }
1259
1264 e.local, e.global, e.fingers);
1265 break;
1266 case Qt::GestureUpdated:
1268 return;
1269
1270 if (!e.delta.isNull()) {
1274 0, e.delta, e.local, e.global, e.fingers);
1275 }
1276 break;
1277 case Qt::GestureFinished:
1278 case Qt::GestureCanceled:
1281 return;
1282 }
1283
1285 qCWarning(lcQpaWaylandInput) << "Unexpected" << (e.state == Qt::GestureFinished ? "GestureFinished" : "GestureCanceled");
1286
1288
1289 // There's currently no way to expose cancelled gestures to the rest of Qt, so
1290 // this part of information is lost.
1294 e.local, e.global, e.fingers);
1295 break;
1296 default:
1297 break;
1298 }
1299}
1300
1303{
1304 switch (e.state) {
1305 case Qt::GestureStarted:
1307 qCWarning(lcQpaWaylandInput) << "Unexpected GestureStarted while already active";
1308
1310 // whole gesture sequence will be ignored
1312 return;
1313 }
1314
1319 e.local, e.global, e.fingers);
1320 break;
1321 case Qt::GestureUpdated:
1323 return;
1324
1325 if (!e.delta.isNull()) {
1329 0, e.delta, e.local, e.global, e.fingers);
1330 }
1331 if (e.rotation_delta != 0) {
1336 e.local, e.global, e.fingers);
1337 }
1338 if (e.scale_delta != 0) {
1342 e.scale_delta,
1343 e.local, e.global, e.fingers);
1344 }
1345 break;
1346 case Qt::GestureFinished:
1347 case Qt::GestureCanceled:
1350 return;
1351 }
1352
1354 qCWarning(lcQpaWaylandInput) << "Unexpected" << (e.state == Qt::GestureFinished ? "GestureFinished" : "GestureCanceled");
1355
1357
1358 // There's currently no way to expose cancelled gestures to the rest of Qt, so
1359 // this part of information is lost.
1363 e.local, e.global, e.fingers);
1364 break;
1365 default:
1366 break;
1367 }
1368}
1369#endif // #ifndef QT_NO_GESTURES
1370
1371
1378
1388
1390{
1391 // There's currently no way to get info about the actual hardware device in use.
1392 // At least we get the correct seat.
1399 }
1400 return;
1401 }
1402
1404 QRect windowRect(0 + marg.left(),
1405 0 + marg.top(),
1406 geometry().size().width(),
1407 geometry().size().height());
1414#if QT_CONFIG(cursor)
1416#endif
1418 }
1419
1420 switch (e.type) {
1421 case QEvent::Enter:
1423#if QT_CONFIG(cursor)
1425#endif
1426 break;
1429 case QEvent::MouseMove:
1431 break;
1432 case QEvent::Wheel: {
1436 e.phase, e.source, e.inverted);
1437 break;
1438 }
1439 default:
1440 Q_UNREACHABLE();
1441 }
1442
1445 } else {
1449 }
1450 }
1451}
1452
1454{
1456
1457 if (!newScreen || newScreen->screen() == window()->screen())
1458 return;
1459
1461
1463 && window()->type() != Qt::ToolTip
1464 && geometry().topLeft() != newScreen->geometry().topLeft()) {
1465 auto geometry = this->geometry();
1468 }
1469
1470 updateScale();
1472}
1473
1475{
1476 if (mFractionalScale) {
1481 return;
1482 }
1483
1484 if (mSurface && mSurface->version() >= 6) {
1488 return;
1489 }
1490
1491 int scale = screen()->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(screen())->scale();
1492 setScale(scale);
1493}
1494
1496{
1498 return;
1499 mScale = newScale;
1500
1501 if (mSurface) {
1502 if (mViewport)
1504 else if (mSurface->version() >= 3)
1506 }
1507 ensureSize();
1508
1510 if (isExposed()) {
1511 // redraw at the new DPR
1512 window()->requestUpdate();
1514 }
1515}
1516
1517#if QT_CONFIG(cursor)
1519{
1522}
1523
1525{
1528 else
1530}
1531#endif
1532
1538
1540{
1541 if (!window()->isVisible())
1542 return false;
1543
1545 return false;
1546
1547 if (mShellSurface)
1548 return mShellSurface->isExposed();
1549
1551 return mSubSurfaceWindow->parent()->isExposed();
1552
1554}
1555
1557{
1558 bool exposed = calculateExposure();
1559 if (exposed == mExposed)
1560 return;
1561
1562 mExposed = exposed;
1563
1564 if (!exposed)
1566 else
1568
1570 auto subWindow = subSurface->window();
1572 }
1573}
1574
1576{
1577 return mExposed;
1578}
1579
1581{
1582 return mDisplay->isWindowActivated(this);
1583}
1584
1586{
1587 return devicePixelRatio();
1588}
1589
1594
1596{
1597 if (window()->type() != Qt::Popup) {
1598 qWarning("This plugin supports grabbing the mouse only for popup windows");
1599 return false;
1600 }
1601
1602 mMouseGrab = grab ? this : nullptr;
1603 return true;
1604}
1605
1610
1615
1620
1630
1640
1648
1650{
1651 return m_properties;
1652}
1653
1658
1663
1664#ifdef QT_PLATFORM_WINDOW_HAS_VIRTUAL_SET_BACKING_STORE
1666{
1667 mBackingStore = dynamic_cast<QWaylandShmBackingStore *>(store);
1668}
1669#endif
1670
1672{
1674 return;
1675
1676 {
1678
1683 }
1685 return;
1686 }
1688 }
1689
1690 qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
1692 mWaitingForUpdate = false;
1694}
1695
1697{
1698 qCDebug(lcWaylandBackingstore) << "requestUpdate";
1699 Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
1700
1701 // If we have a frame callback all is good and will be taken care of there
1702 {
1705 return;
1706 }
1707
1708 // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
1709 // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log
1710 // here so we can get this information when debugging update/frame callback issues.
1711 // Continue as nothing happened, though.
1713 qCDebug(lcWaylandBackingstore) << "requestUpdate called twice without committing anything";
1714
1715 // Some applications (such as Qt Quick) depend on updates being delivered asynchronously,
1716 // so use invokeMethod to delay the delivery a bit.
1717 QMetaObject::invokeMethod(this, [this] {
1718 // Things might have changed in the meantime
1719 {
1722 return;
1723 }
1726 }, Qt::QueuedConnection);
1727}
1728
1729// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly
1730// with eglSwapBuffers) to know when it's time to commit the next one.
1731// Can be called from the render thread (without locking anything) so make sure to not make races in this method.
1733{
1734 qCDebug(lcWaylandBackingstore) << "handleUpdate" << QThread::currentThread();
1735
1736 // TODO: Should sync subsurfaces avoid requesting frame callbacks?
1738 if (!mSurface)
1739 return;
1740
1743 return;
1744
1745 struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
1751 mWaitingForUpdate = false;
1752
1753 // Start a timer for handling the case when the compositor stops sending frame callbacks.
1754 if (mFrameCallbackTimeout > 0) {
1755 QMetaObject::invokeMethod(this, [this] {
1757
1762 }
1763 }, Qt::QueuedConnection);
1764 }
1765}
1766
1768{
1769 qCDebug(lcWaylandBackingstore) << "deliverUpdateRequest";
1770 mWaitingForUpdate = true;
1772}
1773
1775{
1776 mOffset += point;
1777}
1778
1784
1786{
1787 if (auto *seat = display()->lastInputDevice()) {
1790 return rc;
1791 }
1792 return false;
1793}
1794
1796{
1797 if (auto seat = display()->lastInputDevice()) {
1800 return rc;
1801 }
1802 return false;
1803}
1804
1805bool QWaylandWindow::isOpaque() const
1806{
1807 return window()->requestedFormat().alphaBufferSize() <= 0;
1808}
1809
1811{
1813
1815 return;
1816
1818
1822}
1823
1825{
1826 if (!mShellSurface) {
1827 qCWarning(lcQpaWayland) << "requestXdgActivationToken is called with no surface role created, emitting synthetic signal";
1829 return;
1830 }
1832}
1833
1835{
1836 if (mShellSurface)
1838 else
1839 qCWarning(lcQpaWayland) << "setXdgActivationToken is called with no surface role created, token" << token << "discarded";
1840}
1841
1843{
1844 if (mShellSurface)
1847}
1848
1850{
1851 if (mShellSurface)
1854}
1855
1857 while (!mChildPopups.isEmpty()) {
1858 auto popup = mChildPopups.takeLast();
1860 }
1861}
1862
1864{
1865 if (window()->isVisible()) {
1866 initWindow();
1869 }
1870}
1871
1882
1884{
1885 return mSurfaceFormat;
1886}
1887
1888}
1889
1890QT_END_NAMESPACE
1891
1892#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)