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());
|
||||
}
|
||||
|
||||
QRect AbstractClient::inputGeometry() const
|
||||
{
|
||||
if (isDecorated()) {
|
||||
return Toplevel::inputGeometry() + decoration()->resizeOnlyBorders();
|
||||
}
|
||||
return Toplevel::inputGeometry();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -578,6 +578,8 @@ public:
|
|||
*/
|
||||
virtual void showContextHelp();
|
||||
|
||||
QRect inputGeometry() const override;
|
||||
|
||||
// TODO: remove boolean trap
|
||||
static bool belongToSameApplication(const AbstractClient* c1, const AbstractClient* c2, bool active_hack = false);
|
||||
|
||||
|
|
|
@ -70,6 +70,8 @@ private Q_SLOTS:
|
|||
void testPressToMove();
|
||||
void testTapToMove_data();
|
||||
void testTapToMove();
|
||||
void testResizeOutsideWindow_data();
|
||||
void testResizeOutsideWindow();
|
||||
|
||||
private:
|
||||
AbstractClient *showWindow(Test::ShellSurfaceType type);
|
||||
|
@ -498,6 +500,69 @@ void DecorationInputTest::testTapToMove()
|
|||
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)
|
||||
|
|
|
@ -1451,7 +1451,7 @@ Toplevel *InputRedirection::findToplevel(const QPoint &pos)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (t->geometry().contains(pos) && acceptsInput(t, pos)) {
|
||||
if (t->inputGeometry().contains(pos) && acceptsInput(t, pos)) {
|
||||
return t;
|
||||
}
|
||||
} while (it != stacking.begin());
|
||||
|
|
|
@ -538,5 +538,10 @@ quint32 Toplevel::windowId() const
|
|||
return window();
|
||||
}
|
||||
|
||||
QRect Toplevel::inputGeometry() const
|
||||
{
|
||||
return geometry();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -219,6 +219,13 @@ public:
|
|||
**/
|
||||
virtual quint32 windowId() 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;
|
||||
QPoint pos() const;
|
||||
QRect rect() const;
|
||||
|
|
Loading…
Reference in a new issue