17#include "KWayland/Client/compositor.h"
18#include "KWayland/Client/connection_thread.h"
19#include "KWayland/Client/event_queue.h"
20#include "KWayland/Client/registry.h"
21#include "KWayland/Client/seat.h"
22#include "KWayland/Client/surface.h"
24#include "qwayland-text-input-unstable-v1.h"
44 Q_EMIT surface_enter(surface);
48 Q_EMIT surface_leave();
52 Q_EMIT commit_string(text);
56 Q_EMIT delete_surrounding_text(index, length);
60 Q_EMIT preedit_string(text, commit);
81 void testEnableDisable();
83 void testContentPurpose_data();
84 void testContentPurpose();
85 void testContentHints_data();
86 void testContentHints();
89 KWayland::Client::ConnectionThread *m_connection =
nullptr;
90 KWayland::Client::EventQueue *m_queue =
nullptr;
91 KWayland::Client::Compositor *m_clientCompositor =
nullptr;
92 KWayland::Client::Seat *m_clientSeat =
nullptr;
102 quint32 m_totalCommits = 0;
105static const QString s_socketName = QStringLiteral(
"kwin-wayland-server-text-input-v1-test-0");
107void TestTextInputV1Interface::initTestCase()
119 m_connection =
new KWayland::Client::ConnectionThread;
120 QSignalSpy connectedSpy(m_connection, &KWayland::Client::ConnectionThread::connected);
121 m_connection->setSocketName(s_socketName);
123 m_thread =
new QThread(
this);
124 m_connection->moveToThread(m_thread);
127 m_connection->initConnection();
128 QVERIFY(connectedSpy.wait());
129 QVERIFY(!m_connection->connections().isEmpty());
131 m_queue =
new KWayland::Client::EventQueue(
this);
132 QVERIFY(!m_queue->isValid());
133 m_queue->setup(m_connection);
134 QVERIFY(m_queue->isValid());
136 auto registry =
new KWayland::Client::Registry(
this);
137 connect(registry, &KWayland::Client::Registry::interfaceAnnounced,
this, [
this, registry](
const QByteArray &interface, quint32
id, quint32
version) {
138 if (interface == QByteArrayLiteral(
"zwp_text_input_manager_v1")) {
140 m_clientTextInputManagerV1->init(*registry,
id,
version);
144 connect(registry, &KWayland::Client::Registry::seatAnnounced,
this, [
this, registry](quint32 name, quint32
version) {
148 QSignalSpy allAnnouncedSpy(registry, &KWayland::Client::Registry::interfaceAnnounced);
149 QSignalSpy compositorSpy(registry, &KWayland::Client::Registry::compositorAnnounced);
150 QSignalSpy shmSpy(registry, &KWayland::Client::Registry::shmAnnounced);
152 registry->create(m_connection->display());
155 QVERIFY(allAnnouncedSpy.wait());
157 m_clientCompositor =
registry->createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(),
this);
158 QVERIFY(m_clientCompositor->isValid());
161 m_clientTextInputV1->init(m_clientTextInputManagerV1->create_text_input());
162 QVERIFY(m_clientTextInputV1);
167 if (m_clientTextInputV1) {
168 delete m_clientTextInputV1;
169 m_clientTextInputV1 =
nullptr;
171 if (m_clientTextInputManagerV1) {
172 delete m_clientTextInputManagerV1;
173 m_clientTextInputManagerV1 =
nullptr;
185 m_connection->deleteLater();
186 m_connection =
nullptr;
190void TestTextInputV1Interface::testEnableDisable()
194 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
195 QVERIFY(serverSurfaceCreatedSpy.wait());
197 QVERIFY(serverSurface);
200 QVERIFY(m_serverTextInputV1);
211 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
215 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
216 QCOMPARE(surfaceEnterSpy.count(), 0);
217 QCOMPARE(textInputEnabledSpy.count(), 0);
220 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
221 m_clientTextInputV1->set_cursor_rectangle(0, 0, 20, 20);
222 m_clientTextInputV1->set_surrounding_text(
"KDE Plasma Desktop", 0, 3);
223 QVERIFY(surfaceEnterSpy.wait());
225 QCOMPARE(textInputEnabledSpy.count(), 1);
226 QCOMPARE(cursorRectangleChangedSpy.count(), 1);
228 QCOMPARE(m_serverTextInputV1->
surroundingText(), QString(
"KDE Plasma Desktop"));
233 m_clientTextInputV1->deactivate(*m_clientSeat);
234 QVERIFY(textInputEnabledSpy.wait());
235 QCOMPARE(textInputEnabledSpy.count(), 2);
236 QVERIFY(surfaceLeaveSpy.wait());
240 QCOMPARE(surfaceLeaveSpy.count(), 1);
243void TestTextInputV1Interface::testEvents()
247 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
248 QVERIFY(serverSurfaceCreatedSpy.wait());
250 QVERIFY(serverSurface);
253 QVERIFY(m_serverTextInputV1);
259 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
265 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
268 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
269 QVERIFY(textInputEnabledSpy.wait());
275 m_serverTextInputV1->
preEdit(
"Hello KDE community!",
"Hello");
280 QVERIFY(commitStringSpy.wait());
282 QCOMPARE(preEditSpy.last().at(0).value<QString>(),
"Hello KDE community!");
283 QCOMPARE(preEditSpy.last().at(1).value<QString>(),
"Hello");
284 QCOMPARE(commitStringSpy.last().at(0).value<QString>(),
"Plasma");
285 QCOMPARE(deleteSurroundingSpy.last().at(0).value<quint32>(), 6);
286 QCOMPARE(deleteSurroundingSpy.last().at(1).value<quint32>(), 10);
289 m_clientTextInputV1->deactivate(*m_clientSeat);
290 QVERIFY(textInputEnabledSpy.wait());
293void TestTextInputV1Interface::testContentPurpose_data()
295 QTest::addColumn<QtWayland::zwp_text_input_v1::content_purpose>(
"clientPurpose");
296 QTest::addColumn<KWin::TextInputContentPurpose>(
"serverPurpose");
298 QTest::newRow(
"Alpha") << QtWayland::zwp_text_input_v1::content_purpose_alpha << TextInputContentPurpose::Alpha;
299 QTest::newRow(
"Digits") << QtWayland::zwp_text_input_v1::content_purpose_digits << TextInputContentPurpose::Digits;
300 QTest::newRow(
"Number") << QtWayland::zwp_text_input_v1::content_purpose_number << TextInputContentPurpose::Number;
301 QTest::newRow(
"Phone") << QtWayland::zwp_text_input_v1::content_purpose_phone << TextInputContentPurpose::Phone;
302 QTest::newRow(
"Url") << QtWayland::zwp_text_input_v1::content_purpose_url << TextInputContentPurpose::Url;
303 QTest::newRow(
"Email") << QtWayland::zwp_text_input_v1::content_purpose_email << TextInputContentPurpose::Email;
304 QTest::newRow(
"Name") << QtWayland::zwp_text_input_v1::content_purpose_name << TextInputContentPurpose::Name;
305 QTest::newRow(
"Password") << QtWayland::zwp_text_input_v1::content_purpose_password << TextInputContentPurpose::Password;
306 QTest::newRow(
"Date") << QtWayland::zwp_text_input_v1::content_purpose_date << TextInputContentPurpose::Date;
307 QTest::newRow(
"Time") << QtWayland::zwp_text_input_v1::content_purpose_time << TextInputContentPurpose::Time;
308 QTest::newRow(
"DateTime") << QtWayland::zwp_text_input_v1::content_purpose_datetime << TextInputContentPurpose::DateTime;
309 QTest::newRow(
"Terminal") << QtWayland::zwp_text_input_v1::content_purpose_terminal << TextInputContentPurpose::Terminal;
312void TestTextInputV1Interface::testContentPurpose()
316 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
317 QVERIFY(serverSurfaceCreatedSpy.wait());
319 QVERIFY(serverSurface);
322 QVERIFY(m_serverTextInputV1);
328 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
334 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
337 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
338 QVERIFY(textInputEnabledSpy.wait());
342 QCOMPARE(m_serverTextInputV1->
contentPurpose(), TextInputContentPurpose::Normal);
346 QFETCH(QtWayland::zwp_text_input_v1::content_purpose, clientPurpose);
347 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
348 m_clientTextInputV1->set_content_type(QtWayland::zwp_text_input_v1::content_hint_none, clientPurpose);
349 QVERIFY(contentTypeChangedSpy.wait());
354 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
355 m_clientTextInputV1->set_content_type(QtWayland::zwp_text_input_v1::content_hint_none, clientPurpose);
356 QVERIFY(!contentTypeChangedSpy.wait(100));
360 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
361 m_clientTextInputV1->set_content_type(QtWayland::zwp_text_input_v1::content_hint_none, QtWayland::zwp_text_input_v1::content_purpose_normal);
362 QVERIFY(contentTypeChangedSpy.wait());
364 QCOMPARE(m_serverTextInputV1->
contentPurpose(), TextInputContentPurpose::Normal);
367 m_clientTextInputV1->deactivate(*m_clientSeat);
369 QVERIFY(textInputEnabledSpy.wait());
372void TestTextInputV1Interface::testContentHints_data()
374 QTest::addColumn<quint32>(
"clientHint");
375 QTest::addColumn<KWin::TextInputContentHints>(
"serverHints");
377 QTest::addRow(
"Spellcheck") << quint32(QtWayland::zwp_text_input_v1::content_hint_auto_correction)
378 << TextInputContentHints(TextInputContentHint::AutoCorrection);
379 QTest::addRow(
"Completion") << quint32(QtWayland::zwp_text_input_v1::content_hint_auto_completion)
380 << TextInputContentHints(TextInputContentHint::AutoCompletion);
381 QTest::addRow(
"AutoCapital") << quint32(QtWayland::zwp_text_input_v1::content_hint_auto_capitalization)
382 << TextInputContentHints(TextInputContentHint::AutoCapitalization);
383 QTest::addRow(
"Lowercase") << quint32(QtWayland::zwp_text_input_v1::content_hint_lowercase) << TextInputContentHints(TextInputContentHint::LowerCase);
384 QTest::addRow(
"Uppercase") << quint32(QtWayland::zwp_text_input_v1::content_hint_uppercase) << TextInputContentHints(TextInputContentHint::UpperCase);
385 QTest::addRow(
"Titlecase") << quint32(QtWayland::zwp_text_input_v1::content_hint_titlecase) << TextInputContentHints(TextInputContentHint::TitleCase);
386 QTest::addRow(
"HiddenText") << quint32(QtWayland::zwp_text_input_v1::content_hint_hidden_text) << TextInputContentHints(TextInputContentHint::HiddenText);
387 QTest::addRow(
"SensitiveData") << quint32(QtWayland::zwp_text_input_v1::content_hint_sensitive_data)
388 << TextInputContentHints(TextInputContentHint::SensitiveData);
389 QTest::addRow(
"Latin") << quint32(QtWayland::zwp_text_input_v1::content_hint_latin) << TextInputContentHints(TextInputContentHint::Latin);
390 QTest::addRow(
"Multiline") << quint32(QtWayland::zwp_text_input_v1::content_hint_multiline) << TextInputContentHints(TextInputContentHint::MultiLine);
391 QTest::addRow(
"Auto") << quint32(QtWayland::zwp_text_input_v1::content_hint_auto_completion | QtWayland::zwp_text_input_v1::content_hint_auto_correction
392 | QtWayland::zwp_text_input_v1::content_hint_auto_capitalization)
393 << TextInputContentHints(TextInputContentHint::AutoCompletion | TextInputContentHint::AutoCorrection
394 | TextInputContentHint::AutoCapitalization);
397void TestTextInputV1Interface::testContentHints()
401 std::unique_ptr<KWayland::Client::Surface> clientSurface(m_clientCompositor->createSurface(
this));
402 QVERIFY(serverSurfaceCreatedSpy.wait());
404 QVERIFY(serverSurface);
407 QVERIFY(m_serverTextInputV1);
413 QCOMPARE(focusedSurfaceChangedSpy.count(), 0);
419 QCOMPARE(focusedSurfaceChangedSpy.count(), 1);
422 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
423 QVERIFY(textInputEnabledSpy.wait());
426 QCOMPARE(m_serverTextInputV1->
contentHints(), TextInputContentHint::None);
429 m_clientTextInputV1->deactivate(*m_clientSeat);
430 QVERIFY(textInputEnabledSpy.wait());
435 QFETCH(quint32, clientHint);
436 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
437 m_clientTextInputV1->set_content_type(clientHint, QtWayland::zwp_text_input_v1::content_purpose_normal);
438 QVERIFY(contentTypeChangedSpy.wait());
439 QTEST(m_serverTextInputV1->
contentHints(),
"serverHints");
443 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
444 m_clientTextInputV1->set_content_type(clientHint, QtWayland::zwp_text_input_v1::content_purpose_normal);
445 QVERIFY(!contentTypeChangedSpy.wait(100));
449 m_clientTextInputV1->activate(*m_clientSeat, *clientSurface);
450 m_clientTextInputV1->set_content_type(QtWayland::zwp_text_input_v1::content_hint_none, QtWayland::zwp_text_input_v1::content_purpose_normal);
451 QVERIFY(contentTypeChangedSpy.wait());
455 m_clientTextInputV1->deactivate(*m_clientSeat);
456 QVERIFY(textInputEnabledSpy.wait());
462#include "test_textinputv1_interface.moc"
void surfaceCreated(KWin::SurfaceInterface *surface)
Class holding the Wayland server display loop.
bool addSocketName(const QString &name=QString())
Represents a Seat on the Wayland Display.
TextInputV1Interface * textInputV1() const
void setHasKeyboard(bool has)
void focusedTextInputSurfaceChanged()
void setFocusedTextInputSurface(SurfaceInterface *surface)
Resource representing a wl_surface.
Represent the Global for the interface.
Represents a generic Resource for a text input object.
qint32 surroundingTextSelectionAnchor() const
TextInputContentPurpose contentPurpose() const
void cursorRectangleChanged(const QRect &rect)
qint32 surroundingTextCursorPosition() const
void preEdit(const QString &text, const QString &commitText)
void contentTypeChanged()
void commitString(const QString &text)
void deleteSurroundingText(quint32 beforeLength, quint32 afterLength)
TextInputContentHints contentHints() const
QString surroundingText() const
QRect cursorRectangle() const
~TestTextInputV1Interface() override
~TextInputManagerV1() override
void zwp_text_input_v1_delete_surrounding_text(int32_t index, uint32_t length) override
void delete_surrounding_text(qint32 index, quint32 length)
void zwp_text_input_v1_preedit_string(uint32_t serial, const QString &text, const QString &commit) override
void preedit_string(const QString &text, const QString &commit)
void commit_string(const QString &text)
void surface_enter(wl_surface *surface)
void zwp_text_input_v1_leave() override
void zwp_text_input_v1_enter(struct ::wl_surface *surface) override
void zwp_text_input_v1_commit_string(uint32_t serial, const QString &text) override
KWayland::Client::Registry * registry