Commit a9d51ab2 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Refactor geometry handling in interactive move/resize handling func

Window::handleInteractiveMoveResize() calls setMoveResizeGeometry(),
which breaks in a way the encapsulation.

This change refactors geometry handling in handleInteractiveMoveResize()
so the next geometry is computed in a temporary variable and the move
resize geometry is updated either using move() or
doInteractiveResizeSync().
parent d6706c5c
Pipeline #225335 failed with stage
in 20 minutes and 24 seconds
......@@ -451,9 +451,9 @@ bool InternalWindow::belongsToSameApplication(const Window *other, SameApplicati
return otherInternal->handle()->isAncestorOf(handle()) || handle()->isAncestorOf(otherInternal->handle());
}
void InternalWindow::doInteractiveResizeSync()
void InternalWindow::doInteractiveResizeSync(const QRectF &rect)
{
requestGeometry(moveResizeGeometry());
moveResize(rect);
}
void InternalWindow::updateCaption()
......
......@@ -69,7 +69,7 @@ public:
protected:
bool acceptsFocus() const override;
bool belongsToSameApplication(const Window *other, SameApplicationChecks checks) const override;
void doInteractiveResizeSync() override;
void doInteractiveResizeSync(const QRectF &rect) override;
void updateCaption() override;
void moveResizeInternal(const QRectF &rect, MoveResizeMode mode) override;
WindowItem *createItem() override;
......
......@@ -1841,70 +1841,69 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
// the bottomleft corner should be at is at (topleft.x(), bottomright().y())
QPointF topleft = globalPos - interactiveMoveOffset();
QPointF bottomright = globalPos + invertedInteractiveMoveOffset();
QRectF previousMoveResizeGeom = moveResizeGeometry();
const QRectF currentMoveResizeGeom = moveResizeGeometry();
QRectF nextMoveResizeGeom = moveResizeGeometry();
// TODO move whole group when moving its leader or when the leader is not mapped?
auto titleBarRect = [this](bool &transposed, int &requiredPixels) -> QRectF {
const QRectF &moveResizeGeom = moveResizeGeometry();
QRectF r(moveResizeGeom);
r.moveTopLeft(QPointF(0, 0));
auto titleBarRect = [this](const QRectF &rect, bool &transposed, int &requiredPixels) -> QRectF {
QRectF titleRect = rect;
titleRect.moveTopLeft(QPointF(0, 0));
switch (titlebarPosition()) {
default:
case Qt::TopEdge:
r.setHeight(borderTop());
titleRect.setHeight(borderTop());
break;
case Qt::LeftEdge:
r.setWidth(borderLeft());
titleRect.setWidth(borderLeft());
transposed = true;
break;
case Qt::BottomEdge:
r.setTop(r.bottom() - borderBottom());
titleRect.setTop(titleRect.bottom() - borderBottom());
break;
case Qt::RightEdge:
r.setLeft(r.right() - borderRight());
titleRect.setLeft(titleRect.right() - borderRight());
transposed = true;
break;
}
// When doing a restricted move we must always keep 100px of the titlebar
// visible to allow the user to be able to move it again.
requiredPixels = qMin(100 * (transposed ? r.width() : r.height()),
moveResizeGeom.width() * moveResizeGeom.height());
return r;
requiredPixels = qMin(100 * (transposed ? titleRect.width() : titleRect.height()),
rect.width() * rect.height());
return titleRect;
};
bool update = false;
if (isInteractiveResize()) {
QRectF orig = initialInteractiveMoveResizeGeometry();
SizeMode sizeMode = SizeModeAny;
auto calculateMoveResizeGeom = [this, &topleft, &bottomright, &orig, &sizeMode, &gravity]() {
auto calculateMoveResizeGeom = [&topleft, &bottomright, &orig, &nextMoveResizeGeom, &sizeMode, &gravity]() {
switch (gravity) {
case Gravity::TopLeft:
setMoveResizeGeometry(QRectF(topleft, orig.bottomRight()));
nextMoveResizeGeom = QRectF(topleft, orig.bottomRight());
break;
case Gravity::BottomRight:
setMoveResizeGeometry(QRectF(orig.topLeft(), bottomright));
nextMoveResizeGeom = QRectF(orig.topLeft(), bottomright);
break;
case Gravity::BottomLeft:
setMoveResizeGeometry(QRectF(QPointF(topleft.x(), orig.y()), QPointF(orig.right(), bottomright.y())));
nextMoveResizeGeom = QRectF(QPointF(topleft.x(), orig.y()), QPointF(orig.right(), bottomright.y()));
break;
case Gravity::TopRight:
setMoveResizeGeometry(QRectF(QPointF(orig.x(), topleft.y()), QPointF(bottomright.x(), orig.bottom())));
nextMoveResizeGeom = QRect(QPoint(orig.x(), topleft.y()), QPoint(bottomright.x(), orig.bottom()));
break;
case Gravity::Top:
setMoveResizeGeometry(QRectF(QPointF(orig.left(), topleft.y()), orig.bottomRight()));
nextMoveResizeGeom = QRectF(QPointF(orig.left(), topleft.y()), orig.bottomRight());
sizeMode = SizeModeFixedH; // try not to affect height
break;
case Gravity::Bottom:
setMoveResizeGeometry(QRectF(orig.topLeft(), QPointF(orig.right(), bottomright.y())));
nextMoveResizeGeom = QRectF(orig.topLeft(), QPointF(orig.right(), bottomright.y()));
sizeMode = SizeModeFixedH;
break;
case Gravity::Left:
setMoveResizeGeometry(QRectF(QPointF(topleft.x(), orig.top()), orig.bottomRight()));
nextMoveResizeGeom = QRectF(QPointF(topleft.x(), orig.top()), orig.bottomRight());
sizeMode = SizeModeFixedW;
break;
case Gravity::Right:
setMoveResizeGeometry(QRectF(orig.topLeft(), QPointF(bottomright.x(), orig.bottom())));
nextMoveResizeGeom = QRectF(orig.topLeft(), QPointF(bottomright.x(), orig.bottom()));
sizeMode = SizeModeFixedW;
break;
case Gravity::None:
......@@ -1916,7 +1915,7 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
// first resize (without checking constrains), then snap, then check bounds, then check constrains
calculateMoveResizeGeom();
// adjust new size to snap to other windows/borders
setMoveResizeGeometry(workspace()->adjustWindowSize(this, moveResizeGeometry(), gravity));
nextMoveResizeGeom = workspace()->adjustWindowSize(this, nextMoveResizeGeom, gravity);
if (!isUnrestrictedInteractiveMoveResize()) {
// Make sure the titlebar isn't behind a restricted area. We don't need to restrict
......@@ -1926,12 +1925,12 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
availableArea -= workspace()->restrictedMoveArea(VirtualDesktopManager::self()->currentDesktop());
bool transposed = false;
int requiredPixels;
QRectF bTitleRect = titleBarRect(transposed, requiredPixels);
QRectF bTitleRect = titleBarRect(nextMoveResizeGeom, transposed, requiredPixels);
int lastVisiblePixels = -1;
QRectF lastTry = moveResizeGeometry();
QRectF lastTry = nextMoveResizeGeom;
bool titleFailed = false;
for (;;) {
const QRect titleRect = bTitleRect.translated(moveResizeGeometry().topLeft()).toRect();
const QRect titleRect = bTitleRect.translated(nextMoveResizeGeom.topLeft()).toRect();
int visiblePixels = 0;
int realVisiblePixels = 0;
for (const QRect &rect : availableArea) {
......@@ -1952,14 +1951,14 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
break; // we won't become better
} else {
if (!titleFailed) {
setMoveResizeGeometry(lastTry);
nextMoveResizeGeom = lastTry;
}
titleFailed = true;
}
}
lastVisiblePixels = realVisiblePixels;
QRectF moveResizeGeom = moveResizeGeometry();
lastTry = moveResizeGeom;
QRectF currentTry = nextMoveResizeGeom;
lastTry = currentTry;
// Not visible enough, move the window to the closest valid point. We bruteforce
// this by slowly moving the window back to its previous position.
......@@ -1967,10 +1966,10 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
// precedence. The opposing edge has no impact on visiblePixels and only one of
// the adjacent can alter at a time, ie. it's enough to ignore adjacent edges
// if the title edge altered
bool leftChanged = previousMoveResizeGeom.left() != moveResizeGeom.left();
bool rightChanged = previousMoveResizeGeom.right() != moveResizeGeom.right();
bool topChanged = previousMoveResizeGeom.top() != moveResizeGeom.top();
bool btmChanged = previousMoveResizeGeom.bottom() != moveResizeGeom.bottom();
bool leftChanged = currentMoveResizeGeom.left() != currentTry.left();
bool rightChanged = currentMoveResizeGeom.right() != currentTry.right();
bool topChanged = currentMoveResizeGeom.top() != currentTry.top();
bool btmChanged = currentMoveResizeGeom.bottom() != currentTry.bottom();
auto fixChangedState = [titleFailed](bool &major, bool &counter, bool &ad1, bool &ad2) {
counter = false;
if (titleFailed) {
......@@ -1996,27 +1995,26 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
break;
}
if (topChanged) {
moveResizeGeom.setTop(moveResizeGeom.y() + sign(previousMoveResizeGeom.y() - moveResizeGeom.y()));
currentTry.setTop(currentTry.y() + sign(currentMoveResizeGeom.y() - currentTry.y()));
} else if (leftChanged) {
moveResizeGeom.setLeft(moveResizeGeom.x() + sign(previousMoveResizeGeom.x() - moveResizeGeom.x()));
currentTry.setLeft(currentTry.x() + sign(currentMoveResizeGeom.x() - currentTry.x()));
} else if (btmChanged) {
moveResizeGeom.setBottom(moveResizeGeom.bottom() + sign(previousMoveResizeGeom.bottom() - moveResizeGeom.bottom()));
currentTry.setBottom(currentTry.bottom() + sign(currentMoveResizeGeom.bottom() - currentTry.bottom()));
} else if (rightChanged) {
moveResizeGeom.setRight(moveResizeGeom.right() + sign(previousMoveResizeGeom.right() - moveResizeGeom.right()));
currentTry.setRight(currentTry.right() + sign(currentMoveResizeGeom.right() - currentTry.right()));
} else {
break; // no position changed - that's certainly not good
}
setMoveResizeGeometry(moveResizeGeom);
nextMoveResizeGeom = currentTry;
}
}
// Always obey size hints, even when in "unrestricted" mode
QSizeF size = constrainFrameSize(moveResizeGeometry().size(), sizeMode);
QSizeF size = constrainFrameSize(nextMoveResizeGeom.size(), sizeMode);
// the new topleft and bottomright corners (after checking size constrains), if they'll be needed
topleft = QPointF(moveResizeGeometry().right() - size.width(), moveResizeGeometry().bottom() - size.height());
bottomright = QPointF(moveResizeGeometry().left() + size.width(), moveResizeGeometry().top() + size.height());
orig = moveResizeGeometry();
topleft = QPointF(nextMoveResizeGeom.right() - size.width(), nextMoveResizeGeom.bottom() - size.height());
bottomright = QPointF(nextMoveResizeGeom.left() + size.width(), nextMoveResizeGeom.top() + size.height());
orig = nextMoveResizeGeom;
// if aspect ratios are specified, both dimensions may change.
// Therefore grow to the right/bottom if needed.
......@@ -2028,45 +2026,40 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
}
calculateMoveResizeGeom();
if (moveResizeGeometry().size() != previousMoveResizeGeom.size()) {
update = true;
}
} else if (isInteractiveMove()) {
Q_ASSERT(gravity == Gravity::None);
if (!isMovable()) { // isMovableAcrossScreens() must have been true to get here
// Special moving of maximized windows on Xinerama screens
Output *output = workspace()->outputAt(globalPos);
if (isFullScreen()) {
setMoveResizeGeometry(workspace()->clientArea(FullScreenArea, this, output));
nextMoveResizeGeom = workspace()->clientArea(FullScreenArea, this, output);
} else {
QRectF moveResizeGeom = workspace()->clientArea(MaximizeArea, this, output);
QSizeF adjSize = constrainFrameSize(moveResizeGeom.size(), SizeModeMax);
if (adjSize != moveResizeGeom.size()) {
QRectF r(moveResizeGeom);
moveResizeGeom.setSize(adjSize);
moveResizeGeom.moveCenter(r.center());
nextMoveResizeGeom = workspace()->clientArea(MaximizeArea, this, output);
const QSizeF adjSize = constrainFrameSize(nextMoveResizeGeom.size(), SizeModeMax);
if (adjSize != nextMoveResizeGeom.size()) {
QRectF r(nextMoveResizeGeom);
nextMoveResizeGeom.setSize(adjSize);
nextMoveResizeGeom.moveCenter(r.center());
}
setMoveResizeGeometry(moveResizeGeom);
}
} else {
// first move, then snap, then check bounds
QRectF moveResizeGeom = moveResizeGeometry();
moveResizeGeom.moveTopLeft(topleft);
moveResizeGeom.moveTopLeft(workspace()->adjustWindowPosition(this, moveResizeGeom.topLeft(),
isUnrestrictedInteractiveMoveResize()));
setMoveResizeGeometry(moveResizeGeom);
QRectF geometry = nextMoveResizeGeom;
geometry.moveTopLeft(topleft);
geometry.moveTopLeft(workspace()->adjustWindowPosition(this, geometry.topLeft(),
isUnrestrictedInteractiveMoveResize()));
nextMoveResizeGeom = geometry;
if (!isUnrestrictedInteractiveMoveResize()) {
const QRegion strut = workspace()->restrictedMoveArea(VirtualDesktopManager::self()->currentDesktop());
QRegion availableArea(workspace()->clientArea(FullArea, this, workspace()->activeOutput()).toAlignedRect());
QRegion availableArea(workspace()->clientArea(FullArea, this, workspace()->activeOutput()).toRect());
availableArea -= strut; // Strut areas
bool transposed = false;
int requiredPixels;
QRectF bTitleRect = titleBarRect(transposed, requiredPixels);
QRectF bTitleRect = titleBarRect(nextMoveResizeGeom, transposed, requiredPixels);
for (;;) {
QRectF moveResizeGeom = moveResizeGeometry();
const QRectF titleRect(bTitleRect.translated(moveResizeGeom.topLeft()));
QRectF currentTry = nextMoveResizeGeom;
const QRectF titleRect(bTitleRect.translated(currentTry.topLeft()));
int visiblePixels = 0;
for (const QRect &rect : availableArea) {
const QRect r = rect & titleRect.toRect();
......@@ -2091,22 +2084,23 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
if (workspace()->outputs().count() > 1) { // optimization
// TODO: could be useful on partial screen struts (half-width panels etc.)
int newTitleTop = -1;
for (const QRectF &r : strut) {
for (const QRect &region : strut) {
QRectF r = region;
if (r.top() == 0 && r.width() > r.height() && // "top panel"
r.intersects(moveResizeGeom) && moveResizeGeom.top() < r.bottom()) {
r.intersects(currentTry) && currentTry.top() < r.bottom()) {
newTitleTop = r.bottom();
break;
}
}
if (newTitleTop > -1) {
moveResizeGeom.moveTop(newTitleTop); // invalid position, possibly on screen change
setMoveResizeGeometry(moveResizeGeom);
currentTry.moveTop(newTitleTop); // invalid position, possibly on screen change
nextMoveResizeGeom = currentTry;
break;
}
}
int dx = sign(previousMoveResizeGeom.x() - moveResizeGeom.x()),
dy = sign(previousMoveResizeGeom.y() - moveResizeGeom.y());
int dx = sign(currentMoveResizeGeom.x() - currentTry.x()),
dy = sign(currentMoveResizeGeom.y() - currentTry.y());
if (visiblePixels && dx) { // means there's no full width cap -> favor horizontally
dy = 0;
} else if (dy) {
......@@ -2114,33 +2108,28 @@ void Window::handleInteractiveMoveResize(int x, int y, int x_root, int y_root)
}
// Move it back
moveResizeGeom.translate(dx, dy);
setMoveResizeGeometry(moveResizeGeom);
currentTry.translate(dx, dy);
nextMoveResizeGeom = currentTry;
if (moveResizeGeom == previousMoveResizeGeom) {
if (nextMoveResizeGeom == currentMoveResizeGeom) {
break; // Prevent lockup
}
}
}
}
if (moveResizeGeometry().topLeft() != previousMoveResizeGeom.topLeft()) {
update = true;
}
} else {
Q_UNREACHABLE();
}
if (!update) {
return;
}
if (nextMoveResizeGeom != currentMoveResizeGeom) {
if (isInteractiveMove()) {
move(nextMoveResizeGeom.topLeft());
} else {
doInteractiveResizeSync(nextMoveResizeGeom);
}
if (isInteractiveMove()) {
move(moveResizeGeometry().topLeft());
} else {
doInteractiveResizeSync();
Q_EMIT clientStepUserMovedResized(this, nextMoveResizeGeom);
}
Q_EMIT clientStepUserMovedResized(this, moveResizeGeometry());
}
StrutRect Window::strutRect(StrutArea area) const
......@@ -2816,7 +2805,7 @@ bool Window::isWaitingForInteractiveMoveResizeSync() const
return false;
}
void Window::doInteractiveResizeSync()
void Window::doInteractiveResizeSync(const QRectF &)
{
}
......
......@@ -1828,7 +1828,7 @@ protected:
*
* Default implementation does nothing.
*/
virtual void doInteractiveResizeSync();
virtual void doInteractiveResizeSync(const QRectF &rect);
void handleInteractiveMoveResize(int x, int y, int x_root, int y_root);
void handleInteractiveMoveResize(const QPointF &local, const QPointF &global);
void dontInteractiveMoveResize();
......
......@@ -4721,8 +4721,10 @@ bool X11Window::isWaitingForInteractiveMoveResizeSync() const
return m_syncRequest.isPending && m_syncRequest.interactiveResize;
}
void X11Window::doInteractiveResizeSync()
void X11Window::doInteractiveResizeSync(const QRectF &rect)
{
setMoveResizeGeometry(rect);
if (!m_syncRequest.timeout) {
m_syncRequest.timeout = new QTimer(this);
connect(m_syncRequest.timeout, &QTimer::timeout, this, &X11Window::handleSyncTimeout);
......@@ -4750,7 +4752,7 @@ void X11Window::doInteractiveResizeSync()
// this, then we might render partially updated client window. I know, it sucks.
m_frame.setGeometry(moveResizeBufferGeometry);
m_wrapper.setGeometry(QRectF(clientPos(), moveResizeClientGeometry.size()));
m_client.setGeometry(QRectF(QPoint(0, 0), moveResizeClientGeometry.size()));
m_client.setGeometry(QRectF(QPointF(0, 0), moveResizeClientGeometry.size()));
}
void X11Window::handleSyncTimeout()
......
......@@ -349,7 +349,7 @@ protected:
bool belongsToDesktop() const override;
bool doStartInteractiveMoveResize() override;
bool isWaitingForInteractiveMoveResizeSync() const override;
void doInteractiveResizeSync() override;
void doInteractiveResizeSync(const QRectF &rect) override;
QSizeF resizeIncrements() const override;
bool acceptsFocus() const override;
void moveResizeInternal(const QRectF &rect, MoveResizeMode mode) override;
......
......@@ -909,9 +909,9 @@ void XdgToplevelWindow::doMinimize()
workspace()->updateMinimizedOfTransients(this);
}
void XdgToplevelWindow::doInteractiveResizeSync()
void XdgToplevelWindow::doInteractiveResizeSync(const QRectF &rect)
{
moveResizeInternal(moveResizeGeometry(), MoveResizeMode::Resize);
moveResize(rect);
}
void XdgToplevelWindow::doSetActive()
......
......@@ -173,7 +173,7 @@ protected:
void handleRoleCommit() override;
void handleRolePrecommit() override;
void doMinimize() override;
void doInteractiveResizeSync() override;
void doInteractiveResizeSync(const QRectF &rect) override;
void doSetActive() override;
void doSetFullScreen();
void doSetMaximized();
......
Supports Markdown
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