From 77f1c73f06634027c509967b067df071706f11d5 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 | 1 + .../linux/wayland/seat/text_input/mod.rs | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 96394c4b..6a9c4b08 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -164,6 +164,7 @@ changelog entry. - Update `smol_str` to version `0.3` - Rename `VideoModeHandle` to `VideoMode`, now it only stores plain data. - Make `Fullscreen::Exclusive` contain `(MonitorHandle, VideoMode)`. +- On Wayland, no longer send an explicit clearing `Ime::Preedit` just prior to a new `Ime::Preedit`. ### Removed 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 dff37235..45a0f6c9 100644 --- a/src/platform_impl/linux/wayland/seat/text_input/mod.rs +++ b/src/platform_impl/linux/wayland/seat/text_input/mod.rs @@ -119,11 +119,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() {