20#include <QRasterWindow>
23#include <KWayland/Client/keyboard.h>
24#include <KWayland/Client/seat.h>
25#include <KWayland/Client/surface.h>
26#include <KWindowSystem>
28#include <linux/input.h>
33static const QString s_socketName = QStringLiteral(
"wayland_test_kwin_internal_window-0");
42 void testEnterLeave();
43 void testPointerPressRelease();
44 void testPointerAxis();
45 void testKeyboard_data();
47 void testKeyboardShowWithoutActivating();
48 void testKeyboardTriggersLeave();
52 void testSkipCloseAnimation_data();
53 void testSkipCloseAnimation();
54 void testModifierClickUnrestrictedMove();
55 void testModifierScroll();
58 void testEffectWindow();
59 void testReentrantMoveResize();
60 void testDismissPopup();
72 return m_latestGlobalMousePos;
76 return m_pressedButtons;
100 QPoint m_latestGlobalMousePos;
101 Qt::MouseButtons m_pressedButtons = Qt::MouseButtons();
105 : QRasterWindow(nullptr)
107 setFlags(Qt::FramelessWindowHint);
115 p.fillRect(0, 0, width(), height(), Qt::red);
120 if (
event->type() == QEvent::Enter) {
123 if (
event->type() == QEvent::Leave) {
126 return QRasterWindow::event(
event);
131 m_latestGlobalMousePos =
event->globalPos();
137 m_latestGlobalMousePos =
event->globalPos();
138 m_pressedButtons =
event->buttons();
144 m_latestGlobalMousePos =
event->globalPos();
145 m_pressedButtons =
event->buttons();
164void InternalWindowTest::initTestCase()
166 qRegisterMetaType<KWin::Window *>();
167 qRegisterMetaType<KWin::InternalWindow *>();
171 QRect(0, 0, 1280, 1024),
172 QRect(1280, 0, 1280, 1024),
174 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
177 QVERIFY(applicationStartedSpy.wait());
179 QCOMPARE(outputs.count(), 2);
180 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
181 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
184void InternalWindowTest::init()
191void InternalWindowTest::cleanup()
196void InternalWindowTest::testEnterLeave()
200 QVERIFY(!
workspace()->findInternal(
nullptr));
201 QVERIFY(!
workspace()->findInternal(&win));
202 win.setGeometry(0, 0, 100, 100);
205 QTRY_COMPARE(windowAddedSpy.count(), 1);
207 InternalWindow *window = windowAddedSpy.first().first().value<InternalWindow *>();
209 QVERIFY(window->isInternal());
210 QVERIFY(!window->isDecorated());
211 QCOMPARE(
workspace()->findInternal(&win), window);
212 QCOMPARE(window->frameGeometry(), QRect(0, 0, 100, 100));
213 QVERIFY(window->isShown());
214 QVERIFY(
workspace()->stackingOrder().contains(window));
220 quint32 timestamp = 1;
222 QTRY_COMPARE(moveSpy.count(), 1);
225 QTRY_COMPARE(moveSpy.count(), 2);
226 QCOMPARE(moveSpy[1].first().toPoint(), QPoint(60, 50));
229 QTRY_COMPARE(leaveSpy.count(), 1);
232 win.setMask(QRegion(10, 20, 30, 40));
235 QVERIFY(!enterSpy.wait(100));
236 QCOMPARE(enterSpy.count(), 1);
239 QTRY_COMPARE(enterSpy.count(), 2);
242void InternalWindowTest::testPointerPressRelease()
246 win.setGeometry(0, 0, 100, 100);
251 QTRY_COMPARE(windowAddedSpy.count(), 1);
253 quint32 timestamp = 1;
257 QTRY_COMPARE(pressSpy.count(), 1);
259 QTRY_COMPARE(releaseSpy.count(), 1);
262void InternalWindowTest::testPointerAxis()
266 win.setGeometry(0, 0, 100, 100);
269 QTRY_COMPARE(windowAddedSpy.count(), 1);
271 quint32 timestamp = 1;
275 QTRY_COMPARE(wheelSpy.count(), 1);
277 QTRY_COMPARE(wheelSpy.count(), 2);
280void InternalWindowTest::testKeyboard_data()
282 QTest::addColumn<QPoint>(
"cursorPos");
284 QTest::newRow(
"on Window") << QPoint(50, 50);
285 QTest::newRow(
"outside Window") << QPoint(250, 250);
288void InternalWindowTest::testKeyboard()
292 win.setGeometry(0, 0, 100, 100);
296 QTRY_COMPARE(windowAddedSpy.count(), 1);
297 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
298 QVERIFY(internalWindow);
299 QVERIFY(internalWindow->isInternal());
300 QVERIFY(internalWindow->readyForPainting());
302 quint32 timestamp = 1;
303 QFETCH(QPoint, cursorPos);
307 QTRY_COMPARE(pressSpy.count(), 1);
308 QCOMPARE(releaseSpy.count(), 0);
310 QTRY_COMPARE(releaseSpy.count(), 1);
311 QCOMPARE(pressSpy.count(), 1);
314void InternalWindowTest::testKeyboardShowWithoutActivating()
318 win.setProperty(
"_q_showWithoutActivating",
true);
319 win.setGeometry(0, 0, 100, 100);
323 QTRY_COMPARE(windowAddedSpy.count(), 1);
324 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
325 QVERIFY(internalWindow);
326 QVERIFY(internalWindow->isInternal());
327 QVERIFY(internalWindow->readyForPainting());
329 quint32 timestamp = 1;
330 const QPoint cursorPos = QPoint(50, 50);
334 QCOMPARE(pressSpy.count(), 0);
335 QVERIFY(!pressSpy.wait(100));
336 QCOMPARE(releaseSpy.count(), 0);
338 QCOMPARE(releaseSpy.count(), 0);
339 QVERIFY(!releaseSpy.wait(100));
340 QCOMPARE(pressSpy.count(), 0);
343void InternalWindowTest::testKeyboardTriggersLeave()
347 std::unique_ptr<KWayland::Client::Keyboard> keyboard(
Test::waylandSeat()->createKeyboard());
348 QVERIFY(keyboard !=
nullptr);
349 QVERIFY(keyboard->isValid());
350 QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered);
351 QSignalSpy leftSpy(keyboard.get(), &KWayland::Client::Keyboard::left);
358 QVERIFY(window->isActive());
359 QVERIFY(!window->isInternal());
361 if (enteredSpy.isEmpty()) {
362 QVERIFY(enteredSpy.wait());
364 QCOMPARE(enteredSpy.count(), 1);
369 win.setGeometry(0, 0, 100, 100);
373 QTRY_COMPARE(windowAddedSpy.count(), 1);
374 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
375 QVERIFY(internalWindow);
376 QVERIFY(internalWindow->isInternal());
377 QVERIFY(internalWindow->readyForPainting());
379 QVERIFY(leftSpy.isEmpty());
380 QVERIFY(!leftSpy.wait(100));
383 quint32 timestamp = 1;
385 QVERIFY(leftSpy.wait());
386 QCOMPARE(pressSpy.count(), 1);
389 QTRY_COMPARE(releaseSpy.count(), 1);
394 QVERIFY(enteredSpy.wait());
398 shellSurface.reset();
402void InternalWindowTest::testTouch()
407 win.setGeometry(0, 0, 100, 100);
409 QTRY_COMPARE(windowAddedSpy.count(), 1);
415 quint32 timestamp = 1;
416 QCOMPARE(win.pressedButtons(), Qt::MouseButtons());
418 QCOMPARE(pressSpy.count(), 1);
419 QCOMPARE(win.latestGlobalMousePos(), QPoint(50, 50));
420 QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton));
424 QCOMPARE(pressSpy.count(), 1);
426 QCOMPARE(releaseSpy.count(), 0);
427 QCOMPARE(win.latestGlobalMousePos(), QPoint(50, 50));
428 QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton));
432 QCOMPARE(pressSpy.count(), 1);
433 QCOMPARE(win.latestGlobalMousePos(), QPoint(50, 50));
434 QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton));
437 QCOMPARE(moveSpy.count(), 0);
439 QCOMPARE(moveSpy.count(), 1);
440 QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90));
441 QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton));
445 QCOMPARE(moveSpy.count(), 1);
446 QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90));
447 QCOMPARE(win.pressedButtons(), Qt::MouseButtons(Qt::LeftButton));
451 QCOMPARE(releaseSpy.count(), 1);
452 QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90));
453 QCOMPARE(win.pressedButtons(), Qt::MouseButtons());
457 QCOMPARE(releaseSpy.count(), 1);
458 QCOMPARE(moveSpy.count(), 1);
459 QCOMPARE(win.latestGlobalMousePos(), QPoint(80, 90));
460 QCOMPARE(win.pressedButtons(), Qt::MouseButtons());
463void InternalWindowTest::testOpacity()
469 win.setGeometry(0, 0, 100, 100);
471 QTRY_COMPARE(windowAddedSpy.count(), 1);
472 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
473 QVERIFY(internalWindow);
474 QVERIFY(internalWindow->isInternal());
475 QCOMPARE(internalWindow->opacity(), 0.5);
478 win.setOpacity(0.75);
479 QCOMPARE(opacityChangedSpy.count(), 1);
480 QCOMPARE(internalWindow->opacity(), 0.75);
483void InternalWindowTest::testMove()
488 win.setGeometry(0, 0, 100, 100);
490 QTRY_COMPARE(windowAddedSpy.count(), 1);
491 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
492 QVERIFY(internalWindow);
493 QCOMPARE(internalWindow->frameGeometry(), QRect(0, 0, 100, 100));
496 internalWindow->move(QPoint(5, 10));
497 QCOMPARE(internalWindow->frameGeometry(), QRect(5, 10, 100, 100));
498 QTRY_COMPARE(win.geometry(), QRect(5, 10, 100, 100));
500 internalWindow->move(QPoint(10, 20));
501 QCOMPARE(internalWindow->frameGeometry(), QRect(10, 20, 100, 100));
502 QTRY_COMPARE(win.geometry(), QRect(10, 20, 100, 100));
506 GeometryUpdatesBlocker blocker(internalWindow);
507 internalWindow->move(QPoint(5, 10));
509 QCOMPARE(win.geometry(), QRect(10, 20, 100, 100));
512 QTRY_COMPARE(win.geometry(), QRect(5, 10, 100, 100));
515void InternalWindowTest::testSkipCloseAnimation_data()
517 QTest::addColumn<bool>(
"initial");
519 QTest::newRow(
"set") <<
true;
520 QTest::newRow(
"not set") <<
false;
523void InternalWindowTest::testSkipCloseAnimation()
528 win.setGeometry(0, 0, 100, 100);
529 QFETCH(
bool, initial);
530 win.setProperty(
"KWIN_SKIP_CLOSE_ANIMATION", initial);
532 QTRY_COMPARE(windowAddedSpy.count(), 1);
533 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
534 QVERIFY(internalWindow);
535 QCOMPARE(internalWindow->skipsCloseAnimation(), initial);
537 win.setProperty(
"KWIN_SKIP_CLOSE_ANIMATION", !initial);
538 QCOMPARE(skipCloseChangedSpy.count(), 1);
539 QCOMPARE(internalWindow->skipsCloseAnimation(), !initial);
540 win.setProperty(
"KWIN_SKIP_CLOSE_ANIMATION", initial);
541 QCOMPARE(skipCloseChangedSpy.count(), 2);
542 QCOMPARE(internalWindow->skipsCloseAnimation(), initial);
545void InternalWindowTest::testModifierClickUnrestrictedMove()
549 win.setGeometry(0, 0, 100, 100);
550 win.setFlags(win.flags() & ~Qt::FramelessWindowHint);
552 QTRY_COMPARE(windowAddedSpy.count(), 1);
553 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
554 QVERIFY(internalWindow);
555 QVERIFY(internalWindow->isDecorated());
557 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"MouseBindings"));
558 group.writeEntry(
"CommandAllKey",
"Meta");
559 group.writeEntry(
"CommandAll1",
"Move");
560 group.writeEntry(
"CommandAll2",
"Move");
561 group.writeEntry(
"CommandAll3",
"Move");
573 quint32 timestamp = 1;
575 QVERIFY(!internalWindow->isInteractiveMove());
577 QVERIFY(internalWindow->isInteractiveMove());
580 QVERIFY(internalWindow->isInteractiveMove());
583 QVERIFY(!internalWindow->isInteractiveMove());
586void InternalWindowTest::testModifierScroll()
590 win.setGeometry(0, 0, 100, 100);
591 win.setFlags(win.flags() & ~Qt::FramelessWindowHint);
593 QTRY_COMPARE(windowAddedSpy.count(), 1);
594 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
595 QVERIFY(internalWindow);
596 QVERIFY(internalWindow->isDecorated());
598 KConfigGroup group = kwinApp()->config()->group(QStringLiteral(
"MouseBindings"));
599 group.writeEntry(
"CommandAllKey",
"Meta");
600 group.writeEntry(
"CommandAllWheel",
"change opacity");
608 internalWindow->setOpacity(0.5);
609 QCOMPARE(internalWindow->opacity(), 0.5);
610 quint32 timestamp = 1;
613 QCOMPARE(internalWindow->opacity(), 0.6);
615 QCOMPARE(internalWindow->opacity(), 0.5);
619void InternalWindowTest::testPopup()
623 win.setGeometry(0, 0, 100, 100);
624 win.setFlags(win.flags() | Qt::Popup);
626 QTRY_COMPARE(windowAddedSpy.count(), 1);
627 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
628 QVERIFY(internalWindow);
629 QCOMPARE(internalWindow->isPopupWindow(),
true);
632void InternalWindowTest::testScale()
636 .geometry = QRect(0, 0, 1280, 1024),
640 .geometry = QRect(1280, 0, 1280, 1024),
647 win.setGeometry(0, 0, 100, 100);
648 win.setFlags(win.flags() | Qt::Popup);
650 QCOMPARE(win.devicePixelRatio(), 2.0);
651 QTRY_COMPARE(windowAddedSpy.count(), 1);
652 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
653 QCOMPARE(internalWindow->bufferScale(), 2);
656void InternalWindowTest::testEffectWindow()
660 win.setGeometry(0, 0, 100, 100);
662 QTRY_COMPARE(windowAddedSpy.count(), 1);
663 auto internalWindow = windowAddedSpy.first().first().value<InternalWindow *>();
664 QVERIFY(internalWindow);
665 QVERIFY(internalWindow->effectWindow());
666 QCOMPARE(internalWindow->effectWindow()->internalWindow(), &win);
672void InternalWindowTest::testReentrantMoveResize()
680 win.setGeometry(0, 0, 100, 100);
682 QTRY_COMPARE(windowAddedSpy.count(), 1);
683 auto window = windowAddedSpy.first().first().value<InternalWindow *>();
685 QCOMPARE(window->pos(), QPoint(0, 0));
689 window->moveResize(QRectF(QPointF(100, 100), window->size()));
693 window->move(QPoint(40, 50));
696 QCOMPARE(window->pos(), QPoint(100, 100));
699void InternalWindowTest::testDismissPopup()
706 HelperWindow clientToplevel;
707 clientToplevel.setGeometry(0, 0, 100, 100);
708 clientToplevel.show();
709 QTRY_COMPARE(windowAddedSpy.count(), 1);
710 auto serverToplevel = windowAddedSpy.last().first().value<InternalWindow *>();
711 QVERIFY(serverToplevel);
714 QRasterWindow clientPopup;
715 clientPopup.setFlag(Qt::Popup);
716 clientPopup.setTransientParent(&clientToplevel);
717 clientPopup.setGeometry(0, 0, 50, 50);
719 QTRY_COMPARE(windowAddedSpy.count(), 2);
720 auto serverPopup = windowAddedSpy.last().first().value<InternalWindow *>();
721 QVERIFY(serverPopup);
724 HelperWindow otherClientToplevel;
725 otherClientToplevel.setGeometry(100, 100, 100, 100);
726 otherClientToplevel.show();
727 QTRY_COMPARE(windowAddedSpy.count(), 3);
728 auto serverOtherToplevel = windowAddedSpy.last().first().value<InternalWindow *>();
729 QVERIFY(serverOtherToplevel);
733 quint32 timestamp = 0;
736 QTRY_COMPARE(popupClosedSpy.count(), 1);
742#include "internal_window.moc"
Q_SCRIPTABLE KWin::EffectWindow * findWindow(WId id) const
void paintEvent(QPaintEvent *event) override
void mouseMoveEvent(QMouseEvent *event) override
Qt::MouseButtons pressedButtons() const
~HelperWindow() override=default
bool event(QEvent *event) override
void keyReleaseEvent(QKeyEvent *event) override
void mousePressEvent(QMouseEvent *event) override
QPoint latestGlobalMousePos() const
void keyPressEvent(QKeyEvent *event) override
void mouseReleaseEvent(QMouseEvent *event) override
void mouseMoved(const QPoint &global)
void wheelEvent(QWheelEvent *event) override
Qt::KeyboardModifier commandAllModifier() const
void skipCloseAnimationChanged()
void opacityChanged(KWin::Window *window, qreal oldOpacity)
void frameGeometryChanged(const QRectF &oldGeometry)
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
#define WAYLANDTEST_MAIN(TestObject)
Window * renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32, int timeout=5000)
void keyboardKeyReleased(quint32 key, quint32 time)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
void touchDown(qint32 id, const QPointF &pos, quint32 time)
void pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta=0, InputRedirection::PointerAxisSource source=InputRedirection::PointerAxisSourceUnknown)
void keyboardKeyPressed(quint32 key, quint32 time)
bool waitForWaylandKeyboard()
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void touchMotion(qint32 id, const QPointF &pos, quint32 time)
void pointerAxisHorizontal(qreal delta, quint32 time, qint32 discreteDelta=0, InputRedirection::PointerAxisSource source=InputRedirection::PointerAxisSourceUnknown)
KWayland::Client::Seat * waylandSeat()
void pointerButtonPressed(quint32 button, quint32 time)
void pointerMotion(const QPointF &position, quint32 time)
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
void pointerButtonReleased(quint32 button, quint32 time)
void touchUp(qint32 id, quint32 time)
bool waitForWindowClosed(Window *window)
WaylandServer * waylandServer()
InputRedirection * input()