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:
parent
8d7d51e4ef
commit
14d12c0585
5 changed files with 85 additions and 5 deletions
|
@ -460,6 +460,31 @@ AbstractClient::Position AbstractClient::titlebarPosition() const
|
||||||
return PositionTop;
|
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)
|
void AbstractClient::setMinimized(bool set)
|
||||||
{
|
{
|
||||||
set ? minimize() : unminimize();
|
set ? minimize() : unminimize();
|
||||||
|
@ -1426,7 +1451,7 @@ bool AbstractClient::processDecorationButtonPress(QMouseEvent *event, bool ignor
|
||||||
active = true;
|
active = true;
|
||||||
|
|
||||||
// check whether it is a double click
|
// 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()) {
|
if (m_decoration.doubleClickTimer.isValid()) {
|
||||||
const quint64 interval = m_decoration.doubleClickTimer.elapsed();
|
const quint64 interval = m_decoration.doubleClickTimer.elapsed();
|
||||||
m_decoration.doubleClickTimer.invalidate();
|
m_decoration.doubleClickTimer.invalidate();
|
||||||
|
@ -1479,7 +1504,7 @@ bool AbstractClient::processDecorationButtonPress(QMouseEvent *event, bool ignor
|
||||||
void AbstractClient::processDecorationButtonRelease(QMouseEvent *event)
|
void AbstractClient::processDecorationButtonRelease(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (isDecorated()) {
|
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
|
invalidateDecorationDoubleClickTimer(); // click was for the deco and shall not init a doubleclick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,6 +425,7 @@ public:
|
||||||
PositionBottomRight = PositionRight | PositionBottom
|
PositionBottomRight = PositionRight | PositionBottom
|
||||||
};
|
};
|
||||||
Position titlebarPosition() const;
|
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
|
// 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);
|
void packTo(int left, int top);
|
||||||
|
|
|
@ -21,12 +21,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "abstract_client.h"
|
#include "abstract_client.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
|
#include "pointer_input.h"
|
||||||
#include "screenedge.h"
|
#include "screenedge.h"
|
||||||
#include "screens.h"
|
#include "screens.h"
|
||||||
#include "wayland_server.h"
|
#include "wayland_server.h"
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
#include "shell_client.h"
|
#include "shell_client.h"
|
||||||
#include <kwineffects.h>
|
#include <kwineffects.h>
|
||||||
|
#include "decorations/decoratedclient.h"
|
||||||
|
|
||||||
#include <KWayland/Client/connection_thread.h>
|
#include <KWayland/Client/connection_thread.h>
|
||||||
#include <KWayland/Client/compositor.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>
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(Qt::WindowFrameSection)
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -55,7 +59,9 @@ private Q_SLOTS:
|
||||||
void initTestCase();
|
void initTestCase();
|
||||||
void init();
|
void init();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
void testAxis_data();
|
||||||
void testAxis();
|
void testAxis();
|
||||||
|
void testDoubleClick_data();
|
||||||
void testDoubleClick();
|
void testDoubleClick();
|
||||||
void testHover();
|
void testHover();
|
||||||
void testPressToMove_data();
|
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()
|
void DecorationInputTest::testAxis()
|
||||||
{
|
{
|
||||||
AbstractClient *c = showWindow();
|
AbstractClient *c = showWindow();
|
||||||
|
@ -251,6 +267,8 @@ void DecorationInputTest::testAxis()
|
||||||
|
|
||||||
quint32 timestamp = 1;
|
quint32 timestamp = 1;
|
||||||
MOTION(QPoint(c->geometry().center().x(), c->clientPos().y() / 2));
|
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
|
// TODO: mouse wheel direction looks wrong to me
|
||||||
// simulate wheel
|
// simulate wheel
|
||||||
|
@ -263,6 +281,27 @@ void DecorationInputTest::testAxis()
|
||||||
kwinApp()->platform()->pointerAxisVertical(-5.0, timestamp++);
|
kwinApp()->platform()->pointerAxisVertical(-5.0, timestamp++);
|
||||||
QVERIFY(!c->keepBelow());
|
QVERIFY(!c->keepBelow());
|
||||||
QVERIFY(c->keepAbove());
|
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()
|
void KWin::DecorationInputTest::testDoubleClick()
|
||||||
|
@ -288,6 +327,21 @@ void KWin::DecorationInputTest::testDoubleClick()
|
||||||
PRESS;
|
PRESS;
|
||||||
RELEASE;
|
RELEASE;
|
||||||
QVERIFY(!c->isOnAllDesktops());
|
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()
|
void DecorationInputTest::testHover()
|
||||||
|
|
|
@ -1172,7 +1172,7 @@ bool Client::buttonPressEvent(xcb_window_t w, int button, int state, int x, int
|
||||||
event.setAccepted(false);
|
event.setAccepted(false);
|
||||||
QCoreApplication::sendEvent(decoration(), &event);
|
QCoreApplication::sendEvent(decoration(), &event);
|
||||||
if (!event.isAccepted() && !hor) {
|
if (!event.isAccepted() && !hor) {
|
||||||
if (decoration()->titleBar().contains(x, y)) {
|
if (titlebarPositionUnderMouse()) {
|
||||||
performMouseCommand(options->operationTitlebarMouseWheel(delta), QPoint(x_root, y_root));
|
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));
|
x11ToQtKeyboardModifiers(state));
|
||||||
event.setAccepted(false);
|
event.setAccepted(false);
|
||||||
QCoreApplication::sendEvent(decoration(), &event);
|
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
|
invalidateDecorationDoubleClickTimer(); // click was for the deco and shall not init a doubleclick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,7 +485,7 @@ public:
|
||||||
if (e.isAccepted()) {
|
if (e.isAccepted()) {
|
||||||
return true;
|
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),
|
decoration->client()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1),
|
||||||
event->globalPosF().toPoint());
|
event->globalPosF().toPoint());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue