From 2e3cddf8b28cf6ce2b4db9c9a21f0a2427bdf756 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Sun, 5 Jul 2015 17:58:23 +0300 Subject: Use standard wl_subsurface interface to set a window as a child of another one Change-Id: I52628f87dbea5383db06468f9748a9bacdec3179 Reviewed-by: Robin Burchell --- src/client/qwaylanddisplay.cpp | 15 ++++- src/client/qwaylanddisplay_p.h | 4 +- src/client/qwaylandsubsurface.cpp | 41 +++---------- src/client/qwaylandsubsurface_p.h | 14 ++--- src/client/qwaylandwindow.cpp | 126 ++++++++++++++++++++++++-------------- src/client/qwaylandwindow_p.h | 5 ++ 6 files changed, 113 insertions(+), 92 deletions(-) diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp index 5b6f2cbf6..ab69bca32 100644 --- a/src/client/qwaylanddisplay.cpp +++ b/src/client/qwaylanddisplay.cpp @@ -100,6 +100,15 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion) return region; } +::wl_subsurface *QWaylandDisplay::createSubSurface(QWaylandWindow *window, QWaylandWindow *parent) +{ + if (!mSubCompositor) { + return NULL; + } + + return mSubCompositor->get_subsurface(window->object(), parent->object()); +} + QWaylandClientBufferIntegration * QWaylandDisplay::clientBufferIntegration() const { return mWaylandIntegration->clientBufferIntegration(); @@ -125,7 +134,7 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) , mLastKeyboardFocusInputDevice(0) , mDndSelectionHandler(0) , mWindowExtension(0) - , mSubSurfaceExtension(0) + , mSubCompositor(0) , mTouchExtension(0) , mQtKeyExtension(0) , mTextInputManager(0) @@ -259,8 +268,8 @@ void QWaylandDisplay::registry_global(uint32_t id, const QString &interface, uin mDndSelectionHandler.reset(new QWaylandDataDeviceManager(this, id)); } else if (interface == QStringLiteral("qt_surface_extension")) { mWindowExtension.reset(new QtWayland::qt_surface_extension(registry, id, 1)); - } else if (interface == QStringLiteral("qt_sub_surface_extension")) { - mSubSurfaceExtension.reset(new QtWayland::qt_sub_surface_extension(registry, id, 1)); + } else if (interface == QStringLiteral("wl_subcompositor")) { + mSubCompositor.reset(new QtWayland::wl_subcompositor(registry, id, 1)); } else if (interface == QStringLiteral("qt_touch_extension")) { mTouchExtension.reset(new QWaylandTouchExtension(this, id)); } else if (interface == QStringLiteral("qt_key_extension")) { diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h index 9a7ad39ce..96d79ddbd 100644 --- a/src/client/qwaylanddisplay_p.h +++ b/src/client/qwaylanddisplay_p.h @@ -100,6 +100,7 @@ public: struct wl_surface *createSurface(void *handle); QWaylandShellSurface *createShellSurface(QWaylandWindow *window); struct ::wl_region *createRegion(const QRegion &qregion); + struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent); QWaylandClientBufferIntegration *clientBufferIntegration() const; @@ -128,7 +129,6 @@ public: QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler.data(); } QtWayland::qt_surface_extension *windowExtension() const { return mWindowExtension.data(); } - QtWayland::qt_sub_surface_extension *subSurfaceExtension() const { return mSubSurfaceExtension.data(); } QWaylandTouchExtension *touchExtension() const { return mTouchExtension.data(); } QtWayland::wl_text_input_manager *textInputManager() const { return mTextInputManager.data(); } QWaylandHardwareIntegration *hardwareIntegration() const { return mHardwareIntegration.data(); } @@ -188,7 +188,7 @@ private: QWaylandInputDevice *mLastKeyboardFocusInputDevice; QScopedPointer mDndSelectionHandler; QScopedPointer mWindowExtension; - QScopedPointer mSubSurfaceExtension; + QScopedPointer mSubCompositor; QScopedPointer mTouchExtension; QScopedPointer mQtKeyExtension; QScopedPointer mWindowManagerIntegration; diff --git a/src/client/qwaylandsubsurface.cpp b/src/client/qwaylandsubsurface.cpp index 81cfef254..ec813609f 100644 --- a/src/client/qwaylandsubsurface.cpp +++ b/src/client/qwaylandsubsurface.cpp @@ -41,45 +41,18 @@ QT_BEGIN_NAMESPACE namespace QtWaylandClient { -QWaylandSubSurface::QWaylandSubSurface(QWaylandWindow *window, struct ::qt_sub_surface *sub_surface) - : QtWayland::qt_sub_surface(sub_surface) +QWaylandSubSurface::QWaylandSubSurface(QWaylandWindow *window, QWaylandWindow *parent, ::wl_subsurface *sub_surface) + : QtWayland::wl_subsurface(sub_surface) , m_window(window) + , m_parent(parent) { + m_parent->mChildren << this; + set_desync(); } -void QWaylandSubSurface::setParent(const QWaylandWindow *parent) +QWaylandSubSurface::~QWaylandSubSurface() { - QWaylandSubSurface *parentSurface = parent ? parent->subSurfaceWindow() : 0; - if (parentSurface) { - int x = m_window->geometry().x() + parent->frameMargins().left(); - int y = m_window->geometry().y() + parent->frameMargins().top(); - parentSurface->attach_sub_surface(object(), x, y); - } -} - -static void setPositionToParent(QWaylandWindow *parentWaylandWindow) -{ - QObjectList children = parentWaylandWindow->window()->children(); - for (int i = 0; i < children.size(); i++) { - QWindow *childWindow = qobject_cast(children.at(i)); - if (!childWindow) - continue; - - if (childWindow->handle()) { - QWaylandWindow *waylandWindow = static_cast(childWindow->handle()); - waylandWindow->subSurfaceWindow()->setParent(parentWaylandWindow); - setPositionToParent(waylandWindow); - } - } -} - -void QWaylandSubSurface::adjustPositionOfChildren() -{ - QWindow *window = m_window->window(); - if (window->parent()) { - qDebug() << "QWaylandSubSurface::adjustPositionOfChildren not called for toplevel window"; - } - setPositionToParent(m_window); + m_parent->mChildren.removeOne(this); } } diff --git a/src/client/qwaylandsubsurface_p.h b/src/client/qwaylandsubsurface_p.h index 232330855..75d8cf6a0 100644 --- a/src/client/qwaylandsubsurface_p.h +++ b/src/client/qwaylandsubsurface_p.h @@ -39,8 +39,7 @@ #include #include - -#include +#include QT_BEGIN_NAMESPACE @@ -48,18 +47,19 @@ namespace QtWaylandClient { class QWaylandDisplay; class QWaylandWindow; -class QWaylandSubSurface; -class Q_WAYLAND_CLIENT_EXPORT QWaylandSubSurface : public QtWayland::qt_sub_surface +class Q_WAYLAND_CLIENT_EXPORT QWaylandSubSurface : public QtWayland::wl_subsurface { public: - QWaylandSubSurface(QWaylandWindow *window, struct ::qt_sub_surface *sub_surface); + QWaylandSubSurface(QWaylandWindow *window, QWaylandWindow *parent, ::wl_subsurface *subsurface); + ~QWaylandSubSurface(); - void setParent(const QWaylandWindow *parent); - void adjustPositionOfChildren(); + QWaylandWindow *window() const { return m_window; } + QWaylandWindow *parent() const { return m_parent; } private: QWaylandWindow *m_window; + QWaylandWindow *m_parent; }; QT_END_NAMESPACE diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index 922b1ee00..a54979a2f 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -86,21 +86,49 @@ QWaylandWindow::QWaylandWindow(QWindow *window) , mMask() , mBackingStore(Q_NULLPTR) { - init(mDisplay->createSurface(static_cast(this))); - static WId id = 1; mWindowId = id++; - if (mDisplay->subSurfaceExtension()) - mSubSurfaceWindow = new QWaylandSubSurface(this, mDisplay->subSurfaceExtension()->get_sub_surface_aware_surface(object())); + initWindow(); +} + +QWaylandWindow::~QWaylandWindow() +{ + delete mWindowDecoration; + + if (isInitialized()) + reset(); - if (!(window->flags() & Qt::BypassWindowManagerHint)) { + QList inputDevices = mDisplay->inputDevices(); + for (int i = 0; i < inputDevices.size(); ++i) + inputDevices.at(i)->handleWindowDestroyed(this); + + const QWindow *parent = window(); + foreach (QWindow *w, QGuiApplication::topLevelWindows()) { + if (w->transientParent() == parent) + QWindowSystemInterface::handleCloseEvent(w); + } + + if (mMouseGrab == this) { + mMouseGrab = 0; + } +} + +void QWaylandWindow::initWindow() +{ + init(mDisplay->createSurface(static_cast(this))); + if (QPlatformWindow::parent()) { + QWaylandWindow *p = static_cast(QPlatformWindow::parent()); + if (::wl_subsurface *ss = mDisplay->createSubSurface(this, p)) { + mSubSurfaceWindow = new QWaylandSubSurface(this, p, ss); + } + } else if (!(window()->flags() & Qt::BypassWindowManagerHint)) { mShellSurface = mDisplay->createShellSurface(this); } if (mShellSurface) { // Set initial surface title - mShellSurface->setTitle(window->title()); + mShellSurface->setTitle(window()->title()); // The appId is the desktop entry identifier that should follow the // reverse DNS convention (see http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html), @@ -122,14 +150,14 @@ QWaylandWindow::QWaylandWindow(QWindow *window) } } - if (QPlatformWindow::parent() && mSubSurfaceWindow) { - mSubSurfaceWindow->setParent(static_cast(QPlatformWindow::parent())); - } else if (window->transientParent() && mShellSurface) { - if (window->type() != Qt::Popup) { - mShellSurface->updateTransientParent(window->transientParent()); + if (mShellSurface) { + if (window()->transientParent()) { + if (window()->type() != Qt::Popup) { + mShellSurface->updateTransientParent(window()->transientParent()); + } + } else { + mShellSurface->setTopLevel(); } - } else if (mShellSurface) { - mShellSurface->setTopLevel(); } // Enable high-dpi rendering. Scale() returns the screen scale factor and will @@ -138,38 +166,25 @@ QWaylandWindow::QWaylandWindow(QWindow *window) if (mDisplay->compositorVersion() >= 3) set_buffer_scale(scale()); - setOrientationMask(window->screen()->orientationUpdateMask()); - setWindowFlags(window->flags()); - setGeometry_helper(window->geometry()); - setMask(window->mask()); - setWindowStateInternal(window->windowState()); - handleContentOrientationChange(window->contentOrientation()); + if (QScreen *s = window()->screen()) + setOrientationMask(s->orientationUpdateMask()); + setWindowFlags(window()->flags()); + setGeometry_helper(window()->geometry()); + setMask(window()->mask()); + setWindowStateInternal(window()->windowState()); + handleContentOrientationChange(window()->contentOrientation()); } -QWaylandWindow::~QWaylandWindow() +void QWaylandWindow::reset() { - delete mWindowDecoration; + delete mShellSurface; + mShellSurface = 0; + delete mSubSurfaceWindow; + mSubSurfaceWindow = 0; + destroy(); - if (isInitialized()) { - delete mShellSurface; - destroy(); - } if (mFrameCallback) wl_callback_destroy(mFrameCallback); - - QList inputDevices = mDisplay->inputDevices(); - for (int i = 0; i < inputDevices.size(); ++i) - inputDevices.at(i)->handleWindowDestroyed(this); - - const QWindow *parent = window(); - foreach (QWindow *w, QGuiApplication::topLevelWindows()) { - if (w->transientParent() == parent) - QWindowSystemInterface::handleCloseEvent(w); - } - - if (mMouseGrab == this) { - mMouseGrab = 0; - } } QWaylandWindow *QWaylandWindow::fromWlSurface(::wl_surface *surface) @@ -184,9 +199,17 @@ WId QWaylandWindow::winId() const void QWaylandWindow::setParent(const QPlatformWindow *parent) { - const QWaylandWindow *parentWaylandWindow = static_cast(parent); - if (subSurfaceWindow()) { - subSurfaceWindow()->setParent(parentWaylandWindow); + QWaylandWindow *oldparent = mSubSurfaceWindow ? mSubSurfaceWindow->parent() : 0; + if (oldparent == parent) + return; + + if (mSubSurfaceWindow && parent) { // new parent, but we were a subsurface already + delete mSubSurfaceWindow; + QWaylandWindow *p = const_cast(static_cast(parent)); + mSubSurfaceWindow = new QWaylandSubSurface(this, p, mDisplay->createSubSurface(this, p)); + } else { // we're changing role, need to make a new wl_surface + reset(); + initWindow(); } } @@ -214,7 +237,10 @@ void QWaylandWindow::setGeometry_helper(const QRect &rect) qBound(window()->minimumWidth(), rect.width(), window()->maximumWidth()), qBound(window()->minimumHeight(), rect.height(), window()->maximumHeight()))); - if (shellSurface() && window()->transientParent() && window()->type() != Qt::Popup) + if (mSubSurfaceWindow) { + QMargins m = QPlatformWindow::parent()->frameMargins(); + mSubSurfaceWindow->set_position(rect.x() + m.left(), rect.y() + m.top()); + } else if (shellSurface() && window()->transientParent() && window()->type() != Qt::Popup) shellSurface()->updateTransientParent(window()->transientParent()); } @@ -546,7 +572,10 @@ bool QWaylandWindow::createDecoration() decoration = false; if (window()->flags() & Qt::BypassWindowManagerHint) decoration = false; + if (mSubSurfaceWindow) + decoration = false; + bool hadDecoration = mWindowDecoration; if (decoration && !decorationPluginFailed) { if (!mWindowDecoration) { QStringList decorations = QWaylandDecorationFactory::keys(); @@ -577,15 +606,20 @@ bool QWaylandWindow::createDecoration() return false; } mWindowDecoration->setWaylandWindow(this); - if (subSurfaceWindow()) { - subSurfaceWindow()->adjustPositionOfChildren(); - } } } else { delete mWindowDecoration; mWindowDecoration = 0; } + if (hadDecoration != (bool)mWindowDecoration) { + foreach (QWaylandSubSurface *subsurf, mChildren) { + QPoint pos = subsurf->window()->geometry().topLeft(); + QMargins m = frameMargins(); + subsurf->set_position(pos.x() + m.left(), pos.y() + m.top()); + } + } + return mWindowDecoration; } diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 1898c4953..6b9af1031 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -190,6 +190,7 @@ protected: QWaylandDisplay *mDisplay; QWaylandShellSurface *mShellSurface; QWaylandSubSurface *mSubSurfaceWindow; + QVector mChildren; QWaylandAbstractDecoration *mWindowDecoration; bool mMouseEventsInContentArea; @@ -223,6 +224,8 @@ protected: private: bool setWindowStateInternal(Qt::WindowState flags); void setGeometry_helper(const QRect &rect); + void initWindow(); + void reset(); void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e); @@ -231,6 +234,8 @@ private: static QMutex mFrameSyncMutex; static QWaylandWindow *mMouseGrab; + + friend class QWaylandSubSurface; }; inline QIcon QWaylandWindow::windowIcon() const -- cgit v1.2.3