File indexing completed on 2024-12-22 05:09:25

0001 /*
0002     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "event_queue.h"
0007 #include "seat.h"
0008 #include "surface.h"
0009 #include "textinput_p.h"
0010 #include "wayland_pointer_p.h"
0011 
0012 #include <wayland-text-input-v0-client-protocol.h>
0013 
0014 namespace KWayland
0015 {
0016 namespace Client
0017 {
0018 class TextInputUnstableV0::Private : public TextInput::Private
0019 {
0020 public:
0021     Private(TextInputUnstableV0 *q, Seat *seat);
0022 
0023     void setup(wl_text_input *textinputmanagerunstablev0);
0024 
0025     bool isValid() const override;
0026     void enable(Surface *surface) override;
0027     void disable(Surface *surface) override;
0028     void showInputPanel() override;
0029     void hideInputPanel() override;
0030     void setCursorRectangle(const QRect &rect) override;
0031     void setPreferredLanguage(const QString &lang) override;
0032     void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) override;
0033     void reset() override;
0034     void setContentType(ContentHints hint, ContentPurpose purpose) override;
0035 
0036     WaylandPointer<wl_text_input, wl_text_input_destroy> textinputunstablev0;
0037 
0038 private:
0039     static void enterCallaback(void *data, wl_text_input *wl_text_input, wl_surface *surface);
0040     static void leaveCallback(void *data, wl_text_input *wl_text_input);
0041     static void modifiersMapCallback(void *data, wl_text_input *wl_text_input, wl_array *map);
0042     static void inputPanelStateCallback(void *data, wl_text_input *wl_text_input, uint32_t state);
0043     static void preeditStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text, const char *commit);
0044     static void preeditStylingCallback(void *data, wl_text_input *wl_text_input, uint32_t index, uint32_t length, uint32_t style);
0045     static void preeditCursorCallback(void *data, wl_text_input *wl_text_input, int32_t index);
0046     static void commitStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text);
0047     static void cursorPositionCallback(void *data, wl_text_input *wl_text_input, int32_t index, int32_t anchor);
0048     static void deleteSurroundingTextCallback(void *data, wl_text_input *wl_text_input, int32_t index, uint32_t length);
0049     static void keysymCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers);
0050     static void languageCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *language);
0051     static void textDirectionCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, uint32_t direction);
0052 
0053     TextInputUnstableV0 *q;
0054 
0055     static const wl_text_input_listener s_listener;
0056 };
0057 
0058 const wl_text_input_listener TextInputUnstableV0::Private::s_listener = {enterCallaback,
0059                                                                          leaveCallback,
0060                                                                          modifiersMapCallback,
0061                                                                          inputPanelStateCallback,
0062                                                                          preeditStringCallback,
0063                                                                          preeditStylingCallback,
0064                                                                          preeditCursorCallback,
0065                                                                          commitStringCallback,
0066                                                                          cursorPositionCallback,
0067                                                                          deleteSurroundingTextCallback,
0068                                                                          keysymCallback,
0069                                                                          languageCallback,
0070                                                                          textDirectionCallback};
0071 
0072 void TextInputUnstableV0::Private::enterCallaback(void *data, wl_text_input *wl_text_input, wl_surface *surface)
0073 {
0074     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0075     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0076     t->enteredSurface = Surface::get(surface);
0077     Q_EMIT t->q->entered();
0078 }
0079 
0080 void TextInputUnstableV0::Private::leaveCallback(void *data, wl_text_input *wl_text_input)
0081 {
0082     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0083     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0084     t->enteredSurface = nullptr;
0085     Q_EMIT t->q->left();
0086 }
0087 
0088 void TextInputUnstableV0::Private::modifiersMapCallback(void *data, wl_text_input *wl_text_input, wl_array *map)
0089 {
0090     Q_UNUSED(map)
0091     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0092     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0093     // TODO: implement
0094 }
0095 
0096 void TextInputUnstableV0::Private::inputPanelStateCallback(void *data, wl_text_input *wl_text_input, uint32_t state)
0097 {
0098     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0099     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0100     if (t->inputPanelVisible != state) {
0101         t->inputPanelVisible = state;
0102         Q_EMIT t->q->inputPanelStateChanged();
0103     }
0104 }
0105 
0106 void TextInputUnstableV0::Private::preeditStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text, const char *commit)
0107 {
0108     Q_UNUSED(serial)
0109     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0110     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0111     t->pendingPreEdit.commitText = QByteArray(commit);
0112     t->pendingPreEdit.text = QByteArray(text);
0113     if (!t->pendingPreEdit.cursorSet) {
0114         t->pendingPreEdit.cursor = t->pendingPreEdit.text.length();
0115     }
0116     t->currentPreEdit = t->pendingPreEdit;
0117     t->pendingPreEdit = TextInput::Private::PreEdit();
0118     Q_EMIT t->q->composingTextChanged();
0119 }
0120 
0121 void TextInputUnstableV0::Private::preeditStylingCallback(void *data, wl_text_input *wl_text_input, uint32_t index, uint32_t length, uint32_t style)
0122 {
0123     Q_UNUSED(index)
0124     Q_UNUSED(length)
0125     Q_UNUSED(style)
0126     // TODO: implement
0127     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0128     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0129 }
0130 
0131 void TextInputUnstableV0::Private::preeditCursorCallback(void *data, wl_text_input *wl_text_input, int32_t index)
0132 {
0133     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0134     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0135     t->pendingPreEdit.cursor = index;
0136     t->pendingPreEdit.cursorSet = true;
0137 }
0138 
0139 void TextInputUnstableV0::Private::commitStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text)
0140 {
0141     Q_UNUSED(serial)
0142     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0143     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0144     t->pendingCommit.text = QByteArray(text);
0145     t->currentCommit = t->pendingCommit;
0146     // TODO: what are the proper values it should be set to?
0147     t->pendingCommit = TextInput::Private::Commit();
0148     t->pendingCommit.deleteSurrounding.beforeLength = 0;
0149     t->pendingCommit.deleteSurrounding.afterLength = 0;
0150     Q_EMIT t->q->committed();
0151 }
0152 
0153 void TextInputUnstableV0::Private::cursorPositionCallback(void *data, wl_text_input *wl_text_input, int32_t index, int32_t anchor)
0154 {
0155     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0156     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0157     t->pendingCommit.cursor = index;
0158     t->pendingCommit.anchor = anchor;
0159 }
0160 
0161 void TextInputUnstableV0::Private::deleteSurroundingTextCallback(void *data, wl_text_input *wl_text_input, int32_t index, uint32_t length)
0162 {
0163     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0164     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0165     t->pendingCommit.deleteSurrounding.beforeLength = qAbs(index);
0166     t->pendingCommit.deleteSurrounding.afterLength = length - t->pendingCommit.deleteSurrounding.beforeLength;
0167 }
0168 
0169 void TextInputUnstableV0::Private::keysymCallback(void *data,
0170                                                   wl_text_input *wl_text_input,
0171                                                   uint32_t serial,
0172                                                   uint32_t time,
0173                                                   uint32_t sym,
0174                                                   uint32_t wlState,
0175                                                   uint32_t modifiers)
0176 {
0177     Q_UNUSED(serial)
0178     // TODO: add support for modifiers
0179     Q_UNUSED(modifiers)
0180     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0181     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0182     TextInput::KeyState state;
0183     switch (wlState) {
0184     case WL_KEYBOARD_KEY_STATE_RELEASED:
0185         state = TextInput::KeyState::Released;
0186         break;
0187     case WL_KEYBOARD_KEY_STATE_PRESSED:
0188         state = TextInput::KeyState::Pressed;
0189         break;
0190     default:
0191         // invalid
0192         return;
0193     }
0194     Q_EMIT t->q->keyEvent(sym, state, Qt::KeyboardModifiers(), time);
0195 }
0196 
0197 void TextInputUnstableV0::Private::languageCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *language)
0198 {
0199     Q_UNUSED(serial)
0200     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0201     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0202     if (qstrcmp(t->language, language) != 0) {
0203         t->language = QByteArray(language);
0204         Q_EMIT t->q->languageChanged();
0205     }
0206 }
0207 
0208 void TextInputUnstableV0::Private::textDirectionCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, uint32_t wlDirection)
0209 {
0210     Q_UNUSED(serial)
0211     auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
0212     Q_ASSERT(t->textinputunstablev0 == wl_text_input);
0213     Qt::LayoutDirection direction;
0214     switch (wlDirection) {
0215     case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
0216         direction = Qt::LeftToRight;
0217         break;
0218     case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
0219         direction = Qt::RightToLeft;
0220         break;
0221     case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
0222         direction = Qt::LayoutDirectionAuto;
0223         break;
0224     default:
0225         // invalid
0226         return;
0227     }
0228     if (direction != t->textDirection) {
0229         t->textDirection = direction;
0230         Q_EMIT t->q->textDirectionChanged();
0231     }
0232 }
0233 
0234 TextInputUnstableV0::Private::Private(TextInputUnstableV0 *q, Seat *seat)
0235     : TextInput::Private(seat)
0236     , q(q)
0237 {
0238 }
0239 
0240 void TextInputUnstableV0::Private::setup(wl_text_input *ti)
0241 {
0242     Q_ASSERT(ti);
0243     Q_ASSERT(!textinputunstablev0);
0244     textinputunstablev0.setup(ti);
0245     wl_text_input_add_listener(ti, &s_listener, this);
0246 }
0247 
0248 bool TextInputUnstableV0::Private::isValid() const
0249 {
0250     return textinputunstablev0.isValid();
0251 }
0252 
0253 void TextInputUnstableV0::Private::enable(Surface *surface)
0254 {
0255     wl_text_input_activate(textinputunstablev0, *seat, *surface);
0256 }
0257 
0258 void TextInputUnstableV0::Private::disable(Surface *surface)
0259 {
0260     Q_UNUSED(surface)
0261     wl_text_input_deactivate(textinputunstablev0, *seat);
0262 }
0263 
0264 void TextInputUnstableV0::Private::showInputPanel()
0265 {
0266     wl_text_input_show_input_panel(textinputunstablev0);
0267 }
0268 
0269 void TextInputUnstableV0::Private::hideInputPanel()
0270 {
0271     wl_text_input_hide_input_panel(textinputunstablev0);
0272 }
0273 
0274 void TextInputUnstableV0::Private::setCursorRectangle(const QRect &rect)
0275 {
0276     wl_text_input_set_cursor_rectangle(textinputunstablev0, rect.x(), rect.y(), rect.width(), rect.height());
0277 }
0278 
0279 void TextInputUnstableV0::Private::setPreferredLanguage(const QString &lang)
0280 {
0281     wl_text_input_set_preferred_language(textinputunstablev0, lang.toUtf8().constData());
0282 }
0283 
0284 void TextInputUnstableV0::Private::setSurroundingText(const QString &text, quint32 cursor, quint32 anchor)
0285 {
0286     const QStringView strView(text);
0287 
0288     wl_text_input_set_surrounding_text(textinputunstablev0,
0289                                        text.toUtf8().constData(),
0290                                        strView.left(cursor).toUtf8().length(),
0291                                        strView.left(anchor).toUtf8().length());
0292 }
0293 
0294 void TextInputUnstableV0::Private::reset()
0295 {
0296     wl_text_input_reset(textinputunstablev0);
0297 }
0298 
0299 void TextInputUnstableV0::Private::setContentType(ContentHints hints, ContentPurpose purpose)
0300 {
0301     uint32_t wlHints = 0;
0302     uint32_t wlPurpose = 0;
0303     if (hints.testFlag(ContentHint::AutoCompletion)) {
0304         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
0305     }
0306     if (hints.testFlag(ContentHint::AutoCorrection)) {
0307         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION;
0308     }
0309     if (hints.testFlag(ContentHint::AutoCapitalization)) {
0310         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
0311     }
0312     if (hints.testFlag(ContentHint::LowerCase)) {
0313         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
0314     }
0315     if (hints.testFlag(ContentHint::UpperCase)) {
0316         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
0317     }
0318     if (hints.testFlag(ContentHint::TitleCase)) {
0319         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_TITLECASE;
0320     }
0321     if (hints.testFlag(ContentHint::HiddenText)) {
0322         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT;
0323     }
0324     if (hints.testFlag(ContentHint::SensitiveData)) {
0325         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA;
0326     }
0327     if (hints.testFlag(ContentHint::Latin)) {
0328         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_LATIN;
0329     }
0330     if (hints.testFlag(ContentHint::MultiLine)) {
0331         wlHints |= WL_TEXT_INPUT_CONTENT_HINT_MULTILINE;
0332     }
0333     switch (purpose) {
0334     case ContentPurpose::Normal:
0335         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
0336         break;
0337     case ContentPurpose::Alpha:
0338         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA;
0339         break;
0340     case ContentPurpose::Digits:
0341         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
0342         break;
0343     case ContentPurpose::Number:
0344         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
0345         break;
0346     case ContentPurpose::Phone:
0347         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
0348         break;
0349     case ContentPurpose::Url:
0350         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_URL;
0351         break;
0352     case ContentPurpose::Email:
0353         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
0354         break;
0355     case ContentPurpose::Name:
0356         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NAME;
0357         break;
0358     case ContentPurpose::Password:
0359         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
0360         break;
0361     case ContentPurpose::Date:
0362         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATE;
0363         break;
0364     case ContentPurpose::Time:
0365         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_TIME;
0366         break;
0367     case ContentPurpose::DateTime:
0368         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME;
0369         break;
0370     case ContentPurpose::Terminal:
0371         wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL;
0372         break;
0373     }
0374     wl_text_input_set_content_type(textinputunstablev0, wlHints, wlPurpose);
0375 }
0376 
0377 TextInputUnstableV0::TextInputUnstableV0(Seat *seat, QObject *parent)
0378     : TextInput(new Private(this, seat), parent)
0379 {
0380 }
0381 
0382 TextInputUnstableV0::~TextInputUnstableV0()
0383 {
0384     release();
0385 }
0386 
0387 TextInputUnstableV0::Private *TextInputUnstableV0::d_func() const
0388 {
0389     return reinterpret_cast<Private *>(d.data());
0390 }
0391 
0392 void TextInputUnstableV0::setup(wl_text_input *textinputunstablev0)
0393 {
0394     Q_D();
0395     d->setup(textinputunstablev0);
0396 }
0397 
0398 void TextInputUnstableV0::release()
0399 {
0400     Q_D();
0401     d->textinputunstablev0.release();
0402 }
0403 
0404 void TextInputUnstableV0::destroy()
0405 {
0406     Q_D();
0407     d->textinputunstablev0.destroy();
0408 }
0409 
0410 TextInputUnstableV0::operator wl_text_input *()
0411 {
0412     Q_D();
0413     return d->textinputunstablev0;
0414 }
0415 
0416 TextInputUnstableV0::operator wl_text_input *() const
0417 {
0418     Q_D();
0419     return d->textinputunstablev0;
0420 }
0421 
0422 class TextInputManagerUnstableV0::Private : public TextInputManager::Private
0423 {
0424 public:
0425     Private() = default;
0426 
0427     void release() override;
0428     void destroy() override;
0429     bool isValid() override;
0430     void setupV0(wl_text_input_manager *ti) override;
0431     TextInput *createTextInput(Seat *seat, QObject *parent = nullptr) override;
0432     using TextInputManager::Private::operator zwp_text_input_manager_v2 *; // overriding only one overload results in a compiler warning. This tells GCC we're
0433                                                                            // doing it deliberately
0434     operator wl_text_input_manager *() override
0435     {
0436         return textinputmanagerunstablev0;
0437     }
0438     operator wl_text_input_manager *() const override
0439     {
0440         return textinputmanagerunstablev0;
0441     }
0442 
0443     WaylandPointer<wl_text_input_manager, wl_text_input_manager_destroy> textinputmanagerunstablev0;
0444 };
0445 
0446 void TextInputManagerUnstableV0::Private::release()
0447 {
0448     textinputmanagerunstablev0.release();
0449 }
0450 
0451 void TextInputManagerUnstableV0::Private::destroy()
0452 {
0453     textinputmanagerunstablev0.destroy();
0454 }
0455 
0456 bool TextInputManagerUnstableV0::Private::isValid()
0457 {
0458     return textinputmanagerunstablev0.isValid();
0459 }
0460 
0461 TextInputManagerUnstableV0::TextInputManagerUnstableV0(QObject *parent)
0462     : TextInputManager(new Private, parent)
0463 {
0464 }
0465 
0466 TextInputManagerUnstableV0::Private *TextInputManagerUnstableV0::d_func() const
0467 {
0468     return reinterpret_cast<Private *>(d.data());
0469 }
0470 
0471 TextInputManagerUnstableV0::~TextInputManagerUnstableV0()
0472 {
0473     release();
0474 }
0475 
0476 void TextInputManagerUnstableV0::Private::setupV0(wl_text_input_manager *ti)
0477 {
0478     Q_ASSERT(ti);
0479     Q_ASSERT(!textinputmanagerunstablev0);
0480     textinputmanagerunstablev0.setup(ti);
0481 }
0482 
0483 TextInput *TextInputManagerUnstableV0::Private::createTextInput(Seat *seat, QObject *parent)
0484 {
0485     Q_ASSERT(isValid());
0486     TextInputUnstableV0 *t = new TextInputUnstableV0(seat, parent);
0487     auto w = wl_text_input_manager_create_text_input(textinputmanagerunstablev0);
0488     if (queue) {
0489         queue->addProxy(w);
0490     }
0491     t->setup(w);
0492     return t;
0493 }
0494 
0495 }
0496 }