[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
This commit is contained in:
David Edmundson 2019-02-22 14:08:47 +00:00
parent 40477aff2d
commit 7014a33992
3 changed files with 20 additions and 14 deletions

View file

@ -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.

View file

@ -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:

View file

@ -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;