From ad42cfecc1a4ee32a4bbf0ed22de6e7e93a3a335 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 22 Mar 2023 17:45:17 +0200 Subject: [PATCH] wayland: Disable text-input-v3 when it's destroyed Destroying a zwp_text_input_v3 object should be viewed as disabling it. isEnabled property is cached because it cannot be computed in _destroy_resource() handler. By that time, the resource no longer will be in resourceMap(), so TextInputV3InterfacePrivate::isEnabled() will erroneously return false even though we expect true. --- src/wayland/textinput_v3_interface.cpp | 67 +++++++++++--------------- src/wayland/textinput_v3_interface_p.h | 8 +-- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/src/wayland/textinput_v3_interface.cpp b/src/wayland/textinput_v3_interface.cpp index f98887ac22..cc3b2f1e32 100644 --- a/src/wayland/textinput_v3_interface.cpp +++ b/src/wayland/textinput_v3_interface.cpp @@ -103,27 +103,6 @@ TextInputChangeCause convertChangeCause(uint32_t cause) return TextInputChangeCause::Other; } } - -class EnabledEmitter -{ -public: - EnabledEmitter(TextInputV3Interface *q) - : q(q) - , m_wasEnabled(q->isEnabled()) - { - } - ~EnabledEmitter() - { - if (m_wasEnabled != q->isEnabled()) { - Q_EMIT q->enabledChanged(); - } - } - -private: - TextInputV3Interface *q; - const bool m_wasEnabled; -}; - } TextInputManagerV3InterfacePrivate::TextInputManagerV3InterfacePrivate(TextInputManagerV3Interface *_q, Display *display) @@ -170,19 +149,24 @@ void TextInputV3InterfacePrivate::zwp_text_input_v3_bind_resource(Resource *reso { // we initialize the serial for the resource to be 0 serialHash.insert(resource, 0); - enabled.insert(resource, false); + enabledHash.insert(resource, false); +} + +void TextInputV3InterfacePrivate::zwp_text_input_v3_destroy_resource(Resource *resource) +{ + // drop resource from the serial hash + serialHash.remove(resource); + enabledHash.remove(resource); + updateEnabled(); } void TextInputV3InterfacePrivate::zwp_text_input_v3_destroy(Resource *resource) { - // drop resource from the serial hash - serialHash.remove(resource); - enabled.remove(resource); + wl_resource_destroy(resource->handle); } void TextInputV3InterfacePrivate::sendEnter(SurfaceInterface *newSurface) { - EnabledEmitter emitter(q); // It should be always synchronized with SeatInterface::focusedTextInputSurface. Q_ASSERT(!surface && newSurface); surface = newSurface; @@ -190,11 +174,11 @@ void TextInputV3InterfacePrivate::sendEnter(SurfaceInterface *newSurface) for (auto resource : clientResources) { send_enter(resource->handle, newSurface->resource()); } + updateEnabled(); } void TextInputV3InterfacePrivate::sendLeave(SurfaceInterface *leavingSurface) { - EnabledEmitter emitter(q); // It should be always synchronized with SeatInterface::focusedTextInputSurface. Q_ASSERT(leavingSurface && surface == leavingSurface); surface.clear(); @@ -202,6 +186,7 @@ void TextInputV3InterfacePrivate::sendLeave(SurfaceInterface *leavingSurface) for (auto resource : clientResources) { send_leave(resource->handle, leavingSurface->resource()); } + updateEnabled(); } void TextInputV3InterfacePrivate::sendPreEdit(const QString &text, const quint32 cursorBegin, const quint32 cursorEnd) @@ -270,22 +255,27 @@ QList TextInputV3InterfacePrivate::enab QList result; const auto [start, end] = resourceMap().equal_range(client->client()); for (auto it = start; it != end; ++it) { - if (enabled[*it]) { + if (enabledHash[*it]) { result.append(*it); } } return result; } -bool TextInputV3InterfacePrivate::isEnabled() const +void TextInputV3InterfacePrivate::updateEnabled() { - if (!surface) { - return false; + bool newEnabled = false; + if (surface) { + const auto clientResources = textInputsForClient(surface->client()); + newEnabled = std::any_of(clientResources.begin(), clientResources.end(), [this](Resource *resource) { + return enabledHash[resource]; + }); + } + + if (isEnabled != newEnabled) { + isEnabled = newEnabled; + Q_EMIT q->enabledChanged(); } - const auto clientResources = textInputsForClient(surface->client()); - return std::any_of(clientResources.begin(), clientResources.end(), [this](Resource *resource) { - return enabled[resource]; - }); } void TextInputV3InterfacePrivate::zwp_text_input_v3_enable(Resource *resource) @@ -345,10 +335,9 @@ void TextInputV3InterfacePrivate::zwp_text_input_v3_set_text_change_cause(Resour void TextInputV3InterfacePrivate::zwp_text_input_v3_commit(Resource *resource) { - EnabledEmitter emitter(q); serialHash[resource]++; - auto &resourceEnabled = enabled[resource]; + auto &resourceEnabled = enabledHash[resource]; const auto oldResourceEnabled = resourceEnabled; if (resourceEnabled != pending.enabled) { resourceEnabled = pending.enabled; @@ -397,6 +386,8 @@ void TextInputV3InterfacePrivate::zwp_text_input_v3_commit(Resource *resource) if (resourceEnabled && oldResourceEnabled) { Q_EMIT q->enableRequested(); } + + updateEnabled(); } void TextInputV3InterfacePrivate::defaultPending() @@ -492,7 +483,7 @@ QRect TextInputV3Interface::cursorRectangle() const bool TextInputV3Interface::isEnabled() const { - return d->isEnabled(); + return d->isEnabled; } bool TextInputV3Interface::clientSupportsTextInput(ClientConnection *client) const diff --git a/src/wayland/textinput_v3_interface_p.h b/src/wayland/textinput_v3_interface_p.h index 6139b0a992..d18b7d6da7 100644 --- a/src/wayland/textinput_v3_interface_p.h +++ b/src/wayland/textinput_v3_interface_p.h @@ -42,7 +42,8 @@ public: void deleteSurroundingText(quint32 beforeLength, quint32 afterLength); void done(); - bool isEnabled() const; + void updateEnabled(); + QList textInputsForClient(ClientConnection *client) const; QList enabledTextInputsForClient(ClientConnection *client) const; @@ -83,17 +84,18 @@ public: } pending; QHash serialHash; - QHash enabled; + QHash enabledHash; void defaultPending(); void defaultPendingPreedit(); TextInputV3Interface *q; + bool isEnabled = false; protected: void zwp_text_input_v3_bind_resource(Resource *resource) override; + void zwp_text_input_v3_destroy_resource(Resource *resource) override; void zwp_text_input_v3_destroy(Resource *resource) override; - // requests void zwp_text_input_v3_enable(Resource *resource) override; void zwp_text_input_v3_disable(Resource *resource) override; void zwp_text_input_v3_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) override;