From 4e7521fe64932bbb8f18883f363d62a067a01dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 26 Oct 2015 09:17:46 +0100 Subject: [PATCH] Allow moving of Wayland windows So far only moving through useractions menu is possible and only through cursor control (mouse events are lost). A basic first autotest is added to validate the moving of Windows. --- autotests/wayland/CMakeLists.txt | 9 + autotests/wayland/move_resize_window_test.cpp | 229 ++++++++++++++++++ shell_client.cpp | 4 +- 3 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 autotests/wayland/move_resize_window_test.cpp diff --git a/autotests/wayland/CMakeLists.txt b/autotests/wayland/CMakeLists.txt index 604acc1cec..8a7b41e5c3 100644 --- a/autotests/wayland/CMakeLists.txt +++ b/autotests/wayland/CMakeLists.txt @@ -27,6 +27,15 @@ target_link_libraries( testQuickTiling kwin Qt5::Test) add_test(kwin-testQuickTiling testQuickTiling) ecm_mark_as_test(testQuickTiling) +######################################################## +# Move/Resize window test +######################################################## +set( testMoveResize_SRCS move_resize_window_test.cpp kwin_wayland_test.cpp ) +add_executable(testMoveResize ${testMoveResize_SRCS}) +target_link_libraries( testMoveResize kwin Qt5::Test) +add_test(kwin-testMoveResize testMoveResize) +ecm_mark_as_test(testMoveResize) + ######################################################## # Don't Crash For glxgears ######################################################## diff --git a/autotests/wayland/move_resize_window_test.cpp b/autotests/wayland/move_resize_window_test.cpp new file mode 100644 index 0000000000..b0d4c487da --- /dev/null +++ b/autotests/wayland/move_resize_window_test.cpp @@ -0,0 +1,229 @@ + +/******************************************************************** +KWin - the KDE window manager +This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "kwin_wayland_test.h" +#include "abstract_backend.h" +#include "abstract_client.h" +#include "cursor.h" +#include "screens.h" +#include "wayland_server.h" +#include "workspace.h" +#include "shell_client.h" + +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(KWin::AbstractClient::QuickTileMode) +Q_DECLARE_METATYPE(KWin::MaximizeMode) + +namespace KWin +{ + +static const QString s_socketName = QStringLiteral("wayland_test_kwin_quick_tiling-0"); + +class MoveResizeWindowTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void init(); + void cleanup(); + void testMove(); + +private: + KWayland::Client::ConnectionThread *m_connection = nullptr; + KWayland::Client::Compositor *m_compositor = nullptr; + KWayland::Client::ShmPool *m_shm = nullptr; + KWayland::Client::Shell *m_shell = nullptr; + KWayland::Client::EventQueue *m_queue = nullptr; + QThread *m_thread = nullptr; +}; + +void MoveResizeWindowTest::initTestCase() +{ + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType("MaximizeMode"); + QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated); + QVERIFY(workspaceCreatedSpy.isValid()); + waylandServer()->backend()->setInitialWindowSize(QSize(1280, 1024)); + waylandServer()->init(s_socketName.toLocal8Bit()); + kwinApp()->start(); + QVERIFY(workspaceCreatedSpy.wait()); + QCOMPARE(screens()->count(), 1); + QCOMPARE(screens()->geometry(0), QRect(0, 0, 1280, 1024)); +} + +void MoveResizeWindowTest::init() +{ + using namespace KWayland::Client; + // setup connection + m_connection = new ConnectionThread; + QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); + QVERIFY(connectedSpy.isValid()); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + m_queue = new EventQueue(this); + QVERIFY(!m_queue->isValid()); + m_queue->setup(m_connection); + QVERIFY(m_queue->isValid()); + + Registry registry; + registry.setEventQueue(m_queue); + QSignalSpy compositorSpy(®istry, &Registry::compositorAnnounced); + QSignalSpy shmSpy(®istry, &Registry::shmAnnounced); + QSignalSpy shellSpy(®istry, &Registry::shellAnnounced); + QSignalSpy allAnnounced(®istry, &Registry::interfacesAnnounced); + QVERIFY(allAnnounced.isValid()); + QVERIFY(shmSpy.isValid()); + QVERIFY(shellSpy.isValid()); + QVERIFY(compositorSpy.isValid()); + registry.create(m_connection->display()); + QVERIFY(registry.isValid()); + registry.setup(); + QVERIFY(allAnnounced.wait()); + QVERIFY(!compositorSpy.isEmpty()); + QVERIFY(!shmSpy.isEmpty()); + QVERIFY(!shellSpy.isEmpty()); + + m_compositor = registry.createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); + QVERIFY(m_compositor->isValid()); + m_shm = registry.createShmPool(shmSpy.first().first().value(), shmSpy.first().last().value(), this); + QVERIFY(m_shm->isValid()); + m_shell = registry.createShell(shellSpy.first().first().value(), shellSpy.first().last().value(), this); + QVERIFY(m_shell->isValid()); + + screens()->setCurrent(0); +} + +void MoveResizeWindowTest::cleanup() +{ + delete m_compositor; + m_compositor = nullptr; + delete m_shm; + m_shm = nullptr; + delete m_shell; + m_shell = nullptr; + delete m_queue; + m_queue = nullptr; + if (m_thread) { + m_thread->quit(); + m_thread->wait(); + delete m_thread; + m_thread = nullptr; + } + +} + +void MoveResizeWindowTest::testMove() +{ + using namespace KWayland::Client; + + QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded); + QVERIFY(clientAddedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + QVERIFY(!surface.isNull()); + + QScopedPointer shellSurface(m_shell->createSurface(surface.data())); + QVERIFY(!shellSurface.isNull()); + QSignalSpy sizeChangeSpy(shellSurface.data(), &ShellSurface::sizeChanged); + QVERIFY(sizeChangeSpy.isValid()); + // let's render + QImage img(QSize(100, 50), QImage::Format_ARGB32); + img.fill(Qt::blue); + surface->attachBuffer(m_shm->createBuffer(img)); + surface->damage(QRect(0, 0, 100, 50)); + surface->commit(Surface::CommitFlag::None); + + m_connection->flush(); + QVERIFY(clientAddedSpy.wait()); + AbstractClient *c = workspace()->activeClient(); + QVERIFY(c); + QCOMPARE(clientAddedSpy.first().first().value(), c); + QCOMPARE(c->geometry(), QRect(0, 0, 100, 50)); + QSignalSpy geometryChangedSpy(c, &AbstractClient::geometryChanged); + QVERIFY(geometryChangedSpy.isValid()); + QSignalSpy startMoveResizedSpy(c, &AbstractClient::clientStartUserMovedResized); + QVERIFY(startMoveResizedSpy.isValid()); + QSignalSpy moveResizedChangedSpy(c, &AbstractClient::moveResizedChanged); + QVERIFY(moveResizedChangedSpy.isValid()); + QSignalSpy clientStepUserMovedResizedSpy(c, &AbstractClient::clientStepUserMovedResized); + QVERIFY(clientStepUserMovedResizedSpy.isValid()); + QSignalSpy clientFinishUserMovedResizedSpy(c, &AbstractClient::clientFinishUserMovedResized); + QVERIFY(clientFinishUserMovedResizedSpy.isValid()); + + // begin move + QVERIFY(workspace()->getMovingClient() == nullptr); + QCOMPARE(c->isMove(), false); + workspace()->slotWindowMove(); + QCOMPARE(workspace()->getMovingClient(), c); + QCOMPARE(startMoveResizedSpy.count(), 1); + QEXPECT_FAIL("", "Connect is in Client", Continue); + QCOMPARE(moveResizedChangedSpy.count(), 1); + QCOMPARE(c->isMove(), true); + QCOMPARE(c->geometryRestore(), QRect(0, 0, 100, 50)); + + // send some key events, not going through input redirection + const QPoint cursorPos = Cursor::pos(); + c->keyPressEvent(Qt::Key_Right); + c->updateMoveResize(Cursor::pos()); + QCOMPARE(Cursor::pos(), cursorPos + QPoint(8, 0)); + QEXPECT_FAIL("", "First event is ignored", Continue); + QCOMPARE(clientStepUserMovedResizedSpy.count(), 1); + + c->keyPressEvent(Qt::Key_Right); + c->updateMoveResize(Cursor::pos()); + QCOMPARE(Cursor::pos(), cursorPos + QPoint(16, 0)); + QEXPECT_FAIL("", "First event is ignored", Continue); + QCOMPARE(clientStepUserMovedResizedSpy.count(), 2); + + c->keyPressEvent(Qt::Key_Down | Qt::ALT); + c->updateMoveResize(Cursor::pos()); + QEXPECT_FAIL("", "First event is ignored", Continue); + QCOMPARE(clientStepUserMovedResizedSpy.count(), 3); + QCOMPARE(c->geometry(), QRect(16, 32, 100, 50)); + QCOMPARE(Cursor::pos(), cursorPos + QPoint(16, 32)); + + // let's end + QCOMPARE(clientFinishUserMovedResizedSpy.count(), 0); + c->keyPressEvent(Qt::Key_Enter); + QCOMPARE(clientFinishUserMovedResizedSpy.count(), 1); + QCOMPARE(c->geometry(), QRect(16, 32, 100, 50)); + QCOMPARE(c->isMove(), false); + QVERIFY(workspace()->getMovingClient() == nullptr); +} + +} + +WAYLANTEST_MAIN(KWin::MoveResizeWindowTest) +#include "move_resize_window_test.moc" diff --git a/shell_client.cpp b/shell_client.cpp index fb9d5bf4be..b91a955376 100644 --- a/shell_client.cpp +++ b/shell_client.cpp @@ -356,12 +356,12 @@ bool ShellClient::isMinimizable() const bool ShellClient::isMovable() const { - return false; + return true; } bool ShellClient::isMovableAcrossScreens() const { - return false; + return true; } bool ShellClient::isResizable() const