From e1ef4a7f89d49e8f2b56323a742ff4971a74da0b Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 27 Mar 2023 14:27:21 +0300 Subject: [PATCH] Client: Track parent-popup relationship in QWaylandWindow This reduces the amount of boilerplate code that goes in shell integration plugins providing popups. The main motivation behind this change though is to ensure that QWaylandWindow::addChildPopup() gets called outside the QWaylandShellSurface constructor so one could use the popup's shell surface object to customize parent-child relationship. mShellSurface = mShellIntegration->createShellSurface(this); when this code executes, addChildPopup() will be called before the return value of createShellSurface() is assigned to mShellSurface. Change-Id: I9ccfb21f46febb451bdd7b4aa7851a99f3a03655 Reviewed-by: David Edmundson --- .../xdg-shell/qwaylandxdgshell.cpp | 10 ++------ .../platforms/wayland/qwaylandwindow.cpp | 24 +++++++++++++++---- .../platforms/wayland/qwaylandwindow_p.h | 7 ++++-- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index cd6e835f8e6..bf6eb2d0313 100644 --- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -211,10 +211,8 @@ QWaylandXdgSurface::Popup::Popup(QWaylandXdgSurface *xdgSurface, QWaylandWindow , m_parent(parent) { - init(xdgSurface->get_popup(m_parentXdgSurface ? m_parentXdgSurface->object() : nullptr, positioner->object())); - if (m_parent) { - m_parent->addChildPopup(m_xdgSurface->window()); - } + init(xdgSurface->get_popup(m_parentXdgSurface ? m_parentXdgSurface->object() : nullptr, + positioner->object())); } QWaylandXdgSurface::Popup::~Popup() @@ -222,10 +220,6 @@ QWaylandXdgSurface::Popup::~Popup() if (isInitialized()) destroy(); - if (m_parent) { - m_parent->removeChildPopup(m_xdgSurface->window()); - } - if (m_grabbing) { auto *shell = m_xdgSurface->m_shell; Q_ASSERT(shell->m_topmostGrabbingPopup == this); diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 1111582e402..74db519f804 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -137,9 +137,15 @@ void QWaylandWindow::initWindow() } else if (shouldCreateShellSurface()) { Q_ASSERT(!mShellSurface); Q_ASSERT(mShellIntegration); + mTransientParent = closestTransientParent(); mShellSurface = mShellIntegration->createShellSurface(this); if (mShellSurface) { + if (mTransientParent) { + if (window()->type() == Qt::ToolTip || window()->type() == Qt::Popup) + mTransientParent->addChildPopup(this); + } + // Set initial surface title setWindowTitle(window()->title()); @@ -272,10 +278,13 @@ void QWaylandWindow::reset() emit wlSurfaceDestroyed(); QWriteLocker lock(&mSurfaceLock); invalidateSurface(); + if (mTransientParent) + mTransientParent->removeChildPopup(this); delete mShellSurface; mShellSurface = nullptr; delete mSubSurfaceWindow; mSubSurfaceWindow = nullptr; + mTransientParent = nullptr; mSurface.reset(); mViewport.reset(); mFractionalScale.reset(); @@ -1050,6 +1059,11 @@ static QWaylandWindow *closestShellSurfaceWindow(QWindow *window) } QWaylandWindow *QWaylandWindow::transientParent() const +{ + return mTransientParent; +} + +QWaylandWindow *QWaylandWindow::closestTransientParent() const { // Take the closest window with a shell surface, since the transient parent may be a // QWidgetWindow or some other window without a shell surface, which is then not able to @@ -1619,12 +1633,14 @@ void QWaylandWindow::setXdgActivationToken(const QString &token) mShellSurface->setXdgActivationToken(token); } -void QWaylandWindow::addChildPopup(QWaylandWindow *surface) { - mChildPopups.append(surface); +void QWaylandWindow::addChildPopup(QWaylandWindow *child) +{ + mChildPopups.append(child); } -void QWaylandWindow::removeChildPopup(QWaylandWindow *surface) { - mChildPopups.removeAll(surface); +void QWaylandWindow::removeChildPopup(QWaylandWindow *child) +{ + mChildPopups.removeAll(child); } void QWaylandWindow::closeChildPopups() { diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h index d0640e7eb2f..636cd179690 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow_p.h +++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h @@ -225,8 +225,6 @@ public: void beginFrame(); void endFrame(); - void addChildPopup(QWaylandWindow* child); - void removeChildPopup(QWaylandWindow* child); void closeChildPopups(); virtual void reinit(); @@ -320,6 +318,7 @@ protected: QMargins mCustomMargins; + QPointer mTransientParent; QList> mChildPopups; private: @@ -337,6 +336,10 @@ private: void handleScreensChanged(); void sendRecursiveExposeEvent(); + QWaylandWindow *closestTransientParent() const; + void addChildPopup(QWaylandWindow *child); + void removeChildPopup(QWaylandWindow *child); + bool mInResizeFromApplyConfigure = false; bool lastVisible = false; QRect mLastExposeGeometry;