Add support for resize only borders on Wayland
Summary: This change adds support for resizing outside the window decoration (e.g. setting borders to NoSide or None). To support this a new Toplevel::inputGeometry() -> QRect method is added which exposes the geometry adjusted by the margins provided by the decoration. This is checked in InputRedirection when finding a Toplevel at a given position. The logic for figuring out whether the event should go to the decoration or the window already handled the situation correctly, so no further changes are needed. BUG: 364607 FIXED-IN: 5.8.1 Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2787
This commit is contained in:
parent
fd6e4bb023
commit
fb59b05488
6 changed files with 88 additions and 1 deletions
|
@ -1627,4 +1627,12 @@ QRect AbstractClient::iconGeometry() const
|
||||||
return candidateGeom.translated(candidatePanel->pos());
|
return candidateGeom.translated(candidatePanel->pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRect AbstractClient::inputGeometry() const
|
||||||
|
{
|
||||||
|
if (isDecorated()) {
|
||||||
|
return Toplevel::inputGeometry() + decoration()->resizeOnlyBorders();
|
||||||
|
}
|
||||||
|
return Toplevel::inputGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -578,6 +578,8 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void showContextHelp();
|
virtual void showContextHelp();
|
||||||
|
|
||||||
|
QRect inputGeometry() const override;
|
||||||
|
|
||||||
// TODO: remove boolean trap
|
// TODO: remove boolean trap
|
||||||
static bool belongToSameApplication(const AbstractClient* c1, const AbstractClient* c2, bool active_hack = false);
|
static bool belongToSameApplication(const AbstractClient* c1, const AbstractClient* c2, bool active_hack = false);
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,8 @@ private Q_SLOTS:
|
||||||
void testPressToMove();
|
void testPressToMove();
|
||||||
void testTapToMove_data();
|
void testTapToMove_data();
|
||||||
void testTapToMove();
|
void testTapToMove();
|
||||||
|
void testResizeOutsideWindow_data();
|
||||||
|
void testResizeOutsideWindow();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractClient *showWindow(Test::ShellSurfaceType type);
|
AbstractClient *showWindow(Test::ShellSurfaceType type);
|
||||||
|
@ -498,6 +500,69 @@ void DecorationInputTest::testTapToMove()
|
||||||
QCOMPARE(c->pos(), oldPos + offset2 + offset3);
|
QCOMPARE(c->pos(), oldPos + offset2 + offset3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DecorationInputTest::testResizeOutsideWindow_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<Test::ShellSurfaceType>("type");
|
||||||
|
QTest::addColumn<Qt::Edge>("edge");
|
||||||
|
QTest::addColumn<Qt::CursorShape>("expectedCursor");
|
||||||
|
|
||||||
|
QTest::newRow("wlShell - left") << Test::ShellSurfaceType::WlShell << Qt::LeftEdge << Qt::SizeHorCursor;
|
||||||
|
QTest::newRow("xdgShellV5 - left") << Test::ShellSurfaceType::XdgShellV5 << Qt::LeftEdge << Qt::SizeHorCursor;
|
||||||
|
QTest::newRow("wlShell - right") << Test::ShellSurfaceType::WlShell << Qt::RightEdge << Qt::SizeHorCursor;
|
||||||
|
QTest::newRow("xdgShellV5 - right") << Test::ShellSurfaceType::XdgShellV5 << Qt::RightEdge << Qt::SizeHorCursor;
|
||||||
|
QTest::newRow("wlShell - bottom") << Test::ShellSurfaceType::WlShell << Qt::BottomEdge << Qt::SizeVerCursor;
|
||||||
|
QTest::newRow("xdgShellV5 - bottom") << Test::ShellSurfaceType::XdgShellV5 << Qt::BottomEdge << Qt::SizeVerCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecorationInputTest::testResizeOutsideWindow()
|
||||||
|
{
|
||||||
|
// this test verifies that one can resize the window outside the decoration with NoSideBorder
|
||||||
|
|
||||||
|
// first adjust config
|
||||||
|
kwinApp()->config()->group("org.kde.kdecoration2").writeEntry("BorderSize", QStringLiteral("None"));
|
||||||
|
kwinApp()->config()->sync();
|
||||||
|
workspace()->slotReconfigure();
|
||||||
|
|
||||||
|
// now create window
|
||||||
|
QFETCH(Test::ShellSurfaceType, type);
|
||||||
|
AbstractClient *c = showWindow(type);
|
||||||
|
QVERIFY(c);
|
||||||
|
QVERIFY(c->isDecorated());
|
||||||
|
QVERIFY(!c->noBorder());
|
||||||
|
c->move(screens()->geometry(0).center() - QPoint(c->width()/2, c->height()/2));
|
||||||
|
QVERIFY(c->geometry() != c->inputGeometry());
|
||||||
|
QVERIFY(c->inputGeometry().contains(c->geometry()));
|
||||||
|
QSignalSpy startMoveResizedSpy(c, &AbstractClient::clientStartUserMovedResized);
|
||||||
|
QVERIFY(startMoveResizedSpy.isValid());
|
||||||
|
|
||||||
|
// go to border
|
||||||
|
quint32 timestamp = 1;
|
||||||
|
QFETCH(Qt::Edge, edge);
|
||||||
|
switch (edge) {
|
||||||
|
case Qt::LeftEdge:
|
||||||
|
MOTION(QPoint(c->geometry().x() -1, c->geometry().center().y()));
|
||||||
|
break;
|
||||||
|
case Qt::RightEdge:
|
||||||
|
MOTION(QPoint(c->geometry().x() + c->geometry().width() +1, c->geometry().center().y()));
|
||||||
|
break;
|
||||||
|
case Qt::BottomEdge:
|
||||||
|
MOTION(QPoint(c->geometry().center().x(), c->geometry().y() + c->geometry().height() + 1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QVERIFY(!c->geometry().contains(KWin::Cursor::pos()));
|
||||||
|
|
||||||
|
// pressing should trigger resize
|
||||||
|
PRESS;
|
||||||
|
QVERIFY(!c->isResize());
|
||||||
|
QVERIFY(startMoveResizedSpy.wait());
|
||||||
|
QVERIFY(c->isResize());
|
||||||
|
|
||||||
|
RELEASE;
|
||||||
|
QVERIFY(!c->isResize());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WAYLANDTEST_MAIN(KWin::DecorationInputTest)
|
WAYLANDTEST_MAIN(KWin::DecorationInputTest)
|
||||||
|
|
|
@ -1451,7 +1451,7 @@ Toplevel *InputRedirection::findToplevel(const QPoint &pos)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t->geometry().contains(pos) && acceptsInput(t, pos)) {
|
if (t->inputGeometry().contains(pos) && acceptsInput(t, pos)) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
} while (it != stacking.begin());
|
} while (it != stacking.begin());
|
||||||
|
|
|
@ -538,5 +538,10 @@ quint32 Toplevel::windowId() const
|
||||||
return window();
|
return window();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRect Toplevel::inputGeometry() const
|
||||||
|
{
|
||||||
|
return geometry();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,13 @@ public:
|
||||||
**/
|
**/
|
||||||
virtual quint32 windowId() const;
|
virtual quint32 windowId() const;
|
||||||
QRect geometry() const;
|
QRect geometry() const;
|
||||||
|
/**
|
||||||
|
* The geometry of the Toplevel which accepts input events. This might be larger
|
||||||
|
* than the actual geometry, e.g. to support resizing outside the window.
|
||||||
|
*
|
||||||
|
* Default implementation returns same as geometry.
|
||||||
|
**/
|
||||||
|
virtual QRect inputGeometry() const;
|
||||||
QSize size() const;
|
QSize size() const;
|
||||||
QPoint pos() const;
|
QPoint pos() const;
|
||||||
QRect rect() const;
|
QRect rect() const;
|
||||||
|
|
Loading…
Reference in a new issue