From abfe90bddbc9a831309b3d03da3670e36ed6861b Mon Sep 17 00:00:00 2001 From: Tom Churchman Date: Fri, 17 Jan 2025 17:29:10 +0100 Subject: [PATCH] wayland: clear IME preedit only when necessary When all we'll be doing is setting a new preedit, the preedit doesn't have to be explicitly cleared first. This change is perhaps debatable. The direct reason for this is to make it easier to work around quirks/bugs: in Masonry we've found IBus appears to resend the IME preedit in response to `Window::set_ime_cursor_area` (`zwp_text_input_v3::set_cursor_rectangle`). Because currently the preedit is first cleared, a new IME cursor area is sent, which again causes IBus to resend the preedit. This can loop for a while. The Wayland protocol is mechanically quite prescriptive, it says for zwp_text_input_v3:event:done. > 1. Replace existing preedit string with the cursor. > 2. Delete requested surrounding text. > 3. Insert commit string with the cursor at its end. > 4. Calculate surrounding text to send. > 5. Insert new preedit text in cursor position. > 6. Place cursor inside preedit text. Winit currently doesn't do surrounding text, so 2. and 4. can be ignored. In Winit's IME model, without a commit, sending just the `Ime::Preedit` event without explicitly clearing is arguably still equivalent to doing 1., 5., and 6. --- src/changelog/unreleased.md | 4 ++++ .../linux/wayland/seat/text_input/mod.rs | 14 +++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index f3a0f6d2c..fbcee6214 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -39,3 +39,7 @@ The migration guide could reference other migration examples in the current changelog entry. ## Unreleased + +### Changed + +- On Wayland, no longer send an explicit clearing `Ime::Preedit` just prior to a new `Ime::Preedit`. diff --git a/src/platform_impl/linux/wayland/seat/text_input/mod.rs b/src/platform_impl/linux/wayland/seat/text_input/mod.rs index 49d936359..db724893c 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/mod.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/mod.rs @@ -121,11 +121,15 @@ impl Dispatch for TextInputState { None => return, }; - // Clear preedit at the start of `Done`. - state.events_sink.push_window_event( - WindowEvent::Ime(Ime::Preedit(String::new(), None)), - window_id, - ); + // Clear preedit, unless all we'll be doing next is sending a new preedit. + if text_input_data.pending_commit.is_some() + || text_input_data.pending_preedit.is_none() + { + state.events_sink.push_window_event( + WindowEvent::Ime(Ime::Preedit(String::new(), None)), + window_id, + ); + } // Send `Commit`. if let Some(text) = text_input_data.pending_commit.take() {