diff --git a/autotests/wayland/pointer_input.cpp b/autotests/wayland/pointer_input.cpp
index cb9abeb524..dac2db62c1 100644
--- a/autotests/wayland/pointer_input.cpp
+++ b/autotests/wayland/pointer_input.cpp
@@ -41,6 +41,8 @@ along with this program. If not, see .
#include
+#include
+
namespace KWin
{
@@ -56,6 +58,8 @@ private Q_SLOTS:
void testWarpingUpdatesFocus();
void testWarpingGeneratesPointerMotion();
void testUpdateFocusAfterScreenChange();
+ void testModifierClickUnrestrictedMove_data();
+ void testModifierClickUnrestrictedMove();
private:
void render(KWayland::Client::Surface *surface, const QSize &size = QSize(100, 50));
@@ -79,6 +83,8 @@ void PointerInputTest::initTestCase()
QMetaObject::invokeMethod(waylandServer()->backend(), "setOutputCount", Qt::DirectConnection, Q_ARG(int, 2));
waylandServer()->init(s_socketName.toLocal8Bit());
+ kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
+
kwinApp()->start();
QVERIFY(workspaceCreatedSpy.wait());
QCOMPARE(screens()->count(), 2);
@@ -310,6 +316,87 @@ void PointerInputTest::testUpdateFocusAfterScreenChange()
QCOMPARE(enteredSpy.count(), 1);
}
+void PointerInputTest::testModifierClickUnrestrictedMove_data()
+{
+ QTest::addColumn("modifierKey");
+ QTest::addColumn("mouseButton");
+ QTest::addColumn("modKey");
+
+ const QString alt = QStringLiteral("Alt");
+ const QString meta = QStringLiteral("Meta");
+
+ QTest::newRow("Left Alt + Left Click") << KEY_LEFTALT << BTN_LEFT << alt;
+ QTest::newRow("Left Alt + Right Click") << KEY_LEFTALT << BTN_RIGHT << alt;
+ QTest::newRow("Left Alt + Middle Click") << KEY_LEFTALT << BTN_MIDDLE << alt;
+ QTest::newRow("Right Alt + Left Click") << KEY_RIGHTALT << BTN_LEFT << alt;
+ QTest::newRow("Right Alt + Right Click") << KEY_RIGHTALT << BTN_RIGHT << alt;
+ QTest::newRow("Right Alt + Middle Click") << KEY_RIGHTALT << BTN_MIDDLE << alt;
+ // now everything with meta
+ QTest::newRow("Left Meta + Left Click") << KEY_LEFTMETA << BTN_LEFT << meta;
+ QTest::newRow("Left Meta + Right Click") << KEY_LEFTMETA << BTN_RIGHT << meta;
+ QTest::newRow("Left Meta + Middle Click") << KEY_LEFTMETA << BTN_MIDDLE << meta;
+ QTest::newRow("Right Meta + Left Click") << KEY_RIGHTMETA << BTN_LEFT << meta;
+ QTest::newRow("Right Meta + Right Click") << KEY_RIGHTMETA << BTN_RIGHT << meta;
+ QTest::newRow("Right Meta + Middle Click") << KEY_RIGHTMETA << BTN_MIDDLE << meta;
+}
+
+void PointerInputTest::testModifierClickUnrestrictedMove()
+{
+ // this test ensures that Alt+mouse button press triggers unrestricted move
+ using namespace KWayland::Client;
+ // create pointer and signal spy for button events
+ auto pointer = m_seat->createPointer(m_seat);
+ QVERIFY(pointer);
+ QVERIFY(pointer->isValid());
+ QSignalSpy buttonSpy(pointer, &Pointer::buttonStateChanged);
+ QVERIFY(buttonSpy.isValid());
+
+ // first modify the config for this run
+ QFETCH(QString, modKey);
+ KConfigGroup group = kwinApp()->config()->group("MouseBindings");
+ group.writeEntry("CommandAllKey", modKey);
+ group.writeEntry("CommandAll1", "Move");
+ group.writeEntry("CommandAll2", "Move");
+ group.writeEntry("CommandAll3", "Move");
+ group.sync();
+ workspace()->slotReconfigure();
+
+ // create a window
+ QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
+ QVERIFY(clientAddedSpy.isValid());
+ Surface *surface = m_compositor->createSurface(m_compositor);
+ QVERIFY(surface);
+ ShellSurface *shellSurface = m_shell->createSurface(surface, surface);
+ QVERIFY(shellSurface);
+ render(surface);
+ QVERIFY(clientAddedSpy.wait());
+ AbstractClient *window = workspace()->activeClient();
+ QVERIFY(window);
+
+ // move cursor on window
+ Cursor::setPos(window->geometry().center());
+
+ // simulate modifier+click
+ quint32 timestamp = 1;
+ QFETCH(int, modifierKey);
+ QFETCH(int, mouseButton);
+ waylandServer()->backend()->keyboardKeyPressed(modifierKey, timestamp++);
+ QVERIFY(!window->isMove());
+ waylandServer()->backend()->pointerButtonPressed(mouseButton, timestamp++);
+ QVERIFY(window->isMove());
+ // release modifier should not change it
+ waylandServer()->backend()->keyboardKeyReleased(modifierKey, timestamp++);
+ QVERIFY(window->isMove());
+ // but releasing the key should end move/resize
+ waylandServer()->backend()->pointerButtonReleased(mouseButton, timestamp++);
+ QVERIFY(!window->isMove());
+
+ // all of that should not have triggered button events on the surface
+ QCOMPARE(buttonSpy.count(), 0);
+ // also waiting shouldn't give us the event
+ QVERIFY(!buttonSpy.wait(100));
+}
+
}
WAYLANDTEST_MAIN(KWin::PointerInputTest)
diff --git a/input.cpp b/input.cpp
index 8bb324e166..bf94644c88 100644
--- a/input.cpp
+++ b/input.cpp
@@ -520,7 +520,26 @@ public:
bool passThrough = true;
if (AbstractClient *c = dynamic_cast(input()->pointer()->window().data())) {
bool wasAction = false;
- const Options::MouseCommand command = c->getMouseCommand(event->button(), &wasAction);
+ Options::MouseCommand command = Options::MouseNothing;
+ if (event->modifiers() == 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 {
+ c->getMouseCommand(event->button(), &wasAction);
+ }
if (wasAction) {
passThrough = c->performMouseCommand(command, event->globalPos());
}
diff --git a/options.h b/options.h
index 96ad4d333a..4c09b9edc1 100644
--- a/options.h
+++ b/options.h
@@ -459,6 +459,16 @@ public:
uint keyCmdAllModKey() const {
return CmdAllModKey;
}
+ Qt::KeyboardModifier commandAllModifier() const {
+ switch (CmdAllModKey) {
+ case Qt::Key_Alt:
+ return Qt::AltModifier;
+ case Qt::Key_Meta:
+ return Qt::MetaModifier;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
static WindowOperation windowOperation(const QString &name, bool restricted);
static MouseCommand mouseCommand(const QString &name, bool restricted);