Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Smit Barmase
8f1174c155
ime 2025-08-09 00:24:52 +05:30
2 changed files with 44 additions and 20 deletions

View file

@ -655,6 +655,20 @@ impl X11Client {
state.restore_xim(ximc, xim_handler); state.restore_xim(ximc, xim_handler);
drop(state); 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 { if let Some(event) = xim_callback_event {
self.handle_xim_callback_event(event); self.handle_xim_callback_event(event);
} }
@ -682,22 +696,25 @@ impl X11Client {
let Some((mut ximc, mut xim_handler)) = state.take_xim() else { let Some((mut ximc, mut xim_handler)) = state.take_xim() else {
return; 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 let mut ic_attributes = ximc
.build_ic_attributes() .build_ic_attributes()
.push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS) .push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS)
.push(AttributeName::ClientWindow, xim_handler.window) .push(AttributeName::ClientWindow, xim_handler.window)
.push(AttributeName::FocusWindow, xim_handler.window); .push(AttributeName::FocusWindow, xim_handler.window);
let window_id = state.keyboard_focused_window;
drop(state); drop(state);
if let Some(window_id) = window_id { if let Some(window) = self.get_window(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(area) = window.get_ime_area() { if let Some(area) = window.get_ime_area() {
ic_attributes = ic_attributes =
ic_attributes.nested_list(xim::AttributeName::PreeditAttributes, |b| { 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(); let mut state = self.0.borrow_mut();
state.restore_xim(ximc, xim_handler); state.restore_xim(ximc, xim_handler);
} }

View file

@ -13,6 +13,7 @@ pub struct XimHandler {
pub im_id: u16, pub im_id: u16,
pub ic_id: u16, pub ic_id: u16,
pub connected: bool, pub connected: bool,
pub ready: bool,
pub window: xproto::Window, pub window: xproto::Window,
pub last_callback_event: Option<XimCallbackEvent>, pub last_callback_event: Option<XimCallbackEvent>,
} }
@ -23,6 +24,7 @@ impl XimHandler {
im_id: Default::default(), im_id: Default::default(),
ic_id: Default::default(), ic_id: Default::default(),
connected: false, connected: false,
ready: false,
window: Default::default(), window: Default::default(),
last_callback_event: None, last_callback_event: None,
} }
@ -42,17 +44,14 @@ impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler
fn handle_get_im_values( fn handle_get_im_values(
&mut self, &mut self,
client: &mut C, _client: &mut C,
input_method_id: u16, _input_method_id: u16,
_attributes: AHashMap<AttributeName, Vec<u8>>, _attributes: AHashMap<AttributeName, Vec<u8>>,
) -> Result<(), ClientError> { ) -> Result<(), ClientError> {
let ic_attributes = client // IM is ready, but we don't know the real window yet.
.build_ic_attributes() // Defer IC creation to client.enable_ime().
.push(AttributeName::InputStyle, InputStyle::PREEDIT_CALLBACKS) self.ready = true;
.push(AttributeName::ClientWindow, self.window) Ok(())
.push(AttributeName::FocusWindow, self.window)
.build();
client.create_ic(input_method_id, ic_attributes)
} }
fn handle_create_ic( fn handle_create_ic(