diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2018-10-17 14:07:42 +0200 |
---|---|---|
committer | Johan Helsing <johan.helsing@qt.io> | 2018-11-16 08:49:03 +0000 |
commit | 79b7925098936ebf3a8e6ca3119256fb4f1a52a9 (patch) | |
tree | 8325821ac50530ef09e9f9d224d2dc09cc707fd6 | |
parent | b4509e500e2b538dd61048bf1a1f53255bbb917c (diff) |
Compositor: Fix coordinate system inconsistencies
Several properties were using pixel coordinates and surface coordinates without
converting.
[ChangeLog][Compositor] QWaylandSurface::destinationSize has been added which
returns the size of the surface that will be displayed on the screen in surface
coordinates.
[ChangeLog][Compositor] Fixed a bug where QWaylandSurface::inputRegionContains
would return true for some points outside surfaces with buffer scale > 1.
[ChangeLog][Compositor] Fixed a bug which caused ShellSurfaceItems for surfaces
with buffer scale > 1 to move too much when resizing interactively.
It also gets rid of all calls to QWaylandSurface::size, which confusingly
returns the size of the surface's buffer in pixel coordinates. Most properties
now use destionationSize's surface coordinates consistently. Hopefully,
QWaylandSurface::size can be renamed or removed in Qt 6.
Change-Id: I007256a8df7759cf74fbfd51624fa1f90c083336
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
18 files changed, 136 insertions, 61 deletions
diff --git a/examples/wayland/minimal-cpp/compositor.h b/examples/wayland/minimal-cpp/compositor.h index f06421320..3c0c80e0e 100644 --- a/examples/wayland/minimal-cpp/compositor.h +++ b/examples/wayland/minimal-cpp/compositor.h @@ -71,11 +71,11 @@ public: QOpenGLTexture *getTexture(); int iviId() const { return m_iviId; } - QRect globalGeometry() const { return QRect(globalPosition(), surface()->size()); } + QRect globalGeometry() const { return QRect(globalPosition(), surface()->destinationSize()); } void setGlobalPosition(const QPoint &globalPos) { m_pos = globalPos; m_positionSet = true; } QPoint globalPosition() const { return m_pos; } QPoint mapToLocal(const QPoint &globalPos) const; - QSize size() const { return surface() ? surface()->size() : QSize(); } + QSize size() const { return surface() ? surface()->destinationSize() : QSize(); } void initPosition(const QSize &screenSize, const QSize &surfaceSize); diff --git a/examples/wayland/minimal-cpp/window.cpp b/examples/wayland/minimal-cpp/window.cpp index 673e15fd8..f345bd51f 100644 --- a/examples/wayland/minimal-cpp/window.cpp +++ b/examples/wayland/minimal-cpp/window.cpp @@ -95,7 +95,7 @@ void Window::paintGL() GLuint textureId = texture->textureId(); QWaylandSurface *surface = view->surface(); if (surface && surface->hasContent()) { - QSize s = surface->size(); + QSize s = surface->destinationSize(); view->initPosition(size(), s); QPointF pos = view->globalPosition(); QRectF surfaceGeometry(pos, s); diff --git a/examples/wayland/qwindow-compositor/compositor.cpp b/examples/wayland/qwindow-compositor/compositor.cpp index f25e67d87..199de22e2 100644 --- a/examples/wayland/qwindow-compositor/compositor.cpp +++ b/examples/wayland/qwindow-compositor/compositor.cpp @@ -79,7 +79,7 @@ QOpenGLTexture *View::getTexture() if (newContent) { m_texture = buf.toOpenGLTexture(); if (surface()) { - m_size = surface()->size(); + m_size = surface()->destinationSize(); m_origin = buf.origin() == QWaylandSurface::OriginTopLeft ? QOpenGLTextureBlitter::OriginTopLeft : QOpenGLTextureBlitter::OriginBottomLeft; @@ -96,7 +96,7 @@ QOpenGLTextureBlitter::Origin View::textureOrigin() const QSize View::size() const { - return surface() ? surface()->size() : m_size; + return surface() ? surface()->destinationSize() : m_size; } bool View::isCursor() const diff --git a/examples/wayland/qwindow-compositor/compositor.h b/examples/wayland/qwindow-compositor/compositor.h index 2a395a1ab..8f18dc53d 100644 --- a/examples/wayland/qwindow-compositor/compositor.h +++ b/examples/wayland/qwindow-compositor/compositor.h @@ -82,7 +82,7 @@ public: void setParentView(View *parent) { m_parentView = parent; } View *parentView() const { return m_parentView; } QPointF parentPosition() const { return m_parentView ? (m_parentView->position() + m_parentView->parentPosition()) : QPointF(); } - QSize windowSize() { return m_xdgSurface ? m_xdgSurface->windowGeometry().size() : surface() ? surface()->size() : m_size; } + QSize windowSize() { return m_xdgSurface ? m_xdgSurface->windowGeometry().size() : surface() ? surface()->destinationSize() : m_size; } QPoint offset() const { return m_offset; } qreal animationFactor() const {return m_animationFactor; } diff --git a/examples/wayland/qwindow-compositor/window.cpp b/examples/wayland/qwindow-compositor/window.cpp index 80aeec4c3..b8b8e52ec 100644 --- a/examples/wayland/qwindow-compositor/window.cpp +++ b/examples/wayland/qwindow-compositor/window.cpp @@ -180,7 +180,7 @@ void Window::startResize(int edge, bool anchored) m_grabState = ResizeGrab; m_resizeEdge = edge; m_resizeAnchored = anchored; - m_resizeAnchorPosition = getAnchorPosition(m_mouseView->position(), edge, m_mouseView->surface()->size()); + m_resizeAnchorPosition = getAnchorPosition(m_mouseView->position(), edge, m_mouseView->surface()->destinationSize()); } void Window::startDrag(View *dragIcon) diff --git a/src/compositor/compositor_api/qwaylandpointer.cpp b/src/compositor/compositor_api/qwaylandpointer.cpp index 77e736a58..96263e0c2 100644 --- a/src/compositor/compositor_api/qwaylandpointer.cpp +++ b/src/compositor/compositor_api/qwaylandpointer.cpp @@ -239,7 +239,7 @@ uint QWaylandPointer::sendMouseReleaseEvent(Qt::MouseButton button) /*! * Sets the current mouse focus to \a view and sends a mouse move event to it with the - * local position \a localPos and output space position \a outputSpacePos. + * local position \a localPos in surface coordinates and output space position \a outputSpacePos. */ void QWaylandPointer::sendMouseMoveEvent(QWaylandView *view, const QPointF &localPos, const QPointF &outputSpacePos) { @@ -253,7 +253,7 @@ void QWaylandPointer::sendMouseMoveEvent(QWaylandView *view, const QPointF &loca if (view) { // We adjust if the mouse position is on the edge // to work around Qt's event propagation - QSizeF size(view->surface()->size()); + QSizeF size(view->surface()->destinationSize()); if (d->localPosition.x() == size.width()) d->localPosition.rx() -= 0.01; if (d->localPosition.y() == size.height()) @@ -294,7 +294,7 @@ QWaylandView *QWaylandPointer::mouseFocus() const } /*! - * Returns the current local position of the QWaylandPointer. + * Returns the current local position of the QWaylandPointer in surface coordinates. */ QPointF QWaylandPointer::currentLocalPosition() const { diff --git a/src/compositor/compositor_api/qwaylandquickitem.cpp b/src/compositor/compositor_api/qwaylandquickitem.cpp index 6be5701ff..8e1b84921 100644 --- a/src/compositor/compositor_api/qwaylandquickitem.cpp +++ b/src/compositor/compositor_api/qwaylandquickitem.cpp @@ -886,7 +886,7 @@ void QWaylandQuickItem::handleSurfaceChanged() if (d->oldSurface) { disconnect(d->oldSurface, &QWaylandSurface::hasContentChanged, this, &QWaylandQuickItem::surfaceMappedChanged); disconnect(d->oldSurface, &QWaylandSurface::parentChanged, this, &QWaylandQuickItem::parentChanged); - disconnect(d->oldSurface, &QWaylandSurface::sizeChanged, this, &QWaylandQuickItem::updateSize); + disconnect(d->oldSurface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandQuickItem::updateSize); disconnect(d->oldSurface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandQuickItem::updateSize); disconnect(d->oldSurface, &QWaylandSurface::configure, this, &QWaylandQuickItem::updateBuffer); disconnect(d->oldSurface, &QWaylandSurface::redraw, this, &QQuickItem::update); @@ -903,7 +903,7 @@ void QWaylandQuickItem::handleSurfaceChanged() if (QWaylandSurface *newSurface = d->view->surface()) { connect(newSurface, &QWaylandSurface::hasContentChanged, this, &QWaylandQuickItem::surfaceMappedChanged); connect(newSurface, &QWaylandSurface::parentChanged, this, &QWaylandQuickItem::parentChanged); - connect(newSurface, &QWaylandSurface::sizeChanged, this, &QWaylandQuickItem::updateSize); + connect(newSurface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandQuickItem::updateSize); connect(newSurface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandQuickItem::updateSize); connect(newSurface, &QWaylandSurface::configure, this, &QWaylandQuickItem::updateBuffer); connect(newSurface, &QWaylandSurface::redraw, this, &QQuickItem::update); @@ -992,7 +992,7 @@ void QWaylandQuickItem::updateSize() QSize size(0, 0); if (surface()) - size = surface()->size() * (d->scaleFactor() / surface()->bufferScale()); + size = surface()->destinationSize() * d->scaleFactor(); setImplicitSize(size.width(), size.height()); if (d->sizeFollowsSurface) @@ -1061,11 +1061,11 @@ bool QWaylandQuickItem::inputRegionContains(const QPointF &localPosition) QPointF QWaylandQuickItem::mapToSurface(const QPointF &point) const { Q_D(const QWaylandQuickItem); - if (!surface() || surface()->size().isEmpty()) + if (!surface() || surface()->destinationSize().isEmpty()) return point / d->scaleFactor(); - qreal xScale = width() / surface()->size().width() * surface()->bufferScale(); - qreal yScale = height() / surface()->size().height() * surface()->bufferScale(); + qreal xScale = width() / surface()->destinationSize().width(); + qreal yScale = height() / surface()->destinationSize().height(); return QPointF(point.x() / xScale, point.y() / yScale); } @@ -1077,11 +1077,11 @@ QPointF QWaylandQuickItem::mapToSurface(const QPointF &point) const QPointF QWaylandQuickItem::mapFromSurface(const QPointF &point) const { Q_D(const QWaylandQuickItem); - if (!surface() || surface()->size().isEmpty()) + if (!surface() || surface()->destinationSize().isEmpty()) return point * d->scaleFactor(); - qreal xScale = width() / surface()->size().width() * surface()->bufferScale(); - qreal yScale = height() / surface()->size().height() * surface()->bufferScale(); + qreal xScale = width() / surface()->destinationSize().width(); + qreal yScale = height() / surface()->destinationSize().height(); return QPointF(point.x() * xScale, point.y() * yScale); } diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 13ae28220..79b2a9d4e 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -234,19 +234,21 @@ void QWaylandSurfacePrivate::surface_commit(Resource *) // Needed in order to know whether we want to emit signals later QSize oldBufferSize = bufferSize; + QSize oldDestinationSize = destinationSize; bool oldHasContent = hasContent; int oldBufferScale = bufferScale; // Update all internal state if (pending.buffer.hasBuffer() || pending.newlyAttached) bufferRef = pending.buffer; + bufferScale = pending.bufferScale; bufferSize = bufferRef.size(); - damage = pending.damage.intersected(QRect(QPoint(), bufferSize)); + destinationSize = pending.destinationSize.isEmpty() ? bufferSize / bufferScale : pending.destinationSize; + damage = pending.damage.intersected(QRect(QPoint(), destinationSize)); hasContent = bufferRef.hasContent(); - bufferScale = pending.bufferScale; frameCallbacks << pendingFrameCallbacks; - inputRegion = pending.inputRegion.intersected(QRect(QPoint(), bufferSize)); - opaqueRegion = pending.opaqueRegion.intersected(QRect(QPoint(), bufferSize)); + inputRegion = pending.inputRegion.intersected(QRect(QPoint(), destinationSize)); + opaqueRegion = pending.opaqueRegion.intersected(QRect(QPoint(), destinationSize)); QPoint offsetForNextFrame = pending.offset; // Clear per-commit state @@ -274,6 +276,9 @@ void QWaylandSurfacePrivate::surface_commit(Resource *) if (oldBufferScale != bufferScale) emit q->bufferScaleChanged(); + if (oldDestinationSize != destinationSize) + emit q->destinationSizeChanged(); + if (oldHasContent != hasContent) emit q->hasContentChanged(); @@ -448,15 +453,46 @@ bool QWaylandSurface::hasContent() const } /*! + * \qmlproperty size QtWaylandCompositor::WaylandSurface::destinationSize + * + * This property holds the size of this WaylandSurface in surface coordinates. + * + * If you want the size in pixels, multiply this size with \l bufferScale. + * + * \sa bufferScale + */ + +/*! + * \property QWaylandSurface::destinationSize + * + * This property holds the size of this WaylandSurface in surface coordinates. + * + * If you want the size in pixels, multiply this size with \l bufferScale. + * + * \sa bufferScale + */ +QSize QWaylandSurface::destinationSize() const +{ + Q_D(const QWaylandSurface); + return d->destinationSize; +} + +/*! * \qmlproperty size QtWaylandCompositor::WaylandSurface::size * - * This property holds the WaylandSurface's size in pixels. + * This property holds the size of the current buffer of this WaylandSurface in pixels, + * not in surface coordinates. + * + * For the size in surface coordinates, use \l destinationSize instead. */ /*! * \property QWaylandSurface::size * - * This property holds the QWaylandSurface's size in pixels. + * This property holds the size of the current buffer of this QWaylandSurface in pixels, + * not in surface coordinates. + * + * For the size in surface coordinates, use \l destinationSize instead. */ QSize QWaylandSurface::size() const { diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index c208c16d4..243aebd11 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -81,7 +81,8 @@ class Q_WAYLAND_COMPOSITOR_EXPORT QWaylandSurface : public QWaylandObject Q_OBJECT Q_DECLARE_PRIVATE(QWaylandSurface) Q_PROPERTY(QWaylandClient *client READ client CONSTANT) - Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) + Q_PROPERTY(QSize destinationSize READ destinationSize NOTIFY destinationSizeChanged) + Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) // Qt 6: Remove or replace with destinationSize Q_PROPERTY(int bufferScale READ bufferScale NOTIFY bufferScaleChanged) Q_PROPERTY(Qt::ScreenOrientation contentOrientation READ contentOrientation NOTIFY contentOrientationChanged) Q_PROPERTY(QWaylandSurface::Origin origin READ origin NOTIFY originChanged) @@ -110,6 +111,7 @@ public: bool hasContent() const; + QSize destinationSize() const; QSize size() const; int bufferScale() const; @@ -155,6 +157,7 @@ Q_SIGNALS: void damaged(const QRegion &rect); void parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent); void childAdded(QWaylandSurface *child); + void destinationSizeChanged(); void sizeChanged(); void bufferScaleChanged(); void offsetForNextFrame(const QPoint &offset); diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index df868de63..b34367801 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -152,6 +152,7 @@ public: //member variables bool newlyAttached; QRegion inputRegion; int bufferScale; + QSize destinationSize; QRegion opaqueRegion; } pending; @@ -166,6 +167,7 @@ public: //member variables QRegion inputRegion; QRegion opaqueRegion; + QSize destinationSize; QSize bufferSize; int bufferScale = 1; bool isCursorSurface = false; diff --git a/src/compositor/extensions/qwaylandwlshellintegration.cpp b/src/compositor/extensions/qwaylandwlshellintegration.cpp index a2b6b1224..99a2e7655 100644 --- a/src/compositor/extensions/qwaylandwlshellintegration.cpp +++ b/src/compositor/extensions/qwaylandwlshellintegration.cpp @@ -84,8 +84,7 @@ void WlShellIntegration::handleStartResize(QWaylandSeat *seat, QWaylandWlShellSu grabberState = GrabberState::Resize; resizeState.seat = seat; resizeState.resizeEdges = edges; - float scaleFactor = m_item->view()->output()->scaleFactor(); - resizeState.initialSize = m_shellSurface->surface()->size() / scaleFactor; + resizeState.initialSize = m_shellSurface->surface()->destinationSize(); resizeState.initialized = false; } @@ -265,7 +264,7 @@ void WlShellIntegration::handleShellSurfaceDestroyed() void WlShellIntegration::handleSurfaceHasContentChanged() { - if (m_shellSurface && m_shellSurface->surface()->size().isEmpty() + if (m_shellSurface && m_shellSurface->surface()->destinationSize().isEmpty() && m_shellSurface->windowType() == Qt::WindowType::Popup) { handlePopupClosed(); } @@ -285,9 +284,8 @@ void WlShellIntegration::adjustOffsetForNextFrame(const QPointF &offset) if (!m_item->view()->isPrimary()) return; - float scaleFactor = m_item->view()->output()->scaleFactor(); QQuickItem *moveItem = m_item->moveItem(); - moveItem->setPosition(moveItem->position() + offset * scaleFactor / devicePixelRatio()); + moveItem->setPosition(moveItem->position() + m_item->mapFromSurface(offset)); } bool WlShellIntegration::mouseMoveEvent(QMouseEvent *event) diff --git a/src/compositor/extensions/qwaylandxdgshell.cpp b/src/compositor/extensions/qwaylandxdgshell.cpp index bd332287e..d0df8f066 100644 --- a/src/compositor/extensions/qwaylandxdgshell.cpp +++ b/src/compositor/extensions/qwaylandxdgshell.cpp @@ -311,7 +311,7 @@ QRect QWaylandXdgSurfacePrivate::calculateFallbackWindowGeometry() const { // TODO: The unset window geometry should include subsurfaces as well, so this solution // won't work too well on those kinds of clients. - return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale()); + return QRect(QPoint(), m_surface->destinationSize()); } void QWaylandXdgSurfacePrivate::updateFallbackWindowGeometry() @@ -510,7 +510,7 @@ void QWaylandXdgSurface::initialize(QWaylandXdgShell *xdgShell, QWaylandSurface d->init(resource.resource()); setExtensionContainer(surface); d->m_windowGeometry = d->calculateFallbackWindowGeometry(); - connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurface::handleSurfaceSizeChanged); + connect(surface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandXdgSurface::handleSurfaceSizeChanged); connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurface::handleBufferScaleChanged); emit shellChanged(); emit surfaceChanged(); diff --git a/src/compositor/extensions/qwaylandxdgshellintegration.cpp b/src/compositor/extensions/qwaylandxdgshellintegration.cpp index 9ec2810b2..3de52944b 100644 --- a/src/compositor/extensions/qwaylandxdgshellintegration.cpp +++ b/src/compositor/extensions/qwaylandxdgshellintegration.cpp @@ -73,7 +73,7 @@ XdgToplevelIntegration::XdgToplevelIntegration(QWaylandQuickShellSurfaceItem *it connect(m_xdgSurface->shell(), &QWaylandXdgShell::popupCreated, this, [item](QWaylandXdgPopup *popup, QWaylandXdgSurface *){ handlePopupCreated(item, popup); }); - connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgToplevelIntegration::handleSurfaceSizeChanged); + connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgToplevelIntegration::handleSurfaceSizeChanged); connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelIntegration::handleToplevelDestroyed); } @@ -130,7 +130,7 @@ void XdgToplevelIntegration::handleStartResize(QWaylandSeat *seat, Qt::Edges edg resizeState.resizeEdges = edges; resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size(); resizeState.initialPosition = m_item->moveItem()->position(); - resizeState.initialSurfaceSize = m_item->surface()->size(); + resizeState.initialSurfaceSize = m_item->surface()->destinationSize(); resizeState.initialized = false; } @@ -247,14 +247,14 @@ void XdgToplevelIntegration::handleActivatedChanged() void XdgToplevelIntegration::handleSurfaceSizeChanged() { if (grabberState == GrabberState::Resize) { - qreal x = resizeState.initialPosition.x(); - qreal y = resizeState.initialPosition.y(); + qreal dx = 0; + qreal dy = 0; if (resizeState.resizeEdges & Qt::TopEdge) - y += resizeState.initialSurfaceSize.height() - m_item->surface()->size().height(); - + dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height(); if (resizeState.resizeEdges & Qt::LeftEdge) - x += resizeState.initialSurfaceSize.width() - m_item->surface()->size().width(); - m_item->moveItem()->setPosition(QPointF(x, y)); + dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width(); + QPointF offset = m_item->mapFromSurface({dx, dy}); + m_item->moveItem()->setPosition(resizeState.initialPosition + offset); } } diff --git a/src/compositor/extensions/qwaylandxdgshellv5.cpp b/src/compositor/extensions/qwaylandxdgshellv5.cpp index a6e88aabb..2e3b76dc7 100644 --- a/src/compositor/extensions/qwaylandxdgshellv5.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv5.cpp @@ -249,7 +249,7 @@ QRect QWaylandXdgSurfaceV5Private::calculateFallbackWindowGeometry() const { // TODO: The unset window geometry should include subsurfaces as well, so this solution // won't work too well on those kinds of clients. - return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale()); + return QRect(QPoint(), m_surface->destinationSize()); } void QWaylandXdgSurfaceV5Private::updateFallbackWindowGeometry() @@ -837,7 +837,7 @@ void QWaylandXdgSurfaceV5::initialize(QWaylandXdgShellV5 *xdgShell, QWaylandSurf d->init(resource.resource()); setExtensionContainer(surface); d->m_windowGeometry = d->calculateFallbackWindowGeometry(); - connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurfaceV5::handleSurfaceSizeChanged); + connect(surface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandXdgSurfaceV5::handleSurfaceSizeChanged); connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurfaceV5::handleBufferScaleChanged); emit shellChanged(); emit surfaceChanged(); diff --git a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp index d21aa4428..1d63632a3 100644 --- a/src/compositor/extensions/qwaylandxdgshellv5integration.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv5integration.cpp @@ -71,7 +71,7 @@ XdgShellV5Integration::XdgShellV5Integration(QWaylandQuickShellSurfaceItem *item connect(m_xdgSurface, &QWaylandXdgSurfaceV5::unsetMaximized, this, &XdgShellV5Integration::handleUnsetMaximized); connect(m_xdgSurface, &QWaylandXdgSurfaceV5::maximizedChanged, this, &XdgShellV5Integration::handleMaximizedChanged); connect(m_xdgSurface, &QWaylandXdgSurfaceV5::activatedChanged, this, &XdgShellV5Integration::handleActivatedChanged); - connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgShellV5Integration::handleSurfaceSizeChanged); + connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgShellV5Integration::handleSurfaceSizeChanged); connect(m_xdgSurface->shell(), &QWaylandXdgShellV5::xdgPopupCreated, this, [item](QWaylandXdgPopupV5 *popup){ handlePopupCreated(item, popup); }); @@ -139,7 +139,7 @@ void XdgShellV5Integration::handleStartResize(QWaylandSeat *seat, QWaylandXdgSur resizeState.resizeEdges = edges; resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size(); resizeState.initialPosition = m_item->moveItem()->position(); - resizeState.initialSurfaceSize = m_item->surface()->size(); + resizeState.initialSurfaceSize = m_item->surface()->destinationSize(); resizeState.initialized = false; } @@ -194,14 +194,14 @@ void XdgShellV5Integration::handleActivatedChanged() void XdgShellV5Integration::handleSurfaceSizeChanged() { if (grabberState == GrabberState::Resize) { - qreal x = resizeState.initialPosition.x(); - qreal y = resizeState.initialPosition.y(); + qreal dx = 0; + qreal dy = 0; if (resizeState.resizeEdges & QWaylandXdgSurfaceV5::ResizeEdge::TopEdge) - y += resizeState.initialSurfaceSize.height() - m_item->surface()->size().height(); - + dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height(); if (resizeState.resizeEdges & QWaylandXdgSurfaceV5::ResizeEdge::LeftEdge) - x += resizeState.initialSurfaceSize.width() - m_item->surface()->size().width(); - m_item->moveItem()->setPosition(QPointF(x, y)); + dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width(); + QPointF offset = m_item->mapFromSurface({dx, dy}); + m_item->moveItem()->setPosition(resizeState.initialPosition + offset); } } diff --git a/src/compositor/extensions/qwaylandxdgshellv6.cpp b/src/compositor/extensions/qwaylandxdgshellv6.cpp index 8338fe6e2..e6741bfbc 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv6.cpp @@ -316,7 +316,7 @@ QRect QWaylandXdgSurfaceV6Private::calculateFallbackWindowGeometry() const { // TODO: The unset window geometry should include subsurfaces as well, so this solution // won't work too well on those kinds of clients. - return QRect(QPoint(0, 0), m_surface->size() / m_surface->bufferScale()); + return QRect(QPoint(), m_surface->destinationSize()); } void QWaylandXdgSurfaceV6Private::updateFallbackWindowGeometry() @@ -515,7 +515,7 @@ void QWaylandXdgSurfaceV6::initialize(QWaylandXdgShellV6 *xdgShell, QWaylandSurf d->init(resource.resource()); setExtensionContainer(surface); d->m_windowGeometry = d->calculateFallbackWindowGeometry(); - connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandXdgSurfaceV6::handleSurfaceSizeChanged); + connect(surface, &QWaylandSurface::destinationSizeChanged, this, &QWaylandXdgSurfaceV6::handleSurfaceSizeChanged); connect(surface, &QWaylandSurface::bufferScaleChanged, this, &QWaylandXdgSurfaceV6::handleBufferScaleChanged); emit shellChanged(); emit surfaceChanged(); diff --git a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp index 0dd8df6f8..66dbc6841 100644 --- a/src/compositor/extensions/qwaylandxdgshellv6integration.cpp +++ b/src/compositor/extensions/qwaylandxdgshellv6integration.cpp @@ -73,7 +73,7 @@ XdgToplevelV6Integration::XdgToplevelV6Integration(QWaylandQuickShellSurfaceItem connect(m_xdgSurface->shell(), &QWaylandXdgShellV6::popupCreated, this, [item](QWaylandXdgPopupV6 *popup, QWaylandXdgSurfaceV6 *){ handlePopupCreated(item, popup); }); - connect(m_xdgSurface->surface(), &QWaylandSurface::sizeChanged, this, &XdgToplevelV6Integration::handleSurfaceSizeChanged); + connect(m_xdgSurface->surface(), &QWaylandSurface::destinationSizeChanged, this, &XdgToplevelV6Integration::handleSurfaceSizeChanged); connect(m_toplevel, &QObject::destroyed, this, &XdgToplevelV6Integration::handleToplevelDestroyed); } @@ -130,7 +130,7 @@ void XdgToplevelV6Integration::handleStartResize(QWaylandSeat *seat, Qt::Edges e resizeState.resizeEdges = edges; resizeState.initialWindowSize = m_xdgSurface->windowGeometry().size(); resizeState.initialPosition = m_item->moveItem()->position(); - resizeState.initialSurfaceSize = m_item->surface()->size(); + resizeState.initialSurfaceSize = m_item->surface()->destinationSize(); resizeState.initialized = false; } @@ -247,14 +247,14 @@ void XdgToplevelV6Integration::handleActivatedChanged() void XdgToplevelV6Integration::handleSurfaceSizeChanged() { if (grabberState == GrabberState::Resize) { - qreal x = resizeState.initialPosition.x(); - qreal y = resizeState.initialPosition.y(); + qreal dx = 0; + qreal dy = 0; if (resizeState.resizeEdges & Qt::TopEdge) - y += resizeState.initialSurfaceSize.height() - m_item->surface()->size().height(); - + dy = resizeState.initialSurfaceSize.height() - m_item->surface()->destinationSize().height(); if (resizeState.resizeEdges & Qt::LeftEdge) - x += resizeState.initialSurfaceSize.width() - m_item->surface()->size().width(); - m_item->moveItem()->setPosition(QPointF(x, y)); + dx = resizeState.initialSurfaceSize.width() - m_item->surface()->destinationSize().width(); + QPointF offset = m_item->mapFromSurface({dx, dy}); + m_item->moveItem()->setPosition(resizeState.initialPosition + offset); } } diff --git a/tests/auto/compositor/compositor/tst_compositor.cpp b/tests/auto/compositor/compositor/tst_compositor.cpp index 2c0e46b23..78e01af7e 100644 --- a/tests/auto/compositor/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/compositor/tst_compositor.cpp @@ -68,6 +68,7 @@ private slots: void seatKeyboardFocus(); void seatMouseFocus(); void inputRegion(); + void defaultInputRegionHiDpi(); void singleClient(); void multipleClients(); void geometry(); @@ -411,6 +412,7 @@ void tst_WaylandCompositor::mapSurface() QSignalSpy hasContentSpy(waylandSurface, SIGNAL(hasContentChanged())); QCOMPARE(waylandSurface->size(), QSize()); + QCOMPARE(waylandSurface->destinationSize(), QSize()); QCOMPARE(waylandSurface->hasContent(), false); QSize size(256, 256); @@ -425,6 +427,7 @@ void tst_WaylandCompositor::mapSurface() QTRY_COMPARE(hasContentSpy.count(), 1); QCOMPARE(waylandSurface->hasContent(), true); QCOMPARE(waylandSurface->size(), size); + QCOMPARE(waylandSurface->destinationSize(), size); wl_surface_destroy(surface); } @@ -455,6 +458,7 @@ void tst_WaylandCompositor::mapSurfaceHiDpi() auto verifyComittedState = [=]() { QCOMPARE(waylandSurface->size(), bufferSize); + QCOMPARE(waylandSurface->destinationSize(), surfaceSize); QCOMPARE(waylandSurface->bufferScale(), bufferScale); QCOMPARE(waylandSurface->hasContent(), true); }; @@ -473,6 +477,9 @@ void tst_WaylandCompositor::mapSurfaceHiDpi() QObject::connect(waylandSurface, &QWaylandSurface::sizeChanged, verifyComittedState); QSignalSpy sizeSpy(waylandSurface, SIGNAL(sizeChanged())); + QObject::connect(waylandSurface, &QWaylandSurface::destinationSizeChanged, verifyComittedState); + QSignalSpy destinationSizeSpy(waylandSurface, SIGNAL(destinationSizeChanged())); + QObject::connect(waylandSurface, &QWaylandSurface::bufferScaleChanged, verifyComittedState); QSignalSpy bufferScaleSpy(waylandSurface, SIGNAL(bufferScaleChanged())); @@ -484,6 +491,7 @@ void tst_WaylandCompositor::mapSurfaceHiDpi() // No state should be applied before the commit QCOMPARE(waylandSurface->size(), QSize()); + QCOMPARE(waylandSurface->destinationSize(), QSize()); QCOMPARE(waylandSurface->hasContent(), false); QCOMPARE(waylandSurface->bufferScale(), 1); QCOMPARE(offsetSpy.count(), 0); @@ -492,6 +500,7 @@ void tst_WaylandCompositor::mapSurfaceHiDpi() QTRY_COMPARE(hasContentSpy.count(), 1); QTRY_COMPARE(sizeSpy.count(), 1); + QTRY_COMPARE(destinationSizeSpy.count(), 1); QTRY_COMPARE(bufferScaleSpy.count(), 1); QTRY_COMPARE(offsetSpy.count(), 1); @@ -776,6 +785,33 @@ void tst_WaylandCompositor::inputRegion() QVERIFY(!waylandSurface->inputRegionContains(QPoint(1, 2))); } +void tst_WaylandCompositor::defaultInputRegionHiDpi() +{ + TestCompositor compositor(true); + compositor.create(); + + MockClient client; + wl_surface *surface = client.createSurface(); + + int bufferScale = 2; + QSize surfaceSize(16, 16); + QSize bufferSize = surfaceSize * bufferScale; + ShmBuffer buffer(bufferSize, client.shm); + wl_surface_attach(surface, buffer.handle, 0, 0); + wl_surface_damage(surface, 0, 0, surfaceSize.width(), surfaceSize.height()); + wl_surface_set_buffer_scale(surface, bufferScale); + wl_surface_commit(surface); + + QTRY_COMPARE(compositor.surfaces.size(), 1); + QWaylandSurface *waylandSurface = compositor.surfaces.at(0); + + QCOMPARE(waylandSurface->bufferScale(), bufferScale); + QVERIFY(waylandSurface->inputRegionContains(QPoint(0, 0))); + QVERIFY(waylandSurface->inputRegionContains(QPoint(15, 15))); + QVERIFY(!waylandSurface->inputRegionContains(QPoint(-1, -1))); + QVERIFY(!waylandSurface->inputRegionContains(QPoint(16, 16))); +} + class XdgTestCompositor: public TestCompositor { Q_OBJECT public: |