diff --git a/abstract_client.h b/abstract_client.h --- a/abstract_client.h +++ b/abstract_client.h @@ -425,6 +425,7 @@ PositionBottomRight = PositionRight | PositionBottom }; Position titlebarPosition() const; + bool titlebarPositionUnderMouse() const; // a helper for the workspace window packing. tests for screen validity and updates since in maximization case as with normal moving void packTo(int left, int top); diff --git a/abstract_client.cpp b/abstract_client.cpp --- a/abstract_client.cpp +++ b/abstract_client.cpp @@ -460,6 +460,31 @@ return PositionTop; } +bool AbstractClient::titlebarPositionUnderMouse() const +{ + if (!isDecorated()) { + return false; + } + const auto sectionUnderMouse = decoration()->sectionUnderMouse(); + if (sectionUnderMouse == Qt::TitleBarArea) { + return true; + } + // check other sections based on titlebarPosition + switch (titlebarPosition()) { + case AbstractClient::PositionTop: + return (sectionUnderMouse == Qt::TopLeftSection || sectionUnderMouse == Qt::TopSection || sectionUnderMouse == Qt::TopRightSection); + case AbstractClient::PositionLeft: + return (sectionUnderMouse == Qt::TopLeftSection || sectionUnderMouse == Qt::LeftSection || sectionUnderMouse == Qt::BottomLeftSection); + case AbstractClient::PositionRight: + return (sectionUnderMouse == Qt::BottomRightSection || sectionUnderMouse == Qt::RightSection || sectionUnderMouse == Qt::TopRightSection); + case AbstractClient::PositionBottom: + return (sectionUnderMouse == Qt::BottomLeftSection || sectionUnderMouse == Qt::BottomSection || sectionUnderMouse == Qt::BottomRightSection); + default: + // nothing + return false; + } +} + void AbstractClient::setMinimized(bool set) { set ? minimize() : unminimize(); @@ -1426,7 +1451,7 @@ active = true; // check whether it is a double click - if (event->button() == Qt::LeftButton && decoration()->titleBar().contains(event->x(), event->y())) { + if (event->button() == Qt::LeftButton && titlebarPositionUnderMouse()) { if (m_decoration.doubleClickTimer.isValid()) { const quint64 interval = m_decoration.doubleClickTimer.elapsed(); m_decoration.doubleClickTimer.invalidate(); @@ -1479,7 +1504,7 @@ void AbstractClient::processDecorationButtonRelease(QMouseEvent *event) { if (isDecorated()) { - if (event->isAccepted() || !decoration()->titleBar().contains(event->pos())) { + if (event->isAccepted() || !titlebarPositionUnderMouse()) { invalidateDecorationDoubleClickTimer(); // click was for the deco and shall not init a doubleclick } } diff --git a/autotests/wayland/decoration_input_test.cpp b/autotests/wayland/decoration_input_test.cpp --- a/autotests/wayland/decoration_input_test.cpp +++ b/autotests/wayland/decoration_input_test.cpp @@ -21,12 +21,14 @@ #include "platform.h" #include "abstract_client.h" #include "cursor.h" +#include "pointer_input.h" #include "screenedge.h" #include "screens.h" #include "wayland_server.h" #include "workspace.h" #include "shell_client.h" #include +#include "decorations/decoratedclient.h" #include #include @@ -43,6 +45,8 @@ #include +Q_DECLARE_METATYPE(Qt::WindowFrameSection) + namespace KWin { @@ -55,7 +59,9 @@ void initTestCase(); void init(); void cleanup(); + void testAxis_data(); void testAxis(); + void testDoubleClick_data(); void testDoubleClick(); void testHover(); void testPressToMove_data(); @@ -239,6 +245,16 @@ } } +void DecorationInputTest::testAxis_data() +{ + QTest::addColumn("decoPoint"); + QTest::addColumn("expectedSection"); + + QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection; + QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection; + QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection; +} + void DecorationInputTest::testAxis() { AbstractClient *c = showWindow(); @@ -251,6 +267,8 @@ quint32 timestamp = 1; MOTION(QPoint(c->geometry().center().x(), c->clientPos().y() / 2)); + QVERIFY(!input()->pointer()->decoration().isNull()); + QCOMPARE(input()->pointer()->decoration()->decoration()->sectionUnderMouse(), Qt::TitleBarArea); // TODO: mouse wheel direction looks wrong to me // simulate wheel @@ -263,6 +281,27 @@ kwinApp()->platform()->pointerAxisVertical(-5.0, timestamp++); QVERIFY(!c->keepBelow()); QVERIFY(c->keepAbove()); + + // test top most deco pixel, BUG: 362860 + c->move(0, 0); + QFETCH(QPoint, decoPoint); + MOTION(decoPoint); + QVERIFY(!input()->pointer()->decoration().isNull()); + QCOMPARE(input()->pointer()->decoration()->client(), c); + QTEST(input()->pointer()->decoration()->decoration()->sectionUnderMouse(), "expectedSection"); + kwinApp()->platform()->pointerAxisVertical(5.0, timestamp++); + QVERIFY(!c->keepBelow()); + QVERIFY(!c->keepAbove()); +} + +void DecorationInputTest::testDoubleClick_data() +{ + QTest::addColumn("decoPoint"); + QTest::addColumn("expectedSection"); + + QTest::newRow("topLeft") << QPoint(0, 0) << Qt::TopLeftSection; + QTest::newRow("top") << QPoint(250, 0) << Qt::TopSection; + QTest::newRow("topRight") << QPoint(499, 0) << Qt::TopRightSection; } void KWin::DecorationInputTest::testDoubleClick() @@ -288,6 +327,21 @@ PRESS; RELEASE; QVERIFY(!c->isOnAllDesktops()); + + // test top most deco pixel, BUG: 362860 + c->move(0, 0); + QFETCH(QPoint, decoPoint); + MOTION(decoPoint); + QVERIFY(!input()->pointer()->decoration().isNull()); + QCOMPARE(input()->pointer()->decoration()->client(), c); + QTEST(input()->pointer()->decoration()->decoration()->sectionUnderMouse(), "expectedSection"); + // double click + PRESS; + RELEASE; + QVERIFY(!c->isOnAllDesktops()); + PRESS; + RELEASE; + QVERIFY(c->isOnAllDesktops()); } void DecorationInputTest::testHover() diff --git a/events.cpp b/events.cpp --- a/events.cpp +++ b/events.cpp @@ -1172,7 +1172,7 @@ event.setAccepted(false); QCoreApplication::sendEvent(decoration(), &event); if (!event.isAccepted() && !hor) { - if (decoration()->titleBar().contains(x, y)) { + if (titlebarPositionUnderMouse()) { performMouseCommand(options->operationTitlebarMouseWheel(delta), QPoint(x_root, y_root)); } } @@ -1204,7 +1204,7 @@ x11ToQtKeyboardModifiers(state)); event.setAccepted(false); QCoreApplication::sendEvent(decoration(), &event); - if (event.isAccepted() || !decoration()->titleBar().contains(x, y)) { + if (event.isAccepted() || !titlebarPositionUnderMouse()) { invalidateDecorationDoubleClickTimer(); // click was for the deco and shall not init a doubleclick } } diff --git a/input.cpp b/input.cpp --- a/input.cpp +++ b/input.cpp @@ -485,7 +485,7 @@ if (e.isAccepted()) { return true; } - if (orientation == Qt::Vertical && decoration->decoration()->titleBar().contains(localPos.toPoint())) { + if ((orientation == Qt::Vertical) && decoration->client()->titlebarPositionUnderMouse()) { decoration->client()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1), event->globalPosF().toPoint()); }