fix

Smit Barmase created

Change summary

crates/gpui/src/platform/linux/x11/client.rs      | 51 ++++++++++++++--
crates/gpui/src/platform/linux/x11/window.rs      | 34 +++++++++++
crates/gpui/src/platform/linux/x11/xim_handler.rs | 34 ++++++++++-
3 files changed, 107 insertions(+), 12 deletions(-)

Detailed changes

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);

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<Bounds<Pixels>> {
+        dbg!("Window: get_ime_area called");
         let mut state = self.state.borrow_mut();
         let mut bounds: Option<Bounds<Pixels>> = 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
     }

crates/gpui/src/platform/linux/x11/xim_handler.rs 🔗

@@ -31,13 +31,19 @@ impl XimHandler {
 
 impl<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> 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<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> 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<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> 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<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> 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<C: Client<XEvent = xproto::KeyPressEvent>> ClientHandler<C> for XimHandler
         preedit_string: &str,
         _feedbacks: Vec<xim::Feedback>,
     ) -> 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