Warp the cursor pos to the specificed global position in a NET::Move request
Summary: The cursor position is the reference KWin uses while moving a window. If we don't warp the cursor position the window "jumps" to the cursor position on first movement. For requests triggered by the client (e.g. widget style) this does not matter as the cursor is at the correct position. But for tools such as task bars we should ensure the cursor is at the right pos. Reviewers: #plasma, hein Subscribers: plasma-devel Projects: #plasma Differential Revision: https://phabricator.kde.org/D1421
This commit is contained in:
parent
1309b8c8a0
commit
e2e6d8b08b
3 changed files with 89 additions and 3 deletions
|
@ -32,7 +32,7 @@ ecm_mark_as_test(testQuickTiling)
|
|||
########################################################
|
||||
set( testMoveResize_SRCS move_resize_window_test.cpp kwin_wayland_test.cpp )
|
||||
add_executable(testMoveResize ${testMoveResize_SRCS})
|
||||
target_link_libraries( testMoveResize kwin Qt5::Test)
|
||||
target_link_libraries( testMoveResize kwin Qt5::Test XCB::ICCCM)
|
||||
add_test(kwin-testMoveResize testMoveResize)
|
||||
ecm_mark_as_test(testMoveResize)
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
Q_DECLARE_METATYPE(KWin::AbstractClient::QuickTileMode)
|
||||
Q_DECLARE_METATYPE(KWin::MaximizeMode)
|
||||
|
@ -65,6 +66,7 @@ private Q_SLOTS:
|
|||
void testPointerMoveEnd();
|
||||
void testPlasmaShellSurfaceMovable_data();
|
||||
void testPlasmaShellSurfaceMovable();
|
||||
void testNetMove();
|
||||
|
||||
private:
|
||||
KWayland::Client::ConnectionThread *m_connection = nullptr;
|
||||
|
@ -571,6 +573,86 @@ void MoveResizeWindowTest::testPlasmaShellSurfaceMovable()
|
|||
QTEST(c->isResizable(), "resizable");
|
||||
}
|
||||
|
||||
void MoveResizeWindowTest::testNetMove()
|
||||
{
|
||||
// this test verifies that a move request for an X11 window through NET API works
|
||||
// create an xcb window
|
||||
struct XcbConnectionDeleter
|
||||
{
|
||||
static inline void cleanup(xcb_connection_t *pointer)
|
||||
{
|
||||
xcb_disconnect(pointer);
|
||||
}
|
||||
};
|
||||
QScopedPointer<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr));
|
||||
QVERIFY(!xcb_connection_has_error(c.data()));
|
||||
|
||||
xcb_window_t w = xcb_generate_id(c.data());
|
||||
xcb_create_window(c.data(), XCB_COPY_FROM_PARENT, w, rootWindow(),
|
||||
0, 0, 100, 100,
|
||||
0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
|
||||
xcb_size_hints_t hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
xcb_icccm_size_hints_set_position(&hints, 1, 0, 0);
|
||||
xcb_icccm_size_hints_set_size(&hints, 1, 100, 100);
|
||||
xcb_icccm_set_wm_normal_hints(c.data(), w, &hints);
|
||||
// let's set a no-border
|
||||
NETWinInfo winInfo(c.data(), w, rootWindow(), NET::WMWindowType, NET::Properties2());
|
||||
winInfo.setWindowType(NET::Override);
|
||||
xcb_map_window(c.data(), w);
|
||||
xcb_flush(c.data());
|
||||
|
||||
QSignalSpy windowCreatedSpy(workspace(), &Workspace::clientAdded);
|
||||
QVERIFY(windowCreatedSpy.isValid());
|
||||
QVERIFY(windowCreatedSpy.wait());
|
||||
Client *client = windowCreatedSpy.first().first().value<Client*>();
|
||||
QVERIFY(client);
|
||||
QCOMPARE(client->window(), w);
|
||||
const QRect origGeo = client->geometry();
|
||||
|
||||
// let's move the cursor outside the window
|
||||
Cursor::setPos(screens()->geometry(0).center());
|
||||
QVERIFY(!origGeo.contains(Cursor::pos()));
|
||||
|
||||
QSignalSpy moveStartSpy(client, &Client::clientStartUserMovedResized);
|
||||
QVERIFY(moveStartSpy.isValid());
|
||||
QSignalSpy moveEndSpy(client, &Client::clientFinishUserMovedResized);
|
||||
QVERIFY(moveEndSpy.isValid());
|
||||
QSignalSpy moveStepSpy(client, &Client::clientStepUserMovedResized);
|
||||
QVERIFY(moveStepSpy.isValid());
|
||||
|
||||
// use NETRootInfo to trigger a move request
|
||||
NETRootInfo root(c.data(), NET::Properties());
|
||||
root.moveResizeRequest(w, origGeo.center().x(), origGeo.center().y(), NET::Move);
|
||||
xcb_flush(c.data());
|
||||
|
||||
QVERIFY(moveStartSpy.wait());
|
||||
QCOMPARE(workspace()->getMovingClient(), client);
|
||||
QVERIFY(client->isMove());
|
||||
QCOMPARE(client->geometryRestore(), origGeo);
|
||||
QCOMPARE(Cursor::pos(), origGeo.center());
|
||||
|
||||
// let's move a step
|
||||
Cursor::setPos(Cursor::pos() + QPoint(10, 10));
|
||||
QCOMPARE(moveStepSpy.count(), 1);
|
||||
QCOMPARE(moveStepSpy.first().last().toRect(), origGeo.translated(10, 10));
|
||||
|
||||
// let's cancel the move resize again through the net API
|
||||
root.moveResizeRequest(w, client->geometry().center().x(), client->geometry().center().y(), NET::MoveResizeCancel);
|
||||
xcb_flush(c.data());
|
||||
QVERIFY(moveEndSpy.wait());
|
||||
|
||||
// and destroy the window again
|
||||
xcb_unmap_window(c.data(), w);
|
||||
xcb_destroy_window(c.data(), w);
|
||||
xcb_flush(c.data());
|
||||
c.reset();
|
||||
|
||||
QSignalSpy windowClosedSpy(client, &Client::windowClosed);
|
||||
QVERIFY(windowClosedSpy.isValid());
|
||||
QVERIFY(windowClosedSpy.wait());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KWin::MoveResizeWindowTest)
|
||||
|
|
|
@ -1340,9 +1340,13 @@ void Client::focusOutEvent(xcb_focus_out_event_t *e)
|
|||
// performs _NET_WM_MOVERESIZE
|
||||
void Client::NETMoveResize(int x_root, int y_root, NET::Direction direction)
|
||||
{
|
||||
if (direction == NET::Move)
|
||||
if (direction == NET::Move) {
|
||||
// move cursor to the provided position to prevent the window jumping there on first movement
|
||||
// the expectation is that the cursor is already at the provided position,
|
||||
// thus it's more a safety measurement
|
||||
Cursor::setPos(QPoint(x_root, y_root));
|
||||
performMouseCommand(Options::MouseMove, QPoint(x_root, y_root));
|
||||
else if (isMoveResize() && direction == NET::MoveResizeCancel) {
|
||||
} else if (isMoveResize() && direction == NET::MoveResizeCancel) {
|
||||
finishMoveResize(true);
|
||||
setMoveResizePointerButtonDown(false);
|
||||
updateCursor();
|
||||
|
|
Loading…
Reference in a new issue