KWin
Loading...
Searching...
No Matches
input_stacking_order.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "kwin_wayland_test.h"
10
11#include "core/output.h"
12#include "pointer_input.h"
13#include "wayland/seat.h"
14#include "wayland_server.h"
15#include "window.h"
16#include "workspace.h"
17
18#include <KWayland/Client/compositor.h>
19#include <KWayland/Client/connection_thread.h>
20#include <KWayland/Client/event_queue.h>
21#include <KWayland/Client/pointer.h>
22#include <KWayland/Client/registry.h>
23#include <KWayland/Client/seat.h>
24#include <KWayland/Client/shm_pool.h>
25#include <KWayland/Client/surface.h>
26
27#include <QSignalSpy>
28
29namespace KWin
30{
31
32static const QString s_socketName = QStringLiteral("wayland_test_kwin_input_stacking_order-0");
33
34class InputStackingOrderTest : public QObject
35{
36 Q_OBJECT
37private Q_SLOTS:
38 void initTestCase();
39 void init();
40 void cleanup();
41 void testPointerFocusUpdatesOnStackingOrderChange();
42
43private:
44 void render(KWayland::Client::Surface *surface);
45};
46
47void InputStackingOrderTest::initTestCase()
48{
49 qRegisterMetaType<KWin::Window *>();
50 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
51 QVERIFY(waylandServer()->init(s_socketName));
53 QRect(0, 0, 1280, 1024),
54 QRect(1280, 0, 1280, 1024),
55 });
56
57 kwinApp()->start();
58 QVERIFY(applicationStartedSpy.wait());
59 const auto outputs = workspace()->outputs();
60 QCOMPARE(outputs.count(), 2);
61 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
62 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
63 setenv("QT_QPA_PLATFORM", "wayland", true);
64}
65
66void InputStackingOrderTest::init()
67{
70
71 workspace()->setActiveOutput(QPoint(640, 512));
72 input()->pointer()->warp(QPoint(640, 512));
73}
74
75void InputStackingOrderTest::cleanup()
76{
78}
79
80void InputStackingOrderTest::render(KWayland::Client::Surface *surface)
81{
82 Test::render(surface, QSize(100, 50), Qt::blue);
84}
85
86void InputStackingOrderTest::testPointerFocusUpdatesOnStackingOrderChange()
87{
88 // this test creates two windows which overlap
89 // the pointer is in the overlapping area which means the top most window has focus
90 // as soon as the top most window gets lowered the window should lose focus and the
91 // other window should gain focus without a mouse event in between
92
93 // create pointer and signal spy for enter and leave signals
94 auto pointer = Test::waylandSeat()->createPointer(Test::waylandSeat());
95 QVERIFY(pointer);
96 QVERIFY(pointer->isValid());
97 QSignalSpy enteredSpy(pointer, &KWayland::Client::Pointer::entered);
98 QSignalSpy leftSpy(pointer, &KWayland::Client::Pointer::left);
99
100 // now create the two windows and make them overlap
101 QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
102 std::unique_ptr<KWayland::Client::Surface> surface1 = Test::createSurface();
103 QVERIFY(surface1);
104 Test::XdgToplevel *shellSurface1 = Test::createXdgToplevelSurface(surface1.get(), surface1.get());
105 QVERIFY(shellSurface1);
106 render(surface1.get());
107 QVERIFY(windowAddedSpy.wait());
108 Window *window1 = workspace()->activeWindow();
109 QVERIFY(window1);
110
111 std::unique_ptr<KWayland::Client::Surface> surface2 = Test::createSurface();
112 QVERIFY(surface2);
113 Test::XdgToplevel *shellSurface2 = Test::createXdgToplevelSurface(surface2.get(), surface2.get());
114 QVERIFY(shellSurface2);
115 render(surface2.get());
116 QVERIFY(windowAddedSpy.wait());
117
118 Window *window2 = workspace()->activeWindow();
119 QVERIFY(window2);
120 QVERIFY(window1 != window2);
121
122 // now make windows overlap
123 window2->move(window1->pos());
124 QCOMPARE(window1->frameGeometry(), window2->frameGeometry());
125
126 // enter
127 Test::pointerMotion(QPointF(25, 25), 1);
128 QVERIFY(enteredSpy.wait());
129 QCOMPARE(enteredSpy.count(), 1);
130 // window 2 should have focus
131 QCOMPARE(pointer->enteredSurface(), surface2.get());
132 // also on the server
133 QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window2->surface());
134
135 // raise window 1 above window 2
136 QVERIFY(leftSpy.isEmpty());
137 workspace()->raiseWindow(window1);
138 // should send leave to window2
139 QVERIFY(leftSpy.wait());
140 QCOMPARE(leftSpy.count(), 1);
141 // and an enter to window1
142 QCOMPARE(enteredSpy.count(), 2);
143 QCOMPARE(pointer->enteredSurface(), surface1.get());
144 QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window1->surface());
145
146 // let's destroy window1, that should pass focus to window2 again
147 QSignalSpy windowClosedSpy(window1, &Window::closed);
148 surface1.reset();
149 QVERIFY(windowClosedSpy.wait());
150 QVERIFY(enteredSpy.wait());
151 QCOMPARE(enteredSpy.count(), 3);
152 QCOMPARE(pointer->enteredSurface(), surface2.get());
153 QCOMPARE(waylandServer()->seat()->focusedPointerSurface(), window2->surface());
154}
155
156}
157
159#include "input_stacking_order.moc"
PointerInputRedirection * pointer() const
Definition input.h:220
void warp(const QPointF &pos)
Window * activeWindow() const
Definition workspace.h:767
void raiseWindow(Window *window, bool nogroup=false)
Definition layers.cpp:354
void windowAdded(KWin::Window *)
QList< Output * > outputs() const
Definition workspace.h:762
void setActiveOutput(Output *output)
#define WAYLANDTEST_MAIN(TestObject)
void destroyWaylandConnection()
void setOutputConfig(const QList< QRect > &geometries)
KWayland::Client::Seat * seat
bool setupWaylandConnection(AdditionalWaylandInterfaces flags=AdditionalWaylandInterfaces())
void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format=QImage::Format_ARGB32_Premultiplied)
KWayland::Client::Seat * waylandSeat()
void pointerMotion(const QPointF &position, quint32 time)
std::unique_ptr< KWayland::Client::Surface > createSurface()
XdgToplevel * createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent=nullptr)
bool waitForWaylandPointer()
void flushWaylandConnection()
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549