From 8f1174c155d8277a784776b2b65fae2123d2fab2 Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Sat, 9 Aug 2025 00:24:52 +0530 Subject: [PATCH] ime --- crates/gpui/src/platform/linux/x11/client.rs | 47 ++++++++++++++----- .../src/platform/linux/x11/xim_handler.rs | 17 ++++--- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 573e4addf7..a83557d128 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -655,6 +655,20 @@ impl X11Client { state.restore_xim(ximc, xim_handler); drop(state); + // Create IC when IME becomes ready while we already have focus + { + let s = self.0.borrow(); + let need_enable = s + .xim_handler + .as_ref() + .map(|h| h.ready && !h.connected && s.keyboard_focused_window.is_some()) + .unwrap_or(false); + drop(s); + if need_enable { + self.enable_ime(); + } + } + if let Some(event) = xim_callback_event { self.handle_xim_callback_event(event); } @@ -682,22 +696,25 @@ impl X11Client { let Some((mut ximc, mut xim_handler)) = state.take_xim() else { return; }; + + let window_id = state.keyboard_focused_window; + if window_id.is_none() { + // no focus -> nothing to bind to; put XIM back and bail + state.restore_xim(ximc, xim_handler); + return; + } + let window_id = window_id.unwrap(); + // ensure handler.window is the actual focused window + xim_handler.window = window_id; + let mut ic_attributes = ximc .build_ic_attributes() .push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS) .push(AttributeName::ClientWindow, xim_handler.window) .push(AttributeName::FocusWindow, xim_handler.window); - let window_id = state.keyboard_focused_window; drop(state); - if let Some(window_id) = window_id { - let Some(window) = self.get_window(window_id) else { - log::error!("Failed to get window for IME positioning"); - let mut state = self.0.borrow_mut(); - state.ximc = Some(ximc); - state.xim_handler = Some(xim_handler); - return; - }; + if let Some(window) = self.get_window(window_id) { if let Some(area) = window.get_ime_area() { ic_attributes = ic_attributes.nested_list(xim::AttributeName::PreeditAttributes, |b| { @@ -710,9 +727,17 @@ impl X11Client { ); }); } + } else { + log::error!("Failed to get window for IME positioning"); } - ximc.create_ic(xim_handler.im_id, ic_attributes.build()) - .ok(); + + // if we already have an IC, just rebind its window/spot; else create it + if xim_handler.connected { + let _ = ximc.set_ic_values(xim_handler.im_id, xim_handler.ic_id, ic_attributes.build()); + } else { + let _ = ximc.create_ic(xim_handler.im_id, ic_attributes.build()); + } + let mut state = self.0.borrow_mut(); state.restore_xim(ximc, xim_handler); } diff --git a/crates/gpui/src/platform/linux/x11/xim_handler.rs b/crates/gpui/src/platform/linux/x11/xim_handler.rs index 82b7c96312..b38e83bf1c 100644 --- a/crates/gpui/src/platform/linux/x11/xim_handler.rs +++ b/crates/gpui/src/platform/linux/x11/xim_handler.rs @@ -13,6 +13,7 @@ pub struct XimHandler { pub im_id: u16, pub ic_id: u16, pub connected: bool, + pub ready: bool, pub window: xproto::Window, pub last_callback_event: Option, } @@ -23,6 +24,7 @@ impl XimHandler { im_id: Default::default(), ic_id: Default::default(), connected: false, + ready: false, window: Default::default(), last_callback_event: None, } @@ -42,17 +44,14 @@ impl> ClientHandler for XimHandler fn handle_get_im_values( &mut self, - client: &mut C, - input_method_id: u16, + _client: &mut C, + _input_method_id: u16, _attributes: AHashMap>, ) -> Result<(), ClientError> { - let ic_attributes = client - .build_ic_attributes() - .push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS) - .push(AttributeName::ClientWindow, self.window) - .push(AttributeName::FocusWindow, self.window) - .build(); - client.create_ic(input_method_id, ic_attributes) + // IM is ready, but we don't know the real window yet. + // Defer IC creation to client.enable_ime(). + self.ready = true; + Ok(()) } fn handle_create_ic(