diff --git a/src/server/textinput_interface.cpp b/src/server/textinput_interface.cpp index 48b9883..21cadf1 100644 --- a/src/server/textinput_interface.cpp +++ b/src/server/textinput_interface.cpp @@ -1,348 +1,273 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "textinput_interface_p.h" #include "display.h" #include "global_p.h" #include "resource_p.h" #include "seat_interface_p.h" #include "surface_interface.h" #include #include #include namespace KWayland { namespace Server { void TextInputInterface::Private::showInputPanelCallback(wl_client *client, wl_resource *resource) { auto p = cast(resource); Q_ASSERT(*p->client == client); emit p->q_func()->requestShowInputPanel(); } void TextInputInterface::Private::hideInputPanelCallback(wl_client *client, wl_resource *resource) { auto p = cast(resource); Q_ASSERT(*p->client == client); emit p->q_func()->requestHideInputPanel(); } void TextInputInterface::Private::setSurroundingTextCallback(wl_client *client, wl_resource *resource, const char * text, int32_t cursor, int32_t anchor) { auto p = cast(resource); Q_ASSERT(*p->client == client); p->surroundingText = QByteArray(text); // TODO: make qint32 p->surroundingTextCursorPosition = cursor; p->surroundingTextSelectionAnchor = anchor; emit p->q_func()->surroundingTextChanged(); } -namespace { -static TextInputInterface::ContentHints waylandHintsToKWayland(wl_text_input_content_hint wlHints) -{ - TextInputInterface::ContentHints hints = TextInputInterface::ContentHint::None; - - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION) { - hints |= TextInputInterface::ContentHint::AutoCompletion; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION) { - hints |= TextInputInterface::ContentHint::AutoCorrection; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION) { - hints |= TextInputInterface::ContentHint::AutoCapitalization; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE) { - hints |= TextInputInterface::ContentHint::LowerCase; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE) { - hints |= TextInputInterface::ContentHint::UpperCase; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_TITLECASE) { - hints |= TextInputInterface::ContentHint::TitleCase; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT) { - hints |= TextInputInterface::ContentHint::HiddenText; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA) { - hints |= TextInputInterface::ContentHint::SensitiveData; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_LATIN) { - hints |= TextInputInterface::ContentHint::Latin; - } - if (wlHints & WL_TEXT_INPUT_CONTENT_HINT_MULTILINE) { - hints |= TextInputInterface::ContentHint::MultiLine; - } - - return hints; -} - -static TextInputInterface::ContentPurpose waylandPurposeToKWayland(wl_text_input_content_purpose purpose) -{ - switch (purpose) { - case WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA: - return TextInputInterface::ContentPurpose::Alpha; - case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: - return TextInputInterface::ContentPurpose::Digits; - case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: - return TextInputInterface::ContentPurpose::Number; - case WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE: - return TextInputInterface::ContentPurpose::Phone; - case WL_TEXT_INPUT_CONTENT_PURPOSE_URL: - return TextInputInterface::ContentPurpose::Url; - case WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL: - return TextInputInterface::ContentPurpose::Email; - case WL_TEXT_INPUT_CONTENT_PURPOSE_NAME: - return TextInputInterface::ContentPurpose::Name; - case WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD: - return TextInputInterface::ContentPurpose::Password; - case WL_TEXT_INPUT_CONTENT_PURPOSE_DATE: - return TextInputInterface::ContentPurpose::Date; - case WL_TEXT_INPUT_CONTENT_PURPOSE_TIME: - return TextInputInterface::ContentPurpose::Time; - case WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME: - return TextInputInterface::ContentPurpose::DateTime; - case WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL: - return TextInputInterface::ContentPurpose::Terminal; - case WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL: - default: - return TextInputInterface::ContentPurpose::Normal; - } -} - -} - -void TextInputInterface::Private::setContentTypeCallback(wl_client *client, wl_resource *resource, uint32_t hint, uint32_t wlPurpose) +void TextInputInterface::Private::setContentTypeCallback(wl_client *client, wl_resource *resource, uint32_t hint, uint32_t purpose) { auto p = cast(resource); Q_ASSERT(*p->client == client); - // TODO: pass through Private impl - const auto hints = waylandHintsToKWayland(wl_text_input_content_hint(hint)); - const auto purpose = waylandPurposeToKWayland(wl_text_input_content_purpose(wlPurpose)); - if (hints != p->contentHints || purpose != p->contentPurpose) { - p->contentHints = hints; - p->contentPurpose = purpose; + const auto contentHints = p->convertContentHint(hint); + const auto contentPurpose = p->convertContentPurpose(purpose); + if (contentHints != p->contentHints || contentPurpose != p->contentPurpose) { + p->contentHints = contentHints; + p->contentPurpose = contentPurpose; emit p->q_func()->contentTypeChanged(); } } void TextInputInterface::Private::setCursorRectangleCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { auto p = cast(resource); Q_ASSERT(*p->client == client); const QRect rect = QRect(x, y, width, height); if (p->cursorRectangle != rect) { p->cursorRectangle = rect; emit p->q_func()->cursorRectangleChanged(p->cursorRectangle); } } void TextInputInterface::Private::setPreferredLanguageCallback(wl_client *client, wl_resource *resource, const char * language) { auto p = cast(resource); Q_ASSERT(*p->client == client); const QByteArray preferredLanguage = QByteArray(language); if (p->preferredLanguage != preferredLanguage) { p->preferredLanguage = preferredLanguage; emit p->q_func()->preferredLanguageChanged(p->preferredLanguage); } } TextInputInterface::Private::Private(TextInputInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation) : Resource::Private(q, c, parentResource, interface, implementation) { } TextInputInterface::Private::~Private() { if (resource) { wl_resource_destroy(resource); resource = nullptr; } } QByteArray TextInputInterface::preferredLanguage() const { Q_D(); return d->preferredLanguage; } TextInputInterface::ContentHints TextInputInterface::contentHints() const { Q_D(); return d->contentHints; } TextInputInterface::ContentPurpose TextInputInterface::contentPurpose() const { Q_D(); return d->contentPurpose; } QByteArray TextInputInterface::surroundingText() const { Q_D(); return d->surroundingText; } qint32 TextInputInterface::surroundingTextCursorPosition() const { Q_D(); return d->surroundingTextCursorPosition; } qint32 TextInputInterface::surroundingTextSelectionAnchor() const { Q_D(); return d->surroundingTextSelectionAnchor; } void TextInputInterface::preEdit(const QByteArray &text, const QByteArray &commit) { Q_D(); d->preEdit(text, commit); } void TextInputInterface::commit(const QByteArray &text) { Q_D(); d->commit(text); } void TextInputInterface::keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers) Q_D(); d->keysymPressed(keysym, modifiers); } void TextInputInterface::keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers) { Q_D(); d->keysymReleased(keysym, modifiers); } void TextInputInterface::deleteSurroundingText(quint32 beforeLength, quint32 afterLength) { Q_D(); d->deleteSurroundingText(beforeLength, afterLength); } void TextInputInterface::setCursorPosition(qint32 index, qint32 anchor) { Q_D(); d->setCursorPosition(index, anchor); } void TextInputInterface::setTextDirection(Qt::LayoutDirection direction) { Q_D(); d->setTextDirection(direction); } void TextInputInterface::setPreEditCursor(qint32 index) { Q_D(); d->setPreEditCursor(index); } void TextInputInterface::setInputPanelState(bool visible, const QRect &overlappedSurfaceArea) { Q_D(); if (d->inputPanelVisible == visible && d->overlappedSurfaceArea == overlappedSurfaceArea) { // not changed return; } d->inputPanelVisible = visible; d->overlappedSurfaceArea = overlappedSurfaceArea; d->sendInputPanelState(); } void TextInputInterface::setLanguage(const QByteArray &languageTag) { Q_D(); if (d->language == languageTag) { // not changed return; } d->language = languageTag; d->sendLanguage(); } TextInputInterfaceVersion TextInputInterface::interfaceVersion() const { Q_D(); return d->interfaceVersion(); } QPointer TextInputInterface::surface() const { Q_D(); return d->surface; } QRect TextInputInterface::cursorRectangle() const { Q_D(); return d->cursorRectangle; } bool TextInputInterface::isEnabled() const { Q_D(); return d->enabled; } TextInputInterface::Private *TextInputInterface::d_func() const { return reinterpret_cast(d.data()); } TextInputInterface::TextInputInterface(Private *p, QObject *parent) : Resource(p, parent) { } TextInputInterface::~TextInputInterface() = default; TextInputManagerInterface::TextInputManagerInterface(Private *d, QObject *parent) : Global(d, parent) { } TextInputManagerInterface::~TextInputManagerInterface() = default; TextInputInterfaceVersion TextInputManagerInterface::interfaceVersion() const { Q_D(); return d->interfaceVersion; } TextInputManagerInterface::Private *TextInputManagerInterface::d_func() const { return reinterpret_cast(d.data()); } } } diff --git a/src/server/textinput_interface_p.h b/src/server/textinput_interface_p.h index 2db8bd3..be4a0ad 100644 --- a/src/server/textinput_interface_p.h +++ b/src/server/textinput_interface_p.h @@ -1,154 +1,157 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_TEXTINPUT_INTERFACE_P_H #define KWAYLAND_SERVER_TEXTINPUT_INTERFACE_P_H #include "textinput_interface.h" #include "resource_p.h" #include "global_p.h" #include #include #include namespace KWayland { namespace Server { class TextInputManagerUnstableV0Interface; class TextInputManagerUnstableV2Interface; class TextInputManagerInterface::Private : public Global::Private { public: QVector inputs; TextInputInterfaceVersion interfaceVersion; protected: Private(TextInputInterfaceVersion interfaceVersion, TextInputManagerInterface *q, Display *d, const wl_interface *interface, quint32 version); TextInputManagerInterface *q; }; class TextInputInterface::Private : public Resource::Private { public: ~Private(); virtual void sendEnter(SurfaceInterface *surface, quint32 serial) = 0; virtual void sendLeave(quint32 serial, SurfaceInterface *surface) = 0; virtual void preEdit(const QByteArray &text, const QByteArray &commit) = 0; virtual void commit(const QByteArray &text) = 0; virtual void deleteSurroundingText(quint32 beforeLength, quint32 afterLength) = 0; virtual void setTextDirection(Qt::LayoutDirection direction) = 0; virtual void setPreEditCursor(qint32 index) = 0; virtual void setCursorPosition(qint32 index, qint32 anchor) = 0; virtual void keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers) = 0; virtual void keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers) = 0; virtual TextInputInterfaceVersion interfaceVersion() const = 0; virtual void sendInputPanelState() = 0; virtual void sendLanguage() = 0; + virtual TextInputInterface::ContentHints convertContentHint(uint32_t hint) const = 0; + virtual TextInputInterface::ContentPurpose convertContentPurpose(uint32_t purpose) const = 0; + QByteArray preferredLanguage; QRect cursorRectangle; TextInputInterface::ContentHints contentHints = TextInputInterface::ContentHint::None; TextInputInterface::ContentPurpose contentPurpose = TextInputInterface::ContentPurpose::Normal; SeatInterface *seat = nullptr; QPointer surface; bool enabled = false; QByteArray surroundingText; qint32 surroundingTextCursorPosition = 0; qint32 surroundingTextSelectionAnchor = 0; bool inputPanelVisible = false; QRect overlappedSurfaceArea; QByteArray language; protected: Private(TextInputInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation); static void showInputPanelCallback(wl_client *client, wl_resource *resource); static void hideInputPanelCallback(wl_client *client, wl_resource *resource); static void setSurroundingTextCallback(wl_client *client, wl_resource *resource, const char * text, int32_t cursor, int32_t anchor); static void setContentTypeCallback(wl_client *client, wl_resource *resource, uint32_t hint, uint32_t purpose); static void setCursorRectangleCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); static void setPreferredLanguageCallback(wl_client *client, wl_resource *resource, const char * language); private: TextInputInterface *q_func() { return reinterpret_cast(q); } }; class TextInputUnstableV0Interface : public TextInputInterface { Q_OBJECT public: virtual ~TextInputUnstableV0Interface(); Q_SIGNALS: /** * @internal **/ void requestActivate(KWayland::Server::SeatInterface *seat, KWayland::Server::SurfaceInterface *surface); private: explicit TextInputUnstableV0Interface(TextInputManagerUnstableV0Interface *parent, wl_resource *parentResource); friend class TextInputManagerUnstableV0Interface; class Private; }; class TextInputUnstableV2Interface : public TextInputInterface { Q_OBJECT public: virtual ~TextInputUnstableV2Interface(); private: explicit TextInputUnstableV2Interface(TextInputManagerUnstableV2Interface *parent, wl_resource *parentResource); friend class TextInputManagerUnstableV2Interface; class Private; }; class TextInputManagerUnstableV0Interface : public TextInputManagerInterface { Q_OBJECT public: explicit TextInputManagerUnstableV0Interface(Display *display, QObject *parent = nullptr); virtual ~TextInputManagerUnstableV0Interface(); private: class Private; }; class TextInputManagerUnstableV2Interface : public TextInputManagerInterface { Q_OBJECT public: explicit TextInputManagerUnstableV2Interface(Display *display, QObject *parent = nullptr); virtual ~TextInputManagerUnstableV2Interface(); private: class Private; }; } } #endif diff --git a/src/server/textinput_interface_v0.cpp b/src/server/textinput_interface_v0.cpp index 4efd844..7ade220 100644 --- a/src/server/textinput_interface_v0.cpp +++ b/src/server/textinput_interface_v0.cpp @@ -1,364 +1,441 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "textinput_interface_p.h" #include "display.h" #include "resource_p.h" #include "seat_interface_p.h" #include "surface_interface.h" #include namespace KWayland { namespace Server { class TextInputUnstableV0Interface::Private : public TextInputInterface::Private { public: Private(TextInputInterface *q, TextInputManagerUnstableV0Interface *c, wl_resource *parentResource); ~Private(); void activate(SeatInterface *seat, SurfaceInterface *surface); void deactivate(); void sendEnter(SurfaceInterface *surface, quint32 serial) override; void sendLeave(quint32 serial, SurfaceInterface *surface) override; void preEdit(const QByteArray &text, const QByteArray &commit) override; void commit(const QByteArray &text) override; void deleteSurroundingText(quint32 beforeLength, quint32 afterLength) override; void setTextDirection(Qt::LayoutDirection direction) override; void setPreEditCursor(qint32 index) override; void setCursorPosition(qint32 index, qint32 anchor) override; void keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers) override; void keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers) override; TextInputInterfaceVersion interfaceVersion() const override { return TextInputInterfaceVersion::UnstableV0; } void sendInputPanelState() override; void sendLanguage() override; private: static const struct wl_text_input_interface s_interface; TextInputUnstableV0Interface *q_func() { return reinterpret_cast(q); } static void activateCallback(wl_client *client, wl_resource *resource, wl_resource * seat, wl_resource * surface); static void deactivateCallback(wl_client *client, wl_resource *resource, wl_resource * seat); static void resetCallback(wl_client *client, wl_resource *resource); static void setSurroundingTextUintCallback(wl_client *client, wl_resource *resource, const char * text, uint32_t cursor, uint32_t anchor); static void commitStateCallback(wl_client *client, wl_resource *resource, uint32_t serial); static void invokeActionCallback(wl_client *client, wl_resource *resource, uint32_t button, uint32_t index); + // helpers + TextInputInterface::ContentHints convertContentHint(uint32_t hint) const override; + TextInputInterface::ContentPurpose convertContentPurpose(uint32_t purpose) const override; + quint32 latestState = 0; }; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_text_input_interface TextInputUnstableV0Interface::Private::s_interface = { activateCallback, deactivateCallback, showInputPanelCallback, hideInputPanelCallback, resetCallback, setSurroundingTextUintCallback, setContentTypeCallback, setCursorRectangleCallback, setPreferredLanguageCallback, commitStateCallback, invokeActionCallback }; #endif void TextInputUnstableV0Interface::Private::activate(SeatInterface *seat, SurfaceInterface *s) { surface = QPointer(s); enabled = true; emit q_func()->enabledChanged(); emit q_func()->requestActivate(seat, surface); } void TextInputUnstableV0Interface::Private::deactivate() { surface.clear(); enabled = false; emit q_func()->enabledChanged(); } void TextInputUnstableV0Interface::Private::sendEnter(SurfaceInterface *surface, quint32 serial) { Q_UNUSED(serial) if (!resource) { return; } wl_text_input_send_enter(resource, surface->resource()); } void TextInputUnstableV0Interface::Private::sendLeave(quint32 serial, SurfaceInterface *surface) { Q_UNUSED(serial) Q_UNUSED(surface) if (!resource) { return; } wl_text_input_send_leave(resource); } void TextInputUnstableV0Interface::Private::preEdit(const QByteArray &text, const QByteArray &commit) { if (!resource) { return; } wl_text_input_send_preedit_string(resource, latestState, text.constData(), commit.constData()); } void TextInputUnstableV0Interface::Private::commit(const QByteArray &text) { if (!resource) { return; } wl_text_input_send_commit_string(resource, latestState, text.constData()); } void TextInputUnstableV0Interface::Private::keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers) if (!resource) { return; } wl_text_input_send_keysym(resource, latestState, seat ? seat->timestamp() : 0, keysym, WL_KEYBOARD_KEY_STATE_PRESSED, 0); } void TextInputUnstableV0Interface::Private::keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers) if (!resource) { return; } wl_text_input_send_keysym(resource, latestState, seat ? seat->timestamp() : 0, keysym, WL_KEYBOARD_KEY_STATE_RELEASED, 0); } void TextInputUnstableV0Interface::Private::deleteSurroundingText(quint32 beforeLength, quint32 afterLength) { if (!resource) { return; } wl_text_input_send_delete_surrounding_text(resource, -1 * beforeLength, beforeLength + afterLength); } void TextInputUnstableV0Interface::Private::setCursorPosition(qint32 index, qint32 anchor) { if (!resource) { return; } wl_text_input_send_cursor_position(resource, index, anchor); } void TextInputUnstableV0Interface::Private::setTextDirection(Qt::LayoutDirection direction) { if (!resource) { return; } wl_text_input_text_direction wlDirection; switch (direction) { case Qt::LeftToRight: wlDirection = WL_TEXT_INPUT_TEXT_DIRECTION_LTR; break; case Qt::RightToLeft: wlDirection = WL_TEXT_INPUT_TEXT_DIRECTION_RTL; break; case Qt::LayoutDirectionAuto: wlDirection = WL_TEXT_INPUT_TEXT_DIRECTION_AUTO; break; default: Q_UNREACHABLE(); break; } wl_text_input_send_text_direction(resource, latestState, wlDirection); } void TextInputUnstableV0Interface::Private::setPreEditCursor(qint32 index) { if (!resource) { return; } wl_text_input_send_preedit_cursor(resource, index); } void TextInputUnstableV0Interface::Private::sendInputPanelState() { if (!resource) { return; } wl_text_input_send_input_panel_state(resource, inputPanelVisible); } void TextInputUnstableV0Interface::Private::sendLanguage() { if (!resource) { return; } wl_text_input_send_language(resource, latestState, language.constData()); } TextInputUnstableV0Interface::Private::Private(TextInputInterface *q, TextInputManagerUnstableV0Interface *c, wl_resource *parentResource) : TextInputInterface::Private(q, c, parentResource, &wl_text_input_interface, &s_interface) { } TextInputUnstableV0Interface::Private::~Private() = default; void TextInputUnstableV0Interface::Private::activateCallback(wl_client *client, wl_resource *resource, wl_resource *seat, wl_resource *surface) { auto p = cast(resource); Q_ASSERT(*p->client == client); p->activate(SeatInterface::get(seat), SurfaceInterface::get(surface)); } void TextInputUnstableV0Interface::Private::deactivateCallback(wl_client *client, wl_resource *resource, wl_resource *seat) { Q_UNUSED(seat) auto p = cast(resource); Q_ASSERT(*p->client == client); p->deactivate(); } void TextInputUnstableV0Interface::Private::resetCallback(wl_client *client, wl_resource *resource) { auto p = cast(resource); Q_ASSERT(*p->client == client); emit p->q_func()->requestReset(); } void TextInputUnstableV0Interface::Private::setSurroundingTextUintCallback(wl_client *client, wl_resource *resource, const char * text, uint32_t cursor, uint32_t anchor) { setSurroundingTextCallback(client, resource, text, cursor, anchor); } void TextInputUnstableV0Interface::Private::commitStateCallback(wl_client *client, wl_resource *resource, uint32_t serial) { auto p = cast(resource); Q_ASSERT(*p->client == client); p->latestState = serial; } void TextInputUnstableV0Interface::Private::invokeActionCallback(wl_client *client, wl_resource *resource, uint32_t button, uint32_t index) { Q_UNUSED(button) Q_UNUSED(index) // TODO: implement auto p = cast(resource); Q_ASSERT(*p->client == client); } +TextInputInterface::ContentHints TextInputUnstableV0Interface::Private::convertContentHint(uint32_t hint) const +{ + const auto hints = wl_text_input_content_hint(hint); + TextInputInterface::ContentHints ret = TextInputInterface::ContentHint::None; + + if (hints & WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION) { + ret |= TextInputInterface::ContentHint::AutoCompletion; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION) { + ret |= TextInputInterface::ContentHint::AutoCorrection; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION) { + ret |= TextInputInterface::ContentHint::AutoCapitalization; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE) { + ret |= TextInputInterface::ContentHint::LowerCase; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE) { + ret |= TextInputInterface::ContentHint::UpperCase; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_TITLECASE) { + ret |= TextInputInterface::ContentHint::TitleCase; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT) { + ret |= TextInputInterface::ContentHint::HiddenText; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA) { + ret |= TextInputInterface::ContentHint::SensitiveData; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_LATIN) { + ret |= TextInputInterface::ContentHint::Latin; + } + if (hints & WL_TEXT_INPUT_CONTENT_HINT_MULTILINE) { + ret |= TextInputInterface::ContentHint::MultiLine; + } + return ret; +} + +TextInputInterface::ContentPurpose TextInputUnstableV0Interface::Private::convertContentPurpose(uint32_t purpose) const +{ + const auto wlPurpose = wl_text_input_content_purpose(purpose); + + switch (wlPurpose) { + case WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA: + return TextInputInterface::ContentPurpose::Alpha; + case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS: + return TextInputInterface::ContentPurpose::Digits; + case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER: + return TextInputInterface::ContentPurpose::Number; + case WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE: + return TextInputInterface::ContentPurpose::Phone; + case WL_TEXT_INPUT_CONTENT_PURPOSE_URL: + return TextInputInterface::ContentPurpose::Url; + case WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL: + return TextInputInterface::ContentPurpose::Email; + case WL_TEXT_INPUT_CONTENT_PURPOSE_NAME: + return TextInputInterface::ContentPurpose::Name; + case WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD: + return TextInputInterface::ContentPurpose::Password; + case WL_TEXT_INPUT_CONTENT_PURPOSE_DATE: + return TextInputInterface::ContentPurpose::Date; + case WL_TEXT_INPUT_CONTENT_PURPOSE_TIME: + return TextInputInterface::ContentPurpose::Time; + case WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME: + return TextInputInterface::ContentPurpose::DateTime; + case WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL: + return TextInputInterface::ContentPurpose::Terminal; + case WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL: + default: + return TextInputInterface::ContentPurpose::Normal; + } +} + TextInputUnstableV0Interface::TextInputUnstableV0Interface(TextInputManagerUnstableV0Interface *parent, wl_resource *parentResource) : TextInputInterface(new Private(this, parent, parentResource)) { } TextInputUnstableV0Interface::~TextInputUnstableV0Interface() = default; class TextInputManagerUnstableV0Interface::Private : public TextInputManagerInterface::Private { public: Private(TextInputManagerUnstableV0Interface *q, Display *d); private: void bind(wl_client *client, uint32_t version, uint32_t id) override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } static void createTextInputCallback(wl_client *client, wl_resource *resource, uint32_t id); TextInputManagerUnstableV0Interface *q; static const struct wl_text_input_manager_interface s_interface; static const quint32 s_version; }; const quint32 TextInputManagerUnstableV0Interface::Private::s_version = 1; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_text_input_manager_interface TextInputManagerUnstableV0Interface::Private::s_interface = { createTextInputCallback }; #endif void TextInputManagerUnstableV0Interface::Private::createTextInputCallback(wl_client *client, wl_resource *resource, uint32_t id) { auto m = cast(resource); auto *t = new TextInputUnstableV0Interface(m->q, resource); m->inputs << t; QObject::connect(t, &QObject::destroyed, m->q, [t, m] { m->inputs.removeAll(t); } ); QObject::connect(t, &TextInputUnstableV0Interface::requestActivate, m->q, [t, m] (SeatInterface *seat) { // TODO: disallow for other seat seat->d_func()->registerTextInput(t); t->d_func()->seat = seat; } ); t->d->create(m->display->getConnection(client), version, id); } TextInputManagerInterface::Private::Private(TextInputInterfaceVersion interfaceVersion, TextInputManagerInterface *q, Display *d, const wl_interface *interface, quint32 version) : Global::Private(d, interface, version) , interfaceVersion(interfaceVersion) , q(q) { } TextInputManagerUnstableV0Interface::Private::Private(TextInputManagerUnstableV0Interface *q, Display *d) : TextInputManagerInterface::Private(TextInputInterfaceVersion::UnstableV0, q, d, &wl_text_input_manager_interface, s_version) , q(q) { } void TextInputManagerUnstableV0Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&wl_text_input_manager_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); // TODO: should we track? } void TextInputManagerUnstableV0Interface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) // TODO: implement? } TextInputManagerUnstableV0Interface::TextInputManagerUnstableV0Interface(Display *display, QObject *parent) : TextInputManagerInterface(new Private(this, display), parent) { } TextInputManagerUnstableV0Interface::~TextInputManagerUnstableV0Interface() = default; } } diff --git a/src/server/textinput_interface_v2.cpp b/src/server/textinput_interface_v2.cpp index 0eef9b6..e8d4fd1 100644 --- a/src/server/textinput_interface_v2.cpp +++ b/src/server/textinput_interface_v2.cpp @@ -1,340 +1,417 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "textinput_interface_p.h" #include "display.h" #include "resource_p.h" #include "seat_interface_p.h" #include "surface_interface.h" #include namespace KWayland { namespace Server { class TextInputUnstableV2Interface::Private : public TextInputInterface::Private { public: Private(TextInputInterface *q, TextInputManagerUnstableV2Interface *c, wl_resource *parentResource); ~Private(); void sendEnter(SurfaceInterface *surface, quint32 serial) override; void sendLeave(quint32 serial, SurfaceInterface *surface) override; void preEdit(const QByteArray &text, const QByteArray &commit) override; void commit(const QByteArray &text) override; void deleteSurroundingText(quint32 beforeLength, quint32 afterLength) override; void setTextDirection(Qt::LayoutDirection direction) override; void setPreEditCursor(qint32 index) override; void setCursorPosition(qint32 index, qint32 anchor) override; void keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers) override; void keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers) override; TextInputInterfaceVersion interfaceVersion() const override { return TextInputInterfaceVersion::UnstableV2; } void sendInputPanelState() override; void sendLanguage() override; private: - static void enableCallback(wl_client *client, wl_resource *resource, wl_resource * surface); - static void disableCallback(wl_client *client, wl_resource *resource, wl_resource * surface); - static void updateStateCallback(wl_client *client, wl_resource *resource, uint32_t serial, uint32_t reason); static const struct zwp_text_input_v2_interface s_interface; - TextInputUnstableV2Interface *q_func() { return reinterpret_cast(q); } + static void enableCallback(wl_client *client, wl_resource *resource, wl_resource * surface); + static void disableCallback(wl_client *client, wl_resource *resource, wl_resource * surface); + static void updateStateCallback(wl_client *client, wl_resource *resource, uint32_t serial, uint32_t reason); + + // helpers + TextInputInterface::ContentHints convertContentHint(uint32_t hint) const override; + TextInputInterface::ContentPurpose convertContentPurpose(uint32_t purpose) const override; + void enable(SurfaceInterface *s); void disable(); }; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zwp_text_input_v2_interface TextInputUnstableV2Interface::Private::s_interface = { resourceDestroyedCallback, enableCallback, disableCallback, showInputPanelCallback, hideInputPanelCallback, setSurroundingTextCallback, setContentTypeCallback, setCursorRectangleCallback, setPreferredLanguageCallback, updateStateCallback }; #endif void TextInputUnstableV2Interface::Private::enable(SurfaceInterface *s) { surface = QPointer(s); enabled = true; emit q_func()->enabledChanged(); } void TextInputUnstableV2Interface::Private::disable() { surface.clear(); enabled = false; emit q_func()->enabledChanged(); } void TextInputUnstableV2Interface::Private::sendEnter(SurfaceInterface *surface, quint32 serial) { if (!resource || !surface || !surface->resource()) { return; } zwp_text_input_v2_send_enter(resource, serial, surface->resource()); } void TextInputUnstableV2Interface::Private::sendLeave(quint32 serial, SurfaceInterface *surface) { if (!resource || !surface || !surface->resource()) { return; } zwp_text_input_v2_send_leave(resource, serial, surface->resource()); } void TextInputUnstableV2Interface::Private::preEdit(const QByteArray &text, const QByteArray &commit) { if (!resource) { return; } zwp_text_input_v2_send_preedit_string(resource, text.constData(), commit.constData()); } void TextInputUnstableV2Interface::Private::commit(const QByteArray &text) { if (!resource) { return; } zwp_text_input_v2_send_commit_string(resource, text.constData()); } void TextInputUnstableV2Interface::Private::keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers) if (!resource) { return; } zwp_text_input_v2_send_keysym(resource, seat ? seat->timestamp() : 0, keysym, WL_KEYBOARD_KEY_STATE_PRESSED, 0); } void TextInputUnstableV2Interface::Private::keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers) if (!resource) { return; } zwp_text_input_v2_send_keysym(resource, seat ? seat->timestamp() : 0, keysym, WL_KEYBOARD_KEY_STATE_RELEASED, 0); } void TextInputUnstableV2Interface::Private::deleteSurroundingText(quint32 beforeLength, quint32 afterLength) { if (!resource) { return; } zwp_text_input_v2_send_delete_surrounding_text(resource, beforeLength, afterLength); } void TextInputUnstableV2Interface::Private::setCursorPosition(qint32 index, qint32 anchor) { if (!resource) { return; } zwp_text_input_v2_send_cursor_position(resource, index, anchor); } void TextInputUnstableV2Interface::Private::setTextDirection(Qt::LayoutDirection direction) { if (!resource) { return; } zwp_text_input_v2_text_direction wlDirection; switch (direction) { case Qt::LeftToRight: wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_LTR; break; case Qt::RightToLeft: wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_RTL; break; case Qt::LayoutDirectionAuto: wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_AUTO; break; default: Q_UNREACHABLE(); break; } zwp_text_input_v2_send_text_direction(resource, wlDirection); } void TextInputUnstableV2Interface::Private::setPreEditCursor(qint32 index) { if (!resource) { return; } zwp_text_input_v2_send_preedit_cursor(resource, index); } void TextInputUnstableV2Interface::Private::sendInputPanelState() { if (!resource) { return; } zwp_text_input_v2_send_input_panel_state(resource, inputPanelVisible ? ZWP_TEXT_INPUT_V2_INPUT_PANEL_VISIBILITY_VISIBLE : ZWP_TEXT_INPUT_V2_INPUT_PANEL_VISIBILITY_HIDDEN, overlappedSurfaceArea.x(), overlappedSurfaceArea.y(), overlappedSurfaceArea.width(), overlappedSurfaceArea.height()); } void TextInputUnstableV2Interface::Private::sendLanguage() { if (!resource) { return; } zwp_text_input_v2_send_language(resource, language.constData()); } TextInputUnstableV2Interface::Private::Private(TextInputInterface *q, TextInputManagerUnstableV2Interface *c, wl_resource *parentResource) : TextInputInterface::Private(q, c, parentResource, &zwp_text_input_v2_interface, &s_interface) { } TextInputUnstableV2Interface::Private::~Private() = default; void TextInputUnstableV2Interface::Private::enableCallback(wl_client *client, wl_resource *resource, wl_resource *surface) { auto p = cast(resource); Q_ASSERT(*p->client == client); p->enable(SurfaceInterface::get(surface)); } void TextInputUnstableV2Interface::Private::disableCallback(wl_client *client, wl_resource *resource, wl_resource *surface) { Q_UNUSED(surface) auto p = cast(resource); Q_ASSERT(*p->client == client); p->disable(); } void TextInputUnstableV2Interface::Private::updateStateCallback(wl_client *client, wl_resource *resource, uint32_t serial, uint32_t reason) { auto p = cast(resource); Q_ASSERT(*p->client == client); Q_UNUSED(serial) // TODO: use other reason values reason if (reason == ZWP_TEXT_INPUT_V2_UPDATE_STATE_RESET) { emit p->q_func()->requestReset(); } } +TextInputInterface::ContentHints TextInputUnstableV2Interface::Private::convertContentHint(uint32_t hint) const +{ + const auto hints = zwp_text_input_v2_content_hint(hint); + TextInputInterface::ContentHints ret = TextInputInterface::ContentHint::None; + + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION) { + ret |= TextInputInterface::ContentHint::AutoCompletion; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION) { + ret |= TextInputInterface::ContentHint::AutoCorrection; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION) { + ret |= TextInputInterface::ContentHint::AutoCapitalization; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE) { + ret |= TextInputInterface::ContentHint::LowerCase; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE) { + ret |= TextInputInterface::ContentHint::UpperCase; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_TITLECASE) { + ret |= TextInputInterface::ContentHint::TitleCase; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT) { + ret |= TextInputInterface::ContentHint::HiddenText; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA) { + ret |= TextInputInterface::ContentHint::SensitiveData; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN) { + ret |= TextInputInterface::ContentHint::Latin; + } + if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE) { + ret |= TextInputInterface::ContentHint::MultiLine; + } + return ret; +} + +TextInputInterface::ContentPurpose TextInputUnstableV2Interface::Private::convertContentPurpose(uint32_t purpose) const +{ + const auto wlPurpose = zwp_text_input_v2_content_purpose(purpose); + + switch (wlPurpose) { + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_ALPHA: + return TextInputInterface::ContentPurpose::Alpha; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS: + return TextInputInterface::ContentPurpose::Digits; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER: + return TextInputInterface::ContentPurpose::Number; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE: + return TextInputInterface::ContentPurpose::Phone; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL: + return TextInputInterface::ContentPurpose::Url; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL: + return TextInputInterface::ContentPurpose::Email; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NAME: + return TextInputInterface::ContentPurpose::Name; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PASSWORD: + return TextInputInterface::ContentPurpose::Password; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE: + return TextInputInterface::ContentPurpose::Date; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME: + return TextInputInterface::ContentPurpose::Time; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME: + return TextInputInterface::ContentPurpose::DateTime; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TERMINAL: + return TextInputInterface::ContentPurpose::Terminal; + case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL: + default: + return TextInputInterface::ContentPurpose::Normal; + } +} + TextInputUnstableV2Interface::TextInputUnstableV2Interface(TextInputManagerUnstableV2Interface *parent, wl_resource *parentResource) : TextInputInterface(new Private(this, parent, parentResource)) { } TextInputUnstableV2Interface::~TextInputUnstableV2Interface() = default; class TextInputManagerUnstableV2Interface::Private : public TextInputManagerInterface::Private { public: Private(TextInputManagerUnstableV2Interface *q, Display *d); private: void bind(wl_client *client, uint32_t version, uint32_t id) override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } static void destroyCallback(wl_client *client, wl_resource *resource); static void getTextInputCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * seat); TextInputManagerUnstableV2Interface *q; static const struct zwp_text_input_manager_v2_interface s_interface; static const quint32 s_version; }; const quint32 TextInputManagerUnstableV2Interface::Private::s_version = 1; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zwp_text_input_manager_v2_interface TextInputManagerUnstableV2Interface::Private::s_interface = { destroyCallback, getTextInputCallback }; #endif void TextInputManagerUnstableV2Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) wl_resource_destroy(resource); } void TextInputManagerUnstableV2Interface::Private::getTextInputCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * seat) { SeatInterface *s = SeatInterface::get(seat); if (!s) { // TODO: send error return; } auto m = cast(resource); auto *t = new TextInputUnstableV2Interface(m->q, resource); t->d_func()->seat = s; m->inputs << t; QObject::connect(t, &QObject::destroyed, m->q, [t, m] { m->inputs.removeAll(t); } ); t->d->create(m->display->getConnection(client), version, id); s->d_func()->registerTextInput(t); } TextInputManagerUnstableV2Interface::Private::Private(TextInputManagerUnstableV2Interface *q, Display *d) : TextInputManagerInterface::Private(TextInputInterfaceVersion::UnstableV2, q, d, &zwp_text_input_manager_v2_interface, s_version) , q(q) { } void TextInputManagerUnstableV2Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&zwp_text_input_manager_v2_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); // TODO: should we track? } void TextInputManagerUnstableV2Interface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) // TODO: implement? } TextInputManagerUnstableV2Interface::TextInputManagerUnstableV2Interface(Display *display, QObject *parent) : TextInputManagerInterface(new Private(this, display), parent) { } TextInputManagerUnstableV2Interface::~TextInputManagerUnstableV2Interface() = default; } }