Use standard wl_subsurface interface to set a window as a child of another one

Change-Id: I52628f87dbea5383db06468f9748a9bacdec3179
Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
This commit is contained in:
Giulio Camuffo 2015-07-05 17:58:23 +03:00 committed by Simon Hausmann
parent 4d312f1ec7
commit 61b80576b0
6 changed files with 113 additions and 92 deletions

View File

@ -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")) {

View File

@ -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<QWaylandDataDeviceManager> mDndSelectionHandler;
QScopedPointer<QtWayland::qt_surface_extension> mWindowExtension;
QScopedPointer<QtWayland::qt_sub_surface_extension> mSubSurfaceExtension;
QScopedPointer<QtWayland::wl_subcompositor> mSubCompositor;
QScopedPointer<QWaylandTouchExtension> mTouchExtension;
QScopedPointer<QWaylandQtKeyExtension> mQtKeyExtension;
QScopedPointer<QWaylandWindowManagerIntegration> mWindowManagerIntegration;

View File

@ -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<QWindow *>(children.at(i));
if (!childWindow)
continue;
if (childWindow->handle()) {
QWaylandWindow *waylandWindow = static_cast<QWaylandWindow *>(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);
}
}

View File

@ -39,8 +39,7 @@
#include <QtCore/qglobal.h>
#include <QtWaylandClient/private/qwaylandclientexport_p.h>
#include <QtWaylandClient/private/qwayland-sub-surface-extension.h>
#include <QtWaylandClient/private/qwayland-wayland.h>
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

View File

@ -86,21 +86,49 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
, mMask()
, mBackingStore(Q_NULLPTR)
{
init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this)));
static WId id = 1;
mWindowId = id++;
if (mDisplay->subSurfaceExtension())
mSubSurfaceWindow = new QWaylandSubSurface(this, mDisplay->subSurfaceExtension()->get_sub_surface_aware_surface(object()));
initWindow();
}
if (!(window->flags() & Qt::BypassWindowManagerHint)) {
QWaylandWindow::~QWaylandWindow()
{
delete mWindowDecoration;
if (isInitialized())
reset();
QList<QWaylandInputDevice *> 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<QtWayland::wl_surface *>(this)));
if (QPlatformWindow::parent()) {
QWaylandWindow *p = static_cast<QWaylandWindow *>(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<const QWaylandWindow *>(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<QWaylandInputDevice *> 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<const QWaylandWindow *>(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<QWaylandWindow *>(static_cast<const QWaylandWindow *>(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;
}

View File

@ -190,6 +190,7 @@ protected:
QWaylandDisplay *mDisplay;
QWaylandShellSurface *mShellSurface;
QWaylandSubSurface *mSubSurfaceWindow;
QVector<QWaylandSubSurface *> 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