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.
This commit is contained in:
Vlad Zahorodnii 2023-03-22 17:45:17 +02:00
parent 71ebaebe9b
commit ad42cfecc1
2 changed files with 34 additions and 41 deletions

View file

@ -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::Resource *> TextInputV3InterfacePrivate::enab
QList<TextInputV3InterfacePrivate::Resource *> 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

View file

@ -42,7 +42,8 @@ public:
void deleteSurroundingText(quint32 beforeLength, quint32 afterLength);
void done();
bool isEnabled() const;
void updateEnabled();
QList<TextInputV3InterfacePrivate::Resource *> textInputsForClient(ClientConnection *client) const;
QList<TextInputV3InterfacePrivate::Resource *> enabledTextInputsForClient(ClientConnection *client) const;
@ -83,17 +84,18 @@ public:
} pending;
QHash<Resource *, quint32> serialHash;
QHash<Resource *, bool> enabled;
QHash<Resource *, bool> 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;