qtbug-119110.patch 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. From aae65c885d8e38d8abc2959cded7b5e9e5fc88b3 Mon Sep 17 00:00:00 2001
  2. From: Vlad Zahorodnii <vlad.zahorodnii@kde.org>
  3. Date: Tue, 14 Nov 2023 13:31:28 +0200
  4. Subject: Client: Move topmost grabbing popup tracking to QWaylandWindow
  5. If the effective transient parent is different from
  6. QWaylandWindow::transientParent(), then the popups may be closed in
  7. wrong order and producing an xdg-shell protocol error.
  8. This change lifts topmost popup tracking from the xdg-shell plugin to
  9. QWaylandWindow so it can guess the correct transient parent and the
  10. xdg-shell plugin doesn't have to pick a different parent behind our
  11. back.
  12. Fixes: QTBUG-119110
  13. Change-Id: I7c5f780b7bd4c3362aa7b22762ff336ae908ff70
  14. Reviewed-by: David Edmundson <davidedmundson@kde.org>
  15. (cherry picked from commit cfaae5d910406ef38d124e8e2c9114e2bfe87cb3)
  16. Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
  17. ---
  18. src/client/qwaylandwindow.cpp | 23 ++++++++++++++++++++--
  19. src/client/qwaylandwindow_p.h | 3 ++-
  20. .../xdg-shell/qwaylandxdgshell.cpp | 18 -----------------
  21. .../xdg-shell/qwaylandxdgshell_p.h | 1 -
  22. 4 files changed, 23 insertions(+), 22 deletions(-)
  23. diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
  24. index b81e00ef..de2cafb6 100644
  25. --- a/src/client/qwaylandwindow.cpp
  26. +++ b/src/client/qwaylandwindow.cpp
  27. @@ -41,6 +41,7 @@ namespace QtWaylandClient {
  28. Q_LOGGING_CATEGORY(lcWaylandBackingstore, "qt.qpa.wayland.backingstore")
  29. QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
  30. +QWaylandWindow *QWaylandWindow::mTopPopup = nullptr;
  31. QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
  32. : QPlatformWindow(window)
  33. @@ -136,7 +137,22 @@ void QWaylandWindow::initWindow()
  34. } else if (shouldCreateShellSurface()) {
  35. Q_ASSERT(!mShellSurface);
  36. Q_ASSERT(mShellIntegration);
  37. - mTransientParent = closestTransientParent();
  38. + mTransientParent = guessTransientParent();
  39. + if (mTransientParent) {
  40. + if (window()->type() == Qt::Popup) {
  41. + if (mTopPopup && mTopPopup != mTransientParent) {
  42. + qCWarning(lcQpaWayland) << "Creating a popup with a parent," << mTransientParent->window()
  43. + << "which does not match the current topmost grabbing popup,"
  44. + << mTopPopup->window() << "With some shell surface protocols, this"
  45. + << "is not allowed. The wayland QPA plugin is currently handling"
  46. + << "it by setting the parent to the topmost grabbing popup."
  47. + << "Note, however, that this may cause positioning errors and"
  48. + << "popups closing unxpectedly. Please fix the transient parent of the popup.";
  49. + mTransientParent = mTopPopup;
  50. + }
  51. + mTopPopup = this;
  52. + }
  53. + }
  54. mShellSurface = mShellIntegration->createShellSurface(this);
  55. if (mShellSurface) {
  56. @@ -271,6 +287,9 @@ void QWaylandWindow::reset()
  57. {
  58. closeChildPopups();
  59. + if (mTopPopup == this)
  60. + mTopPopup = mTransientParent && (mTransientParent->window()->type() == Qt::Popup) ? mTransientParent : nullptr;
  61. +
  62. if (mSurface) {
  63. emit wlSurfaceDestroyed();
  64. QWriteLocker lock(&mSurfaceLock);
  65. @@ -1120,7 +1139,7 @@ QWaylandWindow *QWaylandWindow::transientParent() const
  66. return mTransientParent;
  67. }
  68. -QWaylandWindow *QWaylandWindow::closestTransientParent() const
  69. +QWaylandWindow *QWaylandWindow::guessTransientParent() const
  70. {
  71. // Take the closest window with a shell surface, since the transient parent may be a
  72. // QWidgetWindow or some other window without a shell surface, which is then not able to
  73. diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
  74. index fbf62906..862366ea 100644
  75. --- a/src/client/qwaylandwindow_p.h
  76. +++ b/src/client/qwaylandwindow_p.h
  77. @@ -349,7 +349,7 @@ private:
  78. void handleScreensChanged();
  79. void sendRecursiveExposeEvent();
  80. - QWaylandWindow *closestTransientParent() const;
  81. + QWaylandWindow *guessTransientParent() const;
  82. void addChildPopup(QWaylandWindow *child);
  83. void removeChildPopup(QWaylandWindow *child);
  84. @@ -361,6 +361,7 @@ private:
  85. void handleFrameCallback(struct ::wl_callback* callback);
  86. static QWaylandWindow *mMouseGrab;
  87. + static QWaylandWindow *mTopPopup;
  88. friend class QWaylandSubSurface;
  89. };
  90. diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
  91. index e5dde262..f6e3e08a 100644
  92. --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
  93. +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
  94. @@ -221,9 +221,6 @@ QWaylandXdgSurface::Popup::~Popup()
  95. destroy();
  96. if (m_grabbing) {
  97. - auto *shell = m_xdgSurface->m_shell;
  98. - Q_ASSERT(shell->m_topmostGrabbingPopup == this);
  99. - shell->m_topmostGrabbingPopup = m_parentXdgSurface ? m_parentXdgSurface->m_popup : nullptr;
  100. m_grabbing = false;
  101. // Synthesize Qt enter/leave events for popup
  102. @@ -255,7 +252,6 @@ void QWaylandXdgSurface::Popup::resetConfiguration()
  103. void QWaylandXdgSurface::Popup::grab(QWaylandInputDevice *seat, uint serial)
  104. {
  105. - m_xdgSurface->m_shell->m_topmostGrabbingPopup = this;
  106. xdg_popup::grab(seat->wl_seat(), serial);
  107. m_grabbing = true;
  108. }
  109. @@ -566,20 +562,6 @@ void QWaylandXdgSurface::setPopup(QWaylandWindow *parent)
  110. void QWaylandXdgSurface::setGrabPopup(QWaylandWindow *parent, QWaylandInputDevice *device, int serial)
  111. {
  112. - auto parentXdgSurface = qobject_cast<QWaylandXdgSurface *>(parent->shellSurface());
  113. - auto *top = m_shell->m_topmostGrabbingPopup;
  114. -
  115. - if (top && top->m_xdgSurface != parentXdgSurface) {
  116. - qCWarning(lcQpaWayland) << "setGrabPopup called with a parent," << parentXdgSurface
  117. - << "which does not match the current topmost grabbing popup,"
  118. - << top->m_xdgSurface << "According to the xdg-shell protocol, this"
  119. - << "is not allowed. The wayland QPA plugin is currently handling"
  120. - << "it by setting the parent to the topmost grabbing popup."
  121. - << "Note, however, that this may cause positioning errors and"
  122. - << "popups closing unxpectedly because xdg-shell mandate that child"
  123. - << "popups close before parents";
  124. - parent = top->m_xdgSurface->m_window;
  125. - }
  126. setPopup(parent);
  127. m_popup->grab(device, serial);
  128. diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
  129. index 951e8234..e2dc12dd 100644
  130. --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
  131. +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h
  132. @@ -171,7 +171,6 @@ private:
  133. QScopedPointer<QWaylandXdgDecorationManagerV1> m_xdgDecorationManager;
  134. QScopedPointer<QWaylandXdgActivationV1> m_xdgActivation;
  135. QScopedPointer<QWaylandXdgExporterV2> m_xdgExporter;
  136. - QWaylandXdgSurface::Popup *m_topmostGrabbingPopup = nullptr;
  137. friend class QWaylandXdgSurface;
  138. };
  139. --
  140. cgit v1.2.3