From 139a845151f7aaf75ef60fdee0a79ea5ab9932cc Mon Sep 17 00:00:00 2001 From: ericek111 Date: Thu, 15 Oct 2026 10:13:27 +0200 Subject: [PATCH] Track input-method contexts by identity - deactivate only drops the context it names; one replaced by an activate is kept until KWin deactivates it - Moving focus straight from one field to another ends a manual hide Co-Authored-By: Claude Opus 5.5 --- src/backend/KWinInputMethod.cpp | 13 ++++++++++--- src/backend/KWinInputMethod.h | 6 ++++-- src/backend/TextBackend.h | 1 + src/window/VisibilityController.cpp | 2 -- src/window/VisibilityController.h | 4 +++- tests/tst_visibility.cpp | 9 +++++++++ 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/backend/KWinInputMethod.cpp b/src/backend/KWinInputMethod.cpp index 578ef05..61ca99c 100644 --- a/src/backend/KWinInputMethod.cpp +++ b/src/backend/KWinInputMethod.cpp @@ -14,9 +14,9 @@ void KWinInputMethodGlobal::zwp_input_method_v1_activate(::zwp_input_method_cont Q_EMIT activated(context); } -void KWinInputMethodGlobal::zwp_input_method_v1_deactivate(::zwp_input_method_context_v1 *) +void KWinInputMethodGlobal::zwp_input_method_v1_deactivate(::zwp_input_method_context_v1 *context) { - Q_EMIT deactivated(); + Q_EMIT deactivated(context); } KWinInputMethod::KWinInputMethod(QObject *parent) @@ -87,13 +87,20 @@ void KWinInputMethod::setKeyPressed(quint32 keysym, bool pressed) void KWinInputMethod::activate(::zwp_input_method_context_v1 *context) { + m_previous = std::move(m_context); m_context = std::make_unique(context); connect(m_context.get(), &KWinInputContext::contextChanged, this, &TextBackend::contextChanged); Q_EMIT activeChanged(); } -void KWinInputMethod::deactivate() +void KWinInputMethod::deactivate(::zwp_input_method_context_v1 *context) { + if (m_previous && m_previous->object() == context) { + m_previous.reset(); + return; + } + if (!m_context || m_context->object() != context) + return; m_context.reset(); Q_EMIT activeChanged(); Q_EMIT contextChanged(); diff --git a/src/backend/KWinInputMethod.h b/src/backend/KWinInputMethod.h index 47afe4b..5687cf8 100644 --- a/src/backend/KWinInputMethod.h +++ b/src/backend/KWinInputMethod.h @@ -22,7 +22,7 @@ public: Q_SIGNALS: void activated(::zwp_input_method_context_v1 *context); - void deactivated(); + void deactivated(::zwp_input_method_context_v1 *context); protected: void zwp_input_method_v1_activate(::zwp_input_method_context_v1 *context) override; @@ -57,9 +57,11 @@ Q_SIGNALS: private: void activate(::zwp_input_method_context_v1 *context); - void deactivate(); + void deactivate(::zwp_input_method_context_v1 *context); KWinInputMethodGlobal m_global; KWinFakeInput m_fakeInput; std::unique_ptr m_context; + // Replaced by an activate before KWin deactivated it; kept until it does. + std::unique_ptr m_previous; }; diff --git a/src/backend/TextBackend.h b/src/backend/TextBackend.h index f0eb954..8d90bcf 100644 --- a/src/backend/TextBackend.h +++ b/src/backend/TextBackend.h @@ -34,6 +34,7 @@ public: virtual void setKeyPressed(quint32 keysym, bool pressed) = 0; Q_SIGNALS: + // Also when focus moves straight from one field to another. void activeChanged(); void contextChanged(); }; diff --git a/src/window/VisibilityController.cpp b/src/window/VisibilityController.cpp index 2384c05..d05b644 100644 --- a/src/window/VisibilityController.cpp +++ b/src/window/VisibilityController.cpp @@ -2,8 +2,6 @@ void VisibilityController::setFieldActive(bool active) { - if (active == m_fieldActive) - return; m_fieldActive = active; m_override.reset(); update(); diff --git a/src/window/VisibilityController.h b/src/window/VisibilityController.h index 19e48bd..c0fbcdd 100644 --- a/src/window/VisibilityController.h +++ b/src/window/VisibilityController.h @@ -7,7 +7,8 @@ // - while a text field is focused // - always, if the user wants it (to type into any window) or when running // standalone (no input-method connection) -// - show()/hide()/toggle() override that until the focus changes +// - show()/hide()/toggle() override that until the focus changes, also +// from one field straight to another class VisibilityController : public QObject { Q_OBJECT @@ -17,6 +18,7 @@ public: bool isVisible() const { return m_visible; } + // Called on every focus change, even when a field follows a field. void setFieldActive(bool active); void setStandalone(bool standalone); void setAlwaysVisible(bool always); diff --git a/tests/tst_visibility.cpp b/tests/tst_visibility.cpp index a823e48..320bd9a 100644 --- a/tests/tst_visibility.cpp +++ b/tests/tst_visibility.cpp @@ -27,6 +27,15 @@ private Q_SLOTS: QVERIFY(v.isVisible()); } + void dismissEndsWhenAnotherFieldIsFocused() + { + VisibilityController v; + v.setFieldActive(true); + v.hide(); + v.setFieldActive(true); // activated straight from one field to the next + QVERIFY(v.isVisible()); + } + void alwaysVisibleShowsWithoutField() { VisibilityController v;