Do not limit mouse actions to titleBarArea but allow on complete titleBarPosition

Summary:
Mouse actions like wheel and double click were restricted to the titleBar
area. This made the top most pixel non-interactive as it's not part of the
titleBarArea.

This change makes the complete titlebarPosition interactive. That is it
includes for a "normal" (top) setup also the TopLeft/Top/Right section.
Thus the top most pixel can be double clicked, mouse wheeled, etc.

For the Wayland case the test case is adjusted.

BUG: 362860
FIXED-IN: 5.7.0

Reviewers: #plasma

Subscribers: plasma-devel

Projects: #plasma

Differential Revision: https://phabricator.kde.org/D1596
This commit is contained in:
Martin Gräßlin 2016-05-12 10:28:40 +02:00
parent 8d7d51e4ef
commit 14d12c0585
5 changed files with 85 additions and 5 deletions

View file

@ -460,6 +460,31 @@ AbstractClient::Position AbstractClient::titlebarPosition() const
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 @@ bool AbstractClient::processDecorationButtonPress(QMouseEvent *event, bool ignor
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 @@ bool AbstractClient::processDecorationButtonPress(QMouseEvent *event, bool ignor
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
}
}

View file

@ -425,6 +425,7 @@ public:
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);

View file

@ -21,12 +21,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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 <kwineffects.h>
#include "decorations/decoratedclient.h"
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/compositor.h>
@ -43,6 +45,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <linux/input.h>
Q_DECLARE_METATYPE(Qt::WindowFrameSection)
namespace KWin
{
@ -55,7 +59,9 @@ private Q_SLOTS:
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::cleanup()
}
}
void DecorationInputTest::testAxis_data()
{
QTest::addColumn<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("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 @@ void DecorationInputTest::testAxis()
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 @@ void DecorationInputTest::testAxis()
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<QPoint>("decoPoint");
QTest::addColumn<Qt::WindowFrameSection>("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 @@ void KWin::DecorationInputTest::testDoubleClick()
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()

View file

@ -1172,7 +1172,7 @@ bool Client::buttonPressEvent(xcb_window_t w, int button, int state, int x, int
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 @@ bool Client::buttonReleaseEvent(xcb_window_t w, int button, int state, int x, in
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
}
}

View file

@ -485,7 +485,7 @@ public:
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());
}