Commit a75fb7f8 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii

Refactor geometry constraints code

Summary:
Currently, there are a couple of issues with sizeForClientSize(). First
of all, we have a method called clientSizeToFrameSize() which does similar
thing except applying geometry constraints and checking window rules. The
other issue is that sizeForClientSize() is doing a bit too much, it checks
window rules, it applies a bunch of geometry constrains. Sometimes it
does not perform conversion between client sizes and frame sizes!

This change attempts to address those issues by replacing sizeForClientSize
with two similar methods and changing semantics of some methods of the
X11Client class.

The most significant difference between sizeForClientSize() and the new
methods is that neither constrainClientSize() nor constrainFrameSize()
check window rules. This is up to users of those methods. In many places,
we don't have to check window rules because we check isResizable(),
which returns false if the frame size is enforced by a window rule.

Reviewers: #kwin, davidedmundson

Reviewed By: #kwin, davidedmundson

Subscribers: davidedmundson, romangg, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D26828
parent 5b6e081a
......@@ -1182,7 +1182,7 @@ void AbstractClient::handleMoveResize(int x, int y, int x_root, int y_root)
}
// Always obey size hints, even when in "unrestricted" mode
QSize size = adjustedSize(moveResizeGeometry().size(), sizeMode);
QSize size = constrainFrameSize(moveResizeGeometry().size(), sizeMode);
// the new topleft and bottomright corners (after checking size constrains), if they'll be needed
topleft = QPoint(moveResizeGeometry().right() - size.width() + 1, moveResizeGeometry().bottom() - size.height() + 1);
bottomright = QPoint(moveResizeGeometry().left() + size.width() - 1, moveResizeGeometry().top() + size.height() - 1);
......@@ -1209,7 +1209,7 @@ void AbstractClient::handleMoveResize(int x, int y, int x_root, int y_root)
setMoveResizeGeometry(workspace()->clientArea(FullScreenArea, screen, 0));
else {
QRect moveResizeGeom = workspace()->clientArea(MaximizeArea, screen, 0);
QSize adjSize = adjustedSize(moveResizeGeom.size(), SizeModeMax);
QSize adjSize = constrainFrameSize(moveResizeGeom.size(), SizeModeMax);
if (adjSize != moveResizeGeom.size()) {
QRect r(moveResizeGeom);
moveResizeGeom.setSize(adjSize);
......@@ -1851,13 +1851,6 @@ BORDER(Right)
BORDER(Top)
#undef BORDER
QSize AbstractClient::sizeForClientSize(const QSize &wsize, SizeMode mode, bool noframe) const
{
Q_UNUSED(mode)
Q_UNUSED(noframe)
return wsize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom());
}
void AbstractClient::addRepaintDuringGeometryUpdates()
{
const QRect deco_rect = visibleRect();
......@@ -3075,7 +3068,7 @@ void AbstractClient::checkWorkspacePosition(QRect oldGeometry, int oldDesktop, Q
checkOffscreenPosition(&newGeom, screenArea);
// Obey size hints. TODO: We really should make sure it stays in the right place
if (!isShade())
newGeom.setSize(adjustedSize(newGeom.size()));
newGeom.setSize(constrainFrameSize(newGeom.size()));
if (newGeom != frameGeometry())
setFrameGeometry(newGeom);
......@@ -3095,21 +3088,46 @@ void AbstractClient::checkOffscreenPosition(QRect* geom, const QRect& screenArea
}
}
QSize AbstractClient::adjustedSize(const QSize& frame, SizeMode mode) const
/**
* Returns the appropriate frame size for the current client size.
*
* This is equivalent to clientSizeToFrameSize(constrainClientSize(clientSize())).
*/
QSize AbstractClient::adjustedSize() const
{
return clientSizeToFrameSize(constrainClientSize(clientSize()));
}
/**
* Constrains the client size @p size according to a set of the window's size hints.
*/
QSize AbstractClient::constrainClientSize(const QSize &size, SizeMode mode) const
{
// first, get the window size for the given frame size s
QSize wsize = frameSizeToClientSize(frame);
if (wsize.isEmpty())
wsize = QSize(qMax(wsize.width(), 1), qMax(wsize.height(), 1));
Q_UNUSED(mode)
return sizeForClientSize(wsize, mode, false);
int width = size.width();
int height = size.height();
// When user is resizing the window, the move resize geometry may have negative width or
// height. In which case, we need to set negative dimensions to reasonable values.
if (width < 1) {
width = 1;
}
if (height < 1) {
height = 1;
}
return QSize(width, height);
}
// this helper returns proper size even if the window is shaded
// see also the comment in X11Client::setGeometry()
QSize AbstractClient::adjustedSize() const
/**
* Constrains the frame size @p size according to a set of the window's size hints.
*/
QSize AbstractClient::constrainFrameSize(const QSize &size, SizeMode mode) const
{
return sizeForClientSize(clientSize());
const QSize unconstrainedClientSize = frameSizeToClientSize(size);
const QSize constrainedClientSize = constrainClientSize(unconstrainedClientSize, mode);
return clientSizeToFrameSize(constrainedClientSize);
}
/**
......
......@@ -633,19 +633,9 @@ public:
SizeModeFixedH, ///< Try not to affect height
SizeModeMax ///< Try not to make it larger in either direction
};
/**
* Calculates the appropriate frame size for the given client size @p wsize.
*
* @p wsize is adapted according to the window's size hints (minimum, maximum and incremental size changes).
*
* Default implementation returns the passed in @p wsize.
*/
virtual QSize sizeForClientSize(const QSize &wsize, SizeMode mode = SizeModeAny, bool noframe = false) const;
/**
* Adjust the frame size @p frame according to the window's size hints.
*/
QSize adjustedSize(const QSize&, SizeMode mode = SizeModeAny) const;
virtual QSize constrainClientSize(const QSize &size, SizeMode mode = SizeModeAny) const;
QSize constrainFrameSize(const QSize &size, SizeMode mode = SizeModeAny) const;
QSize adjustedSize() const;
/**
......
......@@ -458,7 +458,7 @@ void TestXdgShellClient::testFullscreen()
QVERIFY(!c->isFullScreen());
QCOMPARE(c->clientSize(), QSize(100, 50));
QCOMPARE(c->isDecorated(), decoMode == ServerSideDecoration::Mode::Server);
QCOMPARE(c->sizeForClientSize(c->clientSize()), c->frameGeometry().size());
QCOMPARE(c->clientSizeToFrameSize(c->clientSize()), c->frameGeometry().size());
QSignalSpy fullscreenChangedSpy(c, &XdgShellClient::fullScreenChanged);
QVERIFY(fullscreenChangedSpy.isValid());
QSignalSpy frameGeometryChangedSpy(c, &XdgShellClient::frameGeometryChanged);
......
......@@ -436,7 +436,7 @@ void InternalClient::present(const QSharedPointer<QOpenGLFramebufferObject> fbo)
const QSize bufferSize = fbo->size() / bufferScale();
commitGeometry(QRect(pos(), sizeForClientSize(bufferSize)));
commitGeometry(QRect(pos(), clientSizeToFrameSize(bufferSize)));
markAsMapped();
if (m_internalFBO != fbo) {
......@@ -455,7 +455,7 @@ void InternalClient::present(const QImage &image, const QRegion &damage)
const QSize bufferSize = image.size() / bufferScale();
commitGeometry(QRect(pos(), sizeForClientSize(bufferSize)));
commitGeometry(QRect(pos(), clientSizeToFrameSize(bufferSize)));
markAsMapped();
if (m_internalImage.size() != image.size()) {
......
......@@ -748,7 +748,7 @@ void AbstractClient::growHorizontal()
return;
QRect geom = frameGeometry();
geom.setRight(workspace()->packPositionRight(this, geom.right(), true));
QSize adjsize = adjustedSize(geom.size(), SizeModeFixedW);
QSize adjsize = constrainFrameSize(geom.size(), SizeModeFixedW);
if (frameGeometry().size() == adjsize && geom.size() != adjsize && resizeIncrements().width() > 1) { // take care of size increments
int newright = workspace()->packPositionRight(this, geom.right() + resizeIncrements().width() - 1, true);
// check that it hasn't grown outside of the area, due to size increments
......@@ -757,8 +757,8 @@ void AbstractClient::growHorizontal()
QPoint((x() + newright) / 2, frameGeometry().center().y()), desktop()).right() >= newright)
geom.setRight(newright);
}
geom.setSize(adjustedSize(geom.size(), SizeModeFixedW));
geom.setSize(adjustedSize(geom.size(), SizeModeFixedH));
geom.setSize(constrainFrameSize(geom.size(), SizeModeFixedW));
geom.setSize(constrainFrameSize(geom.size(), SizeModeFixedH));
workspace()->updateFocusMousePosition(Cursor::pos()); // may cause leave event;
setFrameGeometry(geom);
}
......@@ -777,7 +777,7 @@ void AbstractClient::shrinkHorizontal()
geom.setRight(workspace()->packPositionLeft(this, geom.right(), false));
if (geom.width() <= 1)
return;
geom.setSize(adjustedSize(geom.size(), SizeModeFixedW));
geom.setSize(constrainFrameSize(geom.size(), SizeModeFixedW));
if (geom.width() > 20) {
workspace()->updateFocusMousePosition(Cursor::pos()); // may cause leave event;
setFrameGeometry(geom);
......@@ -796,7 +796,7 @@ void AbstractClient::growVertical()
return;
QRect geom = frameGeometry();
geom.setBottom(workspace()->packPositionDown(this, geom.bottom(), true));
QSize adjsize = adjustedSize(geom.size(), SizeModeFixedH);
QSize adjsize = constrainFrameSize(geom.size(), SizeModeFixedH);
if (frameGeometry().size() == adjsize && geom.size() != adjsize && resizeIncrements().height() > 1) { // take care of size increments
int newbottom = workspace()->packPositionDown(this, geom.bottom() + resizeIncrements().height() - 1, true);
// check that it hasn't grown outside of the area, due to size increments
......@@ -804,7 +804,7 @@ void AbstractClient::growVertical()
QPoint(frameGeometry().center().x(), (y() + newbottom) / 2), desktop()).bottom() >= newbottom)
geom.setBottom(newbottom);
}
geom.setSize(adjustedSize(geom.size(), SizeModeFixedH));
geom.setSize(constrainFrameSize(geom.size(), SizeModeFixedH));
workspace()->updateFocusMousePosition(Cursor::pos()); // may cause leave event;
setFrameGeometry(geom);
}
......@@ -824,7 +824,7 @@ void AbstractClient::shrinkVertical()
geom.setBottom(workspace()->packPositionUp(this, geom.bottom(), false));
if (geom.height() <= 1)
return;
geom.setSize(adjustedSize(geom.size(), SizeModeFixedH));
geom.setSize(constrainFrameSize(geom.size(), SizeModeFixedH));
if (geom.height() > 20) {
workspace()->updateFocusMousePosition(Cursor::pos()); // may cause leave event;
setFrameGeometry(geom);
......
......@@ -905,7 +905,7 @@ void AbstractClient::applyWindowRules()
// Placement - does need explicit update, just like some others below
// Geometry : setGeometry() doesn't check rules
auto client_rules = rules();
QRect orig_geom = QRect(pos(), sizeForClientSize(clientSize())); // handle shading
QRect orig_geom = QRect(pos(), adjustedSize()); // handle shading
QRect geom = client_rules->checkGeometry(orig_geom);
if (geom != orig_geom)
setFrameGeometry(geom);
......
This diff is collapsed.
......@@ -197,7 +197,7 @@ public:
void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) override;
void resizeWithChecks(int w, int h, xcb_gravity_t gravity, ForceGeometry_t force = NormalGeometrySet);
void resizeWithChecks(const QSize& s, xcb_gravity_t gravity, ForceGeometry_t force = NormalGeometrySet);
QSize sizeForClientSize(const QSize&, SizeMode mode = SizeModeAny, bool noframe = false) const override;
QSize constrainClientSize(const QSize &size, SizeMode mode = SizeModeAny) const override;
bool providesContextHelp() const override;
......
......@@ -192,7 +192,7 @@ void XdgShellClient::finishInit()
if (supportsWindowRules()) {
setupWindowRules(false);
const QRect originalGeometry = QRect(pos(), sizeForClientSize(clientSize()));
const QRect originalGeometry = frameGeometry();
const QRect ruledGeometry = rules()->checkGeometry(originalGeometry, true);
if (originalGeometry != ruledGeometry) {
setFrameGeometry(ruledGeometry);
......@@ -942,7 +942,7 @@ void XdgShellClient::setFullScreen(bool set, bool user)
} else {
if (m_geomFsRestore.isValid()) {
int currentScreen = screen();
setFrameGeometry(QRect(m_geomFsRestore.topLeft(), adjustedSize(m_geomFsRestore.size())));
setFrameGeometry(QRect(m_geomFsRestore.topLeft(), constrainFrameSize(m_geomFsRestore.size())));
if( currentScreen != screen())
workspace()->sendClientToScreen( this, currentScreen );
} else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment