autotests: Add _NET_WM_MOVERESIZE tests

This commit is contained in:
Vlad Zahorodnii 2024-03-16 13:22:42 +02:00
parent 8892b16626
commit 6b1e2f24f4
3 changed files with 443 additions and 75 deletions

View file

@ -54,7 +54,6 @@ private Q_SLOTS:
void testPointerMoveEnd_data(); void testPointerMoveEnd_data();
void testPointerMoveEnd(); void testPointerMoveEnd();
void testClientSideMove(); void testClientSideMove();
void testNetMove();
void testAdjustClientGeometryOfHiddenX11Panel_data(); void testAdjustClientGeometryOfHiddenX11Panel_data();
void testAdjustClientGeometryOfHiddenX11Panel(); void testAdjustClientGeometryOfHiddenX11Panel();
void testAdjustClientGeometryOfHiddenWaylandPanel_data(); void testAdjustClientGeometryOfHiddenWaylandPanel_data();
@ -536,76 +535,6 @@ void MoveResizeWindowTest::testClientSideMove()
QCOMPARE(pointerEnteredSpy.last().last().toPoint(), QPoint(50, 25)); QCOMPARE(pointerEnteredSpy.last().last().toPoint(), QPoint(50, 25));
} }
void MoveResizeWindowTest::testNetMove()
{
// this test verifies that a move request for an X11 window through NET API works
// create an xcb window
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
xcb_window_t windowId = xcb_generate_id(c.get());
xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, 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.get(), windowId, &hints);
// let's set a no-border
NETWinInfo winInfo(c.get(), windowId, rootWindow(), NET::WMWindowType, NET::Properties2());
winInfo.setWindowType(NET::Override);
xcb_map_window(c.get(), windowId);
xcb_flush(c.get());
QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
QVERIFY(windowCreatedSpy.wait());
X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
QVERIFY(window);
QCOMPARE(window->window(), windowId);
const QRectF origGeo = window->frameGeometry();
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QVERIFY(!workspace()->moveResizeWindow());
// use NETRootInfo to trigger a move request
quint32 timestamp = 0;
Test::pointerMotion(window->frameGeometry().center(), timestamp++);
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(windowId, origGeo.center().x(), origGeo.center().y(), NET::Move, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(workspace()->moveResizeWindow(), window);
QVERIFY(window->isInteractiveMove());
QCOMPARE(window->geometryRestore(), origGeo);
QCOMPARE(Cursors::self()->mouse()->pos(), origGeo.center());
// let's move a step
Test::pointerMotionRelative(QPoint(10, 10), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(interactiveMoveResizeSteppedSpy.first().last(), origGeo.translated(10, 10));
// let's cancel the move resize again through the net API
root.moveResizeRequest(windowId, window->frameGeometry().center().x(), window->frameGeometry().center().y(), NET::MoveResizeCancel, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
QVERIFY(interactiveMoveResizeFinishedSpy.wait());
// and destroy the window again
xcb_unmap_window(c.get(), windowId);
xcb_destroy_window(c.get(), windowId);
xcb_flush(c.get());
c.reset();
QSignalSpy windowClosedSpy(window, &X11Window::closed);
QVERIFY(windowClosedSpy.wait());
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
}
void MoveResizeWindowTest::testAdjustClientGeometryOfHiddenX11Panel_data() void MoveResizeWindowTest::testAdjustClientGeometryOfHiddenX11Panel_data()
{ {
QTest::addColumn<QRect>("panelGeometry"); QTest::addColumn<QRect>("panelGeometry");

View file

@ -19,6 +19,7 @@
#include <KWayland/Client/surface.h> #include <KWayland/Client/surface.h>
#include <linux/input-event-codes.h>
#include <netwm.h> #include <netwm.h>
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
@ -79,6 +80,17 @@ private Q_SLOTS:
void testOnAllDesktops(); void testOnAllDesktops();
void testInitialOnAllDesktops(); void testInitialOnAllDesktops();
void testChangeOnAllDesktops(); void testChangeOnAllDesktops();
void testNetWmKeyboardMove();
void testNetWmKeyboardMoveCancel();
void testNetWmKeyboardResize();
void testNetWmKeyboardResizeCancel();
void testNetWmButtonMove();
void testNetWmButtonMoveNotPressed();
void testNetWmButtonMoveCancel();
void testNetWmButtonSize_data();
void testNetWmButtonSize();
void testNetWmButtonSizeNotPressed();
void testNetWmButtonSizeCancel();
void testMinimumSize(); void testMinimumSize();
void testMaximumSize(); void testMaximumSize();
void testTrimCaption_data(); void testTrimCaption_data();
@ -1359,6 +1371,433 @@ void X11WindowTest::testChangeOnAllDesktops()
QCOMPARE(window->desktops(), (QList<VirtualDesktop *>{VirtualDesktopManager::self()->desktopForX11Id(1)})); QCOMPARE(window->desktops(), (QList<VirtualDesktop *>{VirtualDesktopManager::self()->desktopForX11Id(1)}));
} }
void X11WindowTest::testNetWmKeyboardMove()
{
// This test verifies that a client can initiate a keyboard interactive move operation.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::KeyboardMove, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveMove());
// Move the window to the right.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_RIGHT, timestamp++);
Test::keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.translated(8, 0));
// Finish the interactive move.
Test::keyboardKeyPressed(KEY_ENTER, timestamp++);
Test::keyboardKeyReleased(KEY_ENTER, timestamp++);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.translated(8, 0));
}
void X11WindowTest::testNetWmKeyboardMoveCancel()
{
// This test verifies that a client can initiate a keyboard interactive move operation and then cancel it.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::KeyboardMove, XCB_BUTTON_INDEX_ANY);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveMove());
// Move the window to the right.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_RIGHT, timestamp++);
Test::keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.translated(8, 0));
// Cancel the interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::MoveResizeCancel, XCB_BUTTON_INDEX_ANY);
xcb_flush(c.get());
}
QVERIFY(interactiveMoveResizeFinishedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry);
}
void X11WindowTest::testNetWmKeyboardResize()
{
// This test verifies that a client can initiate a keyboard interactive resize operation.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive resize.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width()), Xcb::toXNative(window->y() + window->height()), NET::KeyboardSize, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QSignalSpy frameGeometryChangedSpy(window, &X11Window::frameGeometryChanged);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveResize());
// Move the window to the right, the frame geometry will be updated some time later.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_RIGHT, timestamp++);
Test::keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry.adjusted(0, 0, 8, 0));
// Finish the interactive move.
Test::keyboardKeyPressed(KEY_ENTER, timestamp++);
Test::keyboardKeyReleased(KEY_ENTER, timestamp++);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.adjusted(0, 0, 8, 0));
}
void X11WindowTest::testNetWmKeyboardResizeCancel()
{
// This test verifies that a client can initiate a keyboard interactive resize operation and then cancel it.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive resize.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width()), Xcb::toXNative(window->y() + window->height()), NET::KeyboardSize, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QSignalSpy frameGeometryChangedSpy(window, &X11Window::frameGeometryChanged);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveResize());
// Move the window to the right, the frame geometry will be updated some time later.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_RIGHT, timestamp++);
Test::keyboardKeyReleased(KEY_RIGHT, timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry.adjusted(0, 0, 8, 0));
// Cancel the interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width()), Xcb::toXNative(window->y() + window->height()), NET::MoveResizeCancel, XCB_BUTTON_INDEX_ANY);
xcb_flush(c.get());
}
QVERIFY(interactiveMoveResizeFinishedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry);
}
void X11WindowTest::testNetWmButtonMove()
{
// This test verifies that a client can initiate an interactive move operation controlled by the pointer.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::Move, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveMove());
// Move the window to the right.
Test::pointerMotionRelative(QPointF(8, 0), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.translated(8, 0));
// Finish the interactive move.
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.translated(8, 0));
}
void X11WindowTest::testNetWmButtonMoveNotPressed()
{
// This test verifies that an interactive move operation won't be started if the specified button is not pressed.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::Move, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QVERIFY(!interactiveMoveResizeStartedSpy.wait(10));
}
void X11WindowTest::testNetWmButtonMoveCancel()
{
// This test verifies that a client can initiate an interactive move operation controlled by the pointer and then cancel it.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
auto releaseButton = qScopeGuard([&timestamp]() {
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
});
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::Move, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveMove());
// Move the window to the right.
Test::pointerMotionRelative(QPointF(8, 0), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), originalGeometry.translated(8, 0));
// Cancel the interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x() + window->width() / 2), Xcb::toXNative(window->y() + window->height() / 2), NET::MoveResizeCancel, XCB_BUTTON_INDEX_ANY);
xcb_flush(c.get());
}
QVERIFY(interactiveMoveResizeFinishedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry);
}
void X11WindowTest::testNetWmButtonSize_data()
{
QTest::addColumn<Gravity>("gravity");
QTest::addColumn<NET::Direction>("direction");
QTest::addRow("top-left") << Gravity::TopLeft << NET::Direction::TopLeft;
QTest::addRow("top") << Gravity::Top << NET::Direction::Top;
QTest::addRow("top-right") << Gravity::TopRight << NET::Direction::TopRight;
QTest::addRow("right") << Gravity::Right << NET::Direction::Right;
QTest::addRow("bottom-right") << Gravity::BottomRight << NET::Direction::BottomRight;
QTest::addRow("bottom") << Gravity::Bottom << NET::Direction::Bottom;
QTest::addRow("bottom-left") << Gravity::BottomLeft << NET::Direction::BottomLeft;
QTest::addRow("left") << Gravity::Left << NET::Direction::Left;
}
static QPointF directionToVector(NET::Direction direction, const QSizeF &size)
{
switch (direction) {
case NET::Direction::TopLeft:
return QPointF(-size.width(), -size.height());
case NET::Direction::Top:
return QPointF(0, -size.height());
case NET::Direction::TopRight:
return QPointF(size.width(), -size.height());
case NET::Direction::Right:
return QPointF(size.width(), 0);
case NET::Direction::BottomRight:
return QPointF(size.width(), size.height());
case NET::Direction::Bottom:
return QPointF(0, size.height());
case NET::Direction::BottomLeft:
return QPointF(-size.width(), size.height());
case NET::Direction::Left:
return QPointF(-size.width(), 0);
default:
Q_UNREACHABLE();
}
}
static QRectF expandRect(const QRectF &rect, NET::Direction direction, const QSizeF &amount)
{
switch (direction) {
case NET::Direction::TopLeft:
return rect.adjusted(-amount.width(), -amount.height(), 0, 0);
case NET::Direction::Top:
return rect.adjusted(0, -amount.height(), 0, 0);
case NET::Direction::TopRight:
return rect.adjusted(0, -amount.height(), amount.width(), 0);
case NET::Direction::Right:
return rect.adjusted(0, 0, amount.width(), 0);
case NET::Direction::BottomRight:
return rect.adjusted(0, 0, amount.width(), amount.height());
case NET::Direction::Bottom:
return rect.adjusted(0, 0, 0, amount.height());
case NET::Direction::BottomLeft:
return rect.adjusted(-amount.width(), 0, 0, amount.height());
case NET::Direction::Left:
return rect.adjusted(-amount.width(), 0, 0, 0);
default:
Q_UNREACHABLE();
}
}
void X11WindowTest::testNetWmButtonSize()
{
// This test verifies that a client can initiate an interactive move operation controlled by the pointer.
QFETCH(NET::Direction, direction);
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
const QRectF originalGeometry = window->frameGeometry();
const QPointF initialPointer = window->frameGeometry().center() + directionToVector(direction, originalGeometry.size() * 0.5);
quint32 timestamp = 0;
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
Test::pointerMotion(initialPointer, timestamp++);
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(initialPointer.x()), Xcb::toXNative(initialPointer.y()), direction, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QSignalSpy frameGeometryChangedSpy(window, &X11Window::frameGeometryChanged);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveResize());
QTEST(window->interactiveMoveResizeGravity(), "gravity");
// Resize the window a tiny bit.
Test::pointerMotionRelative(directionToVector(direction, QSizeF(8, 8)), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), expandRect(originalGeometry, direction, QSizeF(8, 8)));
// Finish the interactive move.
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
QCOMPARE(interactiveMoveResizeFinishedSpy.count(), 1);
QCOMPARE(window->frameGeometry(), expandRect(originalGeometry, direction, QSizeF(8, 8)));
}
void X11WindowTest::testNetWmButtonSizeNotPressed()
{
// This test verifies that an interactive siize operation won't be started if the specified button is not pressed.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive move.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x()), Xcb::toXNative(window->y()), NET::TopLeft, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QVERIFY(!interactiveMoveResizeStartedSpy.wait(10));
}
void X11WindowTest::testNetWmButtonSizeCancel()
{
// This test verifies that a client can start an interactive resize and then cancel it.
// Create an xcb window.
Test::XcbConnectionPtr c = Test::createX11Connection();
QVERIFY(!xcb_connection_has_error(c.get()));
X11Window *window = createWindow(c.get(), QRect(100, 100, 100, 200));
// Request interactive resize.
const QRectF originalGeometry = window->frameGeometry();
quint32 timestamp = 0;
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
auto releaseButton = qScopeGuard([&timestamp]() {
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
});
Test::pointerMotion(originalGeometry.topLeft(), timestamp++);
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x()), Xcb::toXNative(window->y()), NET::TopLeft, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QSignalSpy interactiveMoveResizeStartedSpy(window, &X11Window::interactiveMoveResizeStarted);
QSignalSpy interactiveMoveResizeFinishedSpy(window, &X11Window::interactiveMoveResizeFinished);
QSignalSpy interactiveMoveResizeSteppedSpy(window, &X11Window::interactiveMoveResizeStepped);
QSignalSpy frameGeometryChangedSpy(window, &X11Window::frameGeometryChanged);
QVERIFY(interactiveMoveResizeStartedSpy.wait());
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 0);
QVERIFY(window->isInteractiveResize());
// Resize the window a tiny bit.
Test::pointerMotionRelative(QPointF(-8, -8), timestamp++);
QCOMPARE(interactiveMoveResizeSteppedSpy.count(), 1);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry.adjusted(-8, -8, 0, 0));
// Cancel the interactive resize.
{
NETRootInfo root(c.get(), NET::Properties());
root.moveResizeRequest(window->window(), Xcb::toXNative(window->x()), Xcb::toXNative(window->y()), NET::MoveResizeCancel, XCB_BUTTON_INDEX_1);
xcb_flush(c.get());
}
QVERIFY(interactiveMoveResizeFinishedSpy.wait());
QCOMPARE(window->frameGeometry(), originalGeometry);
}
void X11WindowTest::testMinimumSize() void X11WindowTest::testMinimumSize()
{ {
// This test verifies that the minimum size constraint is correctly applied. // This test verifies that the minimum size constraint is correctly applied.

View file

@ -1115,6 +1115,10 @@ public:
{ {
return isInteractiveMoveResize() && interactiveMoveResizeGravity() != Gravity::None; return isInteractiveMoveResize() && interactiveMoveResizeGravity() != Gravity::None;
} }
Gravity interactiveMoveResizeGravity() const
{
return m_interactiveMoveResize.gravity;
}
QPointF interactiveMoveResizeAnchor() const QPointF interactiveMoveResizeAnchor() const
{ {
return m_interactiveMoveResize.anchor; return m_interactiveMoveResize.anchor;
@ -1618,10 +1622,6 @@ protected:
return m_interactiveMoveResize.initialGeometry; return m_interactiveMoveResize.initialGeometry;
} }
void setMoveResizeGeometry(const QRectF &geo); void setMoveResizeGeometry(const QRectF &geo);
Gravity interactiveMoveResizeGravity() const
{
return m_interactiveMoveResize.gravity;
}
void setInteractiveMoveResizeGravity(Gravity gravity) void setInteractiveMoveResizeGravity(Gravity gravity)
{ {
m_interactiveMoveResize.gravity = gravity; m_interactiveMoveResize.gravity = gravity;