Support modifier mouse/scroll action on internal decorated windows
Summary: This fixes the problem that alt+lmb did not start unrestricted move resize for the Debug Console. BUG: 374880 FIXED-IN: 5.12.3 Test Plan: New test case and manual testing whether alt+lmb/rmb works Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #plasma Differential Revision: https://phabricator.kde.org/D10440
This commit is contained in:
parent
067274151f
commit
b554e54e87
2 changed files with 168 additions and 57 deletions
|
@ -61,6 +61,8 @@ private Q_SLOTS:
|
|||
void testMove();
|
||||
void testSkipCloseAnimation_data();
|
||||
void testSkipCloseAnimation();
|
||||
void testModifierClickUnrestrictedMove();
|
||||
void testModifierScroll();
|
||||
};
|
||||
|
||||
class HelperWindow : public QRasterWindow
|
||||
|
@ -175,6 +177,7 @@ void InternalWindowTest::initTestCase()
|
|||
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
|
||||
QMetaObject::invokeMethod(kwinApp()->platform(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2));
|
||||
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
|
||||
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
|
||||
|
||||
kwinApp()->start();
|
||||
QVERIFY(workspaceCreatedSpy.wait());
|
||||
|
@ -212,6 +215,7 @@ void InternalWindowTest::testEnterLeave()
|
|||
ShellClient *c = clientAddedSpy.first().first().value<ShellClient*>();
|
||||
QVERIFY(c->isInternal());
|
||||
QCOMPARE(c->icon().name(), QStringLiteral("wayland"));
|
||||
QVERIFY(!c->isDecorated());
|
||||
QCOMPARE(workspace()->findToplevel(&win), c);
|
||||
QCOMPARE(c->geometry(), QRect(0, 0, 100, 100));
|
||||
QVERIFY(c->isShown(false));
|
||||
|
@ -589,6 +593,84 @@ void InternalWindowTest::testSkipCloseAnimation()
|
|||
QCOMPARE(internalClient->skipsCloseAnimation(), initial);
|
||||
}
|
||||
|
||||
void InternalWindowTest::testModifierClickUnrestrictedMove()
|
||||
{
|
||||
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
|
||||
QVERIFY(clientAddedSpy.isValid());
|
||||
HelperWindow win;
|
||||
win.setGeometry(0, 0, 100, 100);
|
||||
win.setFlags(win.flags() & ~Qt::FramelessWindowHint);
|
||||
win.show();
|
||||
QVERIFY(clientAddedSpy.wait());
|
||||
QCOMPARE(clientAddedSpy.count(), 1);
|
||||
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
|
||||
QVERIFY(internalClient);
|
||||
QVERIFY(internalClient->isDecorated());
|
||||
|
||||
KConfigGroup group = kwinApp()->config()->group("MouseBindings");
|
||||
group.writeEntry("CommandAllKey", "Alt");
|
||||
group.writeEntry("CommandAll1", "Move");
|
||||
group.writeEntry("CommandAll2", "Move");
|
||||
group.writeEntry("CommandAll3", "Move");
|
||||
group.sync();
|
||||
workspace()->slotReconfigure();
|
||||
QCOMPARE(options->commandAllModifier(), Qt::AltModifier);
|
||||
QCOMPARE(options->commandAll1(), Options::MouseUnrestrictedMove);
|
||||
QCOMPARE(options->commandAll2(), Options::MouseUnrestrictedMove);
|
||||
QCOMPARE(options->commandAll3(), Options::MouseUnrestrictedMove);
|
||||
|
||||
// move cursor on window
|
||||
Cursor::setPos(internalClient->geometry().center());
|
||||
|
||||
// simulate modifier+click
|
||||
quint32 timestamp = 1;
|
||||
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
||||
QVERIFY(!internalClient->isMove());
|
||||
kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, timestamp++);
|
||||
QVERIFY(internalClient->isMove());
|
||||
// release modifier should not change it
|
||||
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
||||
QVERIFY(internalClient->isMove());
|
||||
// but releasing the key should end move/resize
|
||||
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, timestamp++);
|
||||
QVERIFY(!internalClient->isMove());
|
||||
}
|
||||
|
||||
void InternalWindowTest::testModifierScroll()
|
||||
{
|
||||
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
|
||||
QVERIFY(clientAddedSpy.isValid());
|
||||
HelperWindow win;
|
||||
win.setGeometry(0, 0, 100, 100);
|
||||
win.setFlags(win.flags() & ~Qt::FramelessWindowHint);
|
||||
win.show();
|
||||
QVERIFY(clientAddedSpy.wait());
|
||||
QCOMPARE(clientAddedSpy.count(), 1);
|
||||
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
|
||||
QVERIFY(internalClient);
|
||||
QVERIFY(internalClient->isDecorated());
|
||||
|
||||
KConfigGroup group = kwinApp()->config()->group("MouseBindings");
|
||||
group.writeEntry("CommandAllKey", "Alt");
|
||||
group.writeEntry("CommandAllWheel", "change opacity");
|
||||
group.sync();
|
||||
workspace()->slotReconfigure();
|
||||
|
||||
// move cursor on window
|
||||
Cursor::setPos(internalClient->geometry().center());
|
||||
|
||||
// set the opacity to 0.5
|
||||
internalClient->setOpacity(0.5);
|
||||
QCOMPARE(internalClient->opacity(), 0.5);
|
||||
quint32 timestamp = 1;
|
||||
kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTALT, timestamp++);
|
||||
kwinApp()->platform()->pointerAxisVertical(-5, timestamp++);
|
||||
QCOMPARE(internalClient->opacity(), 0.6);
|
||||
kwinApp()->platform()->pointerAxisVertical(5, timestamp++);
|
||||
QCOMPARE(internalClient->opacity(), 0.5);
|
||||
kwinApp()->platform()->keyboardKeyReleased(KEY_LEFTALT, timestamp++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::InternalWindowTest)
|
||||
|
|
143
input.cpp
143
input.cpp
|
@ -766,6 +766,64 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
enum class MouseAction {
|
||||
ModifierOnly,
|
||||
ModifierAndWindow
|
||||
};
|
||||
std::pair<bool, bool> performClientMouseAction(QMouseEvent *event, AbstractClient *client, MouseAction action = MouseAction::ModifierOnly)
|
||||
{
|
||||
Options::MouseCommand command = Options::MouseNothing;
|
||||
bool wasAction = false;
|
||||
if (static_cast<MouseEvent*>(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) {
|
||||
wasAction = true;
|
||||
switch (event->button()) {
|
||||
case Qt::LeftButton:
|
||||
command = options->commandAll1();
|
||||
break;
|
||||
case Qt::MiddleButton:
|
||||
command = options->commandAll2();
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
command = options->commandAll3();
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (action == MouseAction::ModifierAndWindow) {
|
||||
command = client->getMouseCommand(event->button(), &wasAction);
|
||||
}
|
||||
}
|
||||
if (wasAction) {
|
||||
return std::make_pair(wasAction, !client->performMouseCommand(command, event->globalPos()));
|
||||
}
|
||||
return std::make_pair(wasAction, false);
|
||||
}
|
||||
|
||||
std::pair<bool, bool> performClientWheelAction(QWheelEvent *event, AbstractClient *c, MouseAction action = MouseAction::ModifierOnly)
|
||||
{
|
||||
bool wasAction = false;
|
||||
Options::MouseCommand command = Options::MouseNothing;
|
||||
if (static_cast<WheelEvent*>(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) {
|
||||
wasAction = true;
|
||||
command = options->operationWindowMouseWheel(-1 * event->angleDelta().y());
|
||||
} else {
|
||||
if (action == MouseAction::ModifierAndWindow) {
|
||||
command = c->getWheelCommand(Qt::Vertical, &wasAction);
|
||||
}
|
||||
}
|
||||
if (wasAction) {
|
||||
return std::make_pair(wasAction, !c->performMouseCommand(command, event->globalPos()));
|
||||
}
|
||||
return std::make_pair(wasAction, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class InternalWindowEventFilter : public InputEventFilter {
|
||||
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override {
|
||||
Q_UNUSED(nativeButton)
|
||||
|
@ -780,6 +838,24 @@ class InternalWindowEventFilter : public InputEventFilter {
|
|||
if (!internal) {
|
||||
return false;
|
||||
}
|
||||
// find client
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease: {
|
||||
auto s = waylandServer()->findClient(internal);
|
||||
if (s && s->isDecorated()) {
|
||||
// only perform mouse commands on decorated internal windows
|
||||
const auto actionResult = performClientMouseAction(event, s);
|
||||
if (actionResult.first) {
|
||||
return actionResult.second;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
QMouseEvent e(event->type(),
|
||||
event->pos() - internal->position(),
|
||||
event->globalPos(),
|
||||
|
@ -793,6 +869,16 @@ class InternalWindowEventFilter : public InputEventFilter {
|
|||
if (!internal) {
|
||||
return false;
|
||||
}
|
||||
if (event->angleDelta().y() != 0) {
|
||||
auto s = waylandServer()->findClient(internal);
|
||||
if (s && s->isDecorated()) {
|
||||
// client window action only on vertical scrolling
|
||||
const auto actionResult = performClientWheelAction(event, s);
|
||||
if (actionResult.first) {
|
||||
return actionResult.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
const QPointF localPos = event->globalPosF() - QPointF(internal->x(), internal->y());
|
||||
const Qt::Orientation orientation = (event->angleDelta().x() != 0) ? Qt::Horizontal : Qt::Vertical;
|
||||
const int delta = event->angleDelta().x() != 0 ? event->angleDelta().x() : event->angleDelta().y();
|
||||
|
@ -929,63 +1015,6 @@ private:
|
|||
QPointF m_lastLocalTouchPos;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
enum class MouseAction {
|
||||
ModifierOnly,
|
||||
ModifierAndWindow
|
||||
};
|
||||
std::pair<bool, bool> performClientMouseAction(QMouseEvent *event, AbstractClient *client, MouseAction action = MouseAction::ModifierOnly)
|
||||
{
|
||||
Options::MouseCommand command = Options::MouseNothing;
|
||||
bool wasAction = false;
|
||||
if (static_cast<MouseEvent*>(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) {
|
||||
wasAction = true;
|
||||
switch (event->button()) {
|
||||
case Qt::LeftButton:
|
||||
command = options->commandAll1();
|
||||
break;
|
||||
case Qt::MiddleButton:
|
||||
command = options->commandAll2();
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
command = options->commandAll3();
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (action == MouseAction::ModifierAndWindow) {
|
||||
command = client->getMouseCommand(event->button(), &wasAction);
|
||||
}
|
||||
}
|
||||
if (wasAction) {
|
||||
return std::make_pair(wasAction, !client->performMouseCommand(command, event->globalPos()));
|
||||
}
|
||||
return std::make_pair(wasAction, false);
|
||||
}
|
||||
|
||||
std::pair<bool, bool> performClientWheelAction(QWheelEvent *event, AbstractClient *c, MouseAction action = MouseAction::ModifierOnly)
|
||||
{
|
||||
bool wasAction = false;
|
||||
Options::MouseCommand command = Options::MouseNothing;
|
||||
if (static_cast<WheelEvent*>(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) {
|
||||
wasAction = true;
|
||||
command = options->operationWindowMouseWheel(-1 * event->angleDelta().y());
|
||||
} else {
|
||||
if (action == MouseAction::ModifierAndWindow) {
|
||||
command = c->getWheelCommand(Qt::Vertical, &wasAction);
|
||||
}
|
||||
}
|
||||
if (wasAction) {
|
||||
return std::make_pair(wasAction, !c->performMouseCommand(command, event->globalPos()));
|
||||
}
|
||||
return std::make_pair(wasAction, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DecorationEventFilter : public InputEventFilter {
|
||||
public:
|
||||
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override {
|
||||
|
|
Loading…
Reference in a new issue