From 7014a33992149ef682990c6123516a099233d919 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Fri, 22 Feb 2019 14:08:47 +0000 Subject: [PATCH] [wayland] Handle sizes in ShellClient::transientPlacement Summary: placeIn did not handle the case for a popup not having had the size already set and only being available via m_xdgShellPopup->initialSize(). This is needed if we want to call placeIn at the correct time, before the window is mapped. There was also a logic bug when sliding popups. We called the confusingly named setX thinking it would be move the popup keeping the width the same. In practice it moves the left edge keeping the right position the same. This wasn't an issue as the size was discarded. Handling the resize constraint is not yet done, but it should now be even more trivial. Reviewers: #kwin, zzag Reviewed By: #kwin, zzag Subscribers: zzag, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D18956 --- placement.cpp | 5 +++-- shell_client.cpp | 27 ++++++++++++++++----------- shell_client.h | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/placement.cpp b/placement.cpp index afac83825a..da1368b8da 100644 --- a/placement.cpp +++ b/placement.cpp @@ -500,8 +500,9 @@ void Placement::placeTransient(AbstractClient *c) { const auto parent = c->transientFor(); const QRect screen = Workspace::self()->clientArea(parent->isFullScreen() ? FullScreenArea : PlacementArea, parent); - const QPoint popupPos = c->transientPlacement(screen).topLeft(); - c->move(popupPos); + const QRect popupGeometry = c->transientPlacement(screen); + c->setGeometry(popupGeometry); + // Potentially a client could set no constraint adjustments // and we'll be offscreen. diff --git a/shell_client.cpp b/shell_client.cpp index 825aed2d77..892dced092 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -1453,6 +1453,7 @@ QRect ShellClient::transientPlacement(const QRect &bounds) const Qt::Edges gravity; QPoint offset; PositionerConstraints constraintAdjustments; + QSize size = geometry().size(); const QPoint parentClientPos = transientFor()->pos() + transientFor()->clientPos(); QRect popupPosition; @@ -1486,12 +1487,16 @@ QRect ShellClient::transientPlacement(const QRect &bounds) const gravity = m_xdgShellPopup->gravity(); offset = m_xdgShellPopup->anchorOffset(); constraintAdjustments = m_xdgShellPopup->constraintAdjustments(); + if (!size.isValid()) { + size = m_xdgShellPopup->initialSize(); + } } else { Q_UNREACHABLE(); } + //initial position - popupPosition = QRect(popupOffset(anchorRect, anchorEdge, gravity) + offset + parentClientPos, geometry().size()); + popupPosition = QRect(popupOffset(anchorRect, anchorEdge, gravity, size) + offset + parentClientPos, size); //if that fits, we don't need to do anything if (inBounds(popupPosition)) { @@ -1510,20 +1515,21 @@ QRect ShellClient::transientPlacement(const QRect &bounds) const if (flippedGravity & (Qt::LeftEdge | Qt::RightEdge)) { flippedGravity ^= (Qt::LeftEdge | Qt::RightEdge); } - auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity) + offset + parentClientPos, geometry().size()); + auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity, size) + offset + parentClientPos, size); //if it still doesn't fit we should continue with the unflipped version if (inBounds(flippedPopupPosition, Qt::LeftEdge | Qt::RightEdge)) { - popupPosition.setX(flippedPopupPosition.x()); + popupPosition.moveLeft(flippedPopupPosition.x()); } } } if (constraintAdjustments & PositionerConstraint::SlideX) { if (!inBounds(popupPosition, Qt::LeftEdge)) { - popupPosition.setX(bounds.x()); + popupPosition.moveLeft(bounds.x()); } if (!inBounds(popupPosition, Qt::RightEdge)) { - popupPosition.setX(bounds.x() + bounds.width() - geometry().width()); + // moveRight suffers from the classic QRect off by one issue + popupPosition.moveLeft(bounds.x() + bounds.width() - size.width()); } } if (constraintAdjustments & PositionerConstraint::ResizeX) { @@ -1542,20 +1548,20 @@ QRect ShellClient::transientPlacement(const QRect &bounds) const if (flippedGravity & (Qt::TopEdge | Qt::BottomEdge)) { flippedGravity ^= (Qt::TopEdge | Qt::BottomEdge); } - auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity) + offset + parentClientPos, geometry().size()); + auto flippedPopupPosition = QRect(popupOffset(anchorRect, flippedAnchorEdge, flippedGravity, size) + offset + parentClientPos, size); //if it still doesn't fit we should continue with the unflipped version if (inBounds(flippedPopupPosition, Qt::TopEdge | Qt::BottomEdge)) { - popupPosition.setY(flippedPopupPosition.y()); + popupPosition.moveTop(flippedPopupPosition.y()); } } } if (constraintAdjustments & PositionerConstraint::SlideY) { if (!inBounds(popupPosition, Qt::TopEdge)) { - popupPosition.setY(bounds.y()); + popupPosition.moveTop(bounds.y()); } if (!inBounds(popupPosition, Qt::BottomEdge)) { - popupPosition.setY(bounds.y() + bounds.height() - geometry().height()); + popupPosition.moveTop(bounds.y() + bounds.height() - size.height()); } } if (constraintAdjustments & PositionerConstraint::ResizeY) { @@ -1565,9 +1571,8 @@ QRect ShellClient::transientPlacement(const QRect &bounds) const return popupPosition; } -QPoint ShellClient::popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity) const +QPoint ShellClient::popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize) const { - const QSize popupSize = geometry().size(); QPoint anchorPoint; switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { case Qt::LeftEdge: diff --git a/shell_client.h b/shell_client.h index cfb9201d5b..51d00a75d8 100644 --- a/shell_client.h +++ b/shell_client.h @@ -210,7 +210,7 @@ private: void updateMaximizeMode(MaximizeMode maximizeMode); // called on surface commit and processes all m_pendingConfigureRequests up to m_lastAckedConfigureReqest void updatePendingGeometry(); - QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity) const; + QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize) const; static void deleteClient(ShellClient *c); KWayland::Server::ShellSurfaceInterface *m_shellSurface;