diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 573e4addf7..27447e9064 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -631,42 +631,54 @@ impl X11Client { for event in events.into_iter() { let mut state = self.0.borrow_mut(); if !state.has_xim() { + dbg!("XIM: no XIM available for key event"); drop(state); self.handle_event(event); continue; } let Some((mut ximc, mut xim_handler)) = state.take_xim() else { + dbg!("XIM: failed to take XIM for key event"); continue; }; let xim_connected = xim_handler.connected; + dbg!("XIM: processing key event", xim_connected); drop(state); let xim_filtered = match ximc.filter_event(&event, &mut xim_handler) { - Ok(handled) => handled, + Ok(handled) => { + dbg!("XIM: filter_event result", handled); + handled + }, Err(err) => { + dbg!("XIM: filter_event error", &err); log::error!("XIMClientError: {}", err); false } }; let xim_callback_event = xim_handler.last_callback_event.take(); + dbg!("XIM: callback event present", xim_callback_event.is_some()); let mut state = self.0.borrow_mut(); state.restore_xim(ximc, xim_handler); drop(state); if let Some(event) = xim_callback_event { + dbg!("XIM: handling callback event"); self.handle_xim_callback_event(event); } if xim_filtered { + dbg!("XIM: event was filtered, not processing further"); continue; } if xim_connected { + dbg!("XIM: forwarding event to XIM"); self.xim_handle_event(event); } else { self.handle_event(event); + dbg!("XIM: not connected, skipping XIM event handling"); } } } @@ -1273,22 +1285,28 @@ impl X11Client { } fn handle_xim_callback_event(&self, event: XimCallbackEvent) { + dbg!("XIM: handle_xim_callback_event called"); match event { XimCallbackEvent::XimXEvent(event) => { + dbg!("XIM: handling forwarded X event"); self.handle_event(event); } XimCallbackEvent::XimCommitEvent(window, text) => { + dbg!("XIM: handling commit event", window, &text); self.xim_handle_commit(window, text); } XimCallbackEvent::XimPreeditEvent(window, text) => { + dbg!("XIM: handling preedit event", window, &text); self.xim_handle_preedit(window, text); } }; } fn xim_handle_event(&self, event: Event) -> Option<()> { + dbg!("XIM: xim_handle_event called"); match event { Event::KeyPress(event) | Event::KeyRelease(event) => { + dbg!("XIM: handling key press/release event", event.event); let mut state = self.0.borrow_mut(); state.pre_key_char_down = Some(Keystroke::from_xkb( &state.xkb, @@ -1298,19 +1316,25 @@ impl X11Client { let (mut ximc, mut xim_handler) = state.take_xim()?; drop(state); xim_handler.window = event.event; - ximc.forward_event( + dbg!("XIM: forwarding event to XIM server", event.event, xim_handler.im_id, xim_handler.ic_id); + let result = ximc.forward_event( xim_handler.im_id, xim_handler.ic_id, xim::ForwardEventFlag::empty(), &event, - ) - .context("X11: Failed to forward XIM event") - .log_err(); + ); + if let Err(ref error) = result { + dbg!("XIM: forward_event error", error); + } + result + .context("X11: Failed to forward XIM event") + .log_err(); let mut state = self.0.borrow_mut(); state.restore_xim(ximc, xim_handler); drop(state); } event => { + dbg!("XIM: forwarding non-key event to normal handler"); self.handle_event(event); } } @@ -1318,27 +1342,35 @@ impl X11Client { } fn xim_handle_commit(&self, window: xproto::Window, text: String) -> Option<()> { + dbg!("XIM: xim_handle_commit called", window, &text); let Some(window) = self.get_window(window) else { + dbg!("XIM: bug: Failed to get window for XIM commit", window); log::error!("bug: Failed to get window for XIM commit"); return None; }; let mut state = self.0.borrow_mut(); let keystroke = state.pre_key_char_down.take(); state.composing = false; + dbg!("XIM: setting composing to false, keystroke present", keystroke.is_some()); drop(state); if let Some(mut keystroke) = keystroke { keystroke.key_char = Some(text.clone()); + dbg!("XIM: calling window.handle_input with keystroke"); window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent { keystroke, is_held: false, })); + } else { + dbg!("XIM: no keystroke available for commit"); } Some(()) } fn xim_handle_preedit(&self, window: xproto::Window, text: String) -> Option<()> { + dbg!("XIM: xim_handle_preedit called", window, &text); let Some(window) = self.get_window(window) else { + dbg!("XIM: bug: Failed to get window for XIM preedit", window); log::error!("bug: Failed to get window for XIM preedit"); return None; }; @@ -1346,10 +1378,13 @@ impl X11Client { let mut state = self.0.borrow_mut(); let (mut ximc, mut xim_handler) = state.take_xim()?; state.composing = !text.is_empty(); + dbg!("XIM: setting composing state", state.composing); drop(state); + dbg!("XIM: calling window.handle_ime_preedit"); window.handle_ime_preedit(text); if let Some(area) = window.get_ime_area() { + dbg!("XIM: got IME area, updating spot location", area); let ic_attributes = ximc .build_ic_attributes() .push( @@ -1368,8 +1403,10 @@ impl X11Client { ); }) .build(); - ximc.set_ic_values(xim_handler.im_id, xim_handler.ic_id, ic_attributes) - .ok(); + let result = ximc.set_ic_values(xim_handler.im_id, xim_handler.ic_id, ic_attributes); + dbg!("XIM: set_ic_values result for preedit", result.is_ok()); + } else { + dbg!("XIM: no IME area available"); } let mut state = self.0.borrow_mut(); state.restore_xim(ximc, xim_handler); diff --git a/crates/gpui/src/platform/linux/x11/window.rs b/crates/gpui/src/platform/linux/x11/window.rs index 1a3c323c35..9fec293fd2 100644 --- a/crates/gpui/src/platform/linux/x11/window.rs +++ b/crates/gpui/src/platform/linux/x11/window.rs @@ -956,79 +956,111 @@ impl X11WindowStatePtr { } pub fn handle_input(&self, input: PlatformInput) { + dbg!("Window: handle_input called", &input); if let Some(ref mut fun) = self.callbacks.borrow_mut().input { - if !fun(input.clone()).propagate { + let result = fun(input.clone()); + dbg!("Window: input callback result", result.propagate); + if !result.propagate { return; } } if let PlatformInput::KeyDown(event) = input { + dbg!("Window: handling KeyDown event", &event.keystroke); // only allow shift modifier when inserting text if event.keystroke.modifiers.is_subset_of(&Modifiers::shift()) { + dbg!("Window: modifiers subset of shift, checking for key_char"); let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { if let Some(key_char) = &event.keystroke.key_char { + dbg!("Window: inserting key_char directly", key_char); drop(state); input_handler.replace_text_in_range(None, key_char); state = self.state.borrow_mut(); } state.input_handler = Some(input_handler); } + } else { + dbg!("Window: modifiers not subset of shift, ignoring key_char insertion"); } } } pub fn handle_ime_commit(&self, text: String) { + dbg!("Window: handle_ime_commit called", &text); let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { + dbg!("Window: got input handler, calling replace_text_in_range"); drop(state); input_handler.replace_text_in_range(None, &text); let mut state = self.state.borrow_mut(); state.input_handler = Some(input_handler); + } else { + dbg!("Window: no input handler available for IME commit"); } } pub fn handle_ime_preedit(&self, text: String) { + dbg!("Window: handle_ime_preedit called", &text); let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { + dbg!("Window: got input handler, calling replace_and_mark_text_in_range"); drop(state); input_handler.replace_and_mark_text_in_range(None, &text, None); let mut state = self.state.borrow_mut(); state.input_handler = Some(input_handler); + } else { + dbg!("Window: no input handler available for IME preedit"); } } pub fn handle_ime_unmark(&self) { + dbg!("Window: handle_ime_unmark called"); let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { + dbg!("Window: got input handler, calling unmark_text"); drop(state); input_handler.unmark_text(); let mut state = self.state.borrow_mut(); state.input_handler = Some(input_handler); + } else { + dbg!("Window: no input handler available for IME unmark"); } } pub fn handle_ime_delete(&self) { + dbg!("Window: handle_ime_delete called"); let mut state = self.state.borrow_mut(); if let Some(mut input_handler) = state.input_handler.take() { drop(state); if let Some(marked) = input_handler.marked_text_range() { + dbg!("Window: found marked text range, deleting", &marked); input_handler.replace_text_in_range(Some(marked), ""); + } else { + dbg!("Window: no marked text range to delete"); } let mut state = self.state.borrow_mut(); state.input_handler = Some(input_handler); + } else { + dbg!("Window: no input handler available for IME delete"); } } pub fn get_ime_area(&self) -> Option> { + dbg!("Window: get_ime_area called"); let mut state = self.state.borrow_mut(); let mut bounds: Option> = None; if let Some(mut input_handler) = state.input_handler.take() { drop(state); if let Some(selection) = input_handler.selected_text_range(true) { bounds = input_handler.bounds_for_range(selection.range); + dbg!("Window: got IME area bounds", bounds); + } else { + dbg!("Window: no selected text range for IME area"); } let mut state = self.state.borrow_mut(); state.input_handler = Some(input_handler); + } else { + dbg!("Window: no input handler available for IME area"); }; bounds } diff --git a/crates/gpui/src/platform/linux/x11/xim_handler.rs b/crates/gpui/src/platform/linux/x11/xim_handler.rs index 82b7c96312..db4e288937 100644 --- a/crates/gpui/src/platform/linux/x11/xim_handler.rs +++ b/crates/gpui/src/platform/linux/x11/xim_handler.rs @@ -31,13 +31,19 @@ impl XimHandler { impl> ClientHandler for XimHandler { fn handle_connect(&mut self, client: &mut C) -> Result<(), ClientError> { - client.open("C") + dbg!("XIM: handle_connect called"); + let result = client.open("C"); + dbg!("XIM: handle_connect result", &result); + result } fn handle_open(&mut self, client: &mut C, input_method_id: u16) -> Result<(), ClientError> { + dbg!("XIM: handle_open called", input_method_id); self.im_id = input_method_id; - client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle]) + let result = client.get_im_values(input_method_id, &[AttributeName::QueryInputStyle]); + dbg!("XIM: handle_open result", &result); + result } fn handle_get_im_values( @@ -61,8 +67,10 @@ impl> ClientHandler for XimHandler _input_method_id: u16, input_context_id: u16, ) -> Result<(), ClientError> { + dbg!("XIM: handle_create_ic called", input_context_id); self.connected = true; self.ic_id = input_context_id; + dbg!("XIM: connection established", self.connected, self.ic_id); Ok(()) } @@ -73,6 +81,7 @@ impl> ClientHandler for XimHandler _input_context_id: u16, text: &str, ) -> Result<(), ClientError> { + dbg!("XIM: handle_commit called", text, self.window); self.last_callback_event = Some(XimCallbackEvent::XimCommitEvent( self.window, String::from(text), @@ -88,21 +97,30 @@ impl> ClientHandler for XimHandler _flag: xim::ForwardEventFlag, xev: C::XEvent, ) -> Result<(), ClientError> { + dbg!("XIM: handle_forward_event called", xev.response_type); match xev.response_type { x11rb::protocol::xproto::KEY_PRESS_EVENT => { + dbg!("XIM: forwarding key press event"); self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyPress(xev))); } x11rb::protocol::xproto::KEY_RELEASE_EVENT => { + dbg!("XIM: forwarding key release event"); self.last_callback_event = Some(XimCallbackEvent::XimXEvent(Event::KeyRelease(xev))); } - _ => {} + _ => { + dbg!("XIM: ignoring event type", xev.response_type); + } } Ok(()) } fn handle_close(&mut self, client: &mut C, _input_method_id: u16) -> Result<(), ClientError> { - client.disconnect() + dbg!("XIM: handle_close called"); + // self.connected = false; + let result = client.disconnect(); + dbg!("XIM: disconnect result", &result); + result } fn handle_preedit_draw( @@ -117,6 +135,14 @@ impl> ClientHandler for XimHandler preedit_string: &str, _feedbacks: Vec, ) -> Result<(), ClientError> { + dbg!( + "XIM: handle_preedit_draw called", + preedit_string, + self.window, + _caret, + _chg_first, + _chg_len + ); // XIMReverse: 1, XIMPrimary: 8, XIMTertiary: 32: selected text // XIMUnderline: 2, XIMSecondary: 16: underlined text // XIMHighlight: 4: normal text