diff --git a/src/wayland/handlers/compositor.rs b/src/wayland/handlers/compositor.rs index 19ef2b7d..b972a603 100644 --- a/src/wayland/handlers/compositor.rs +++ b/src/wayland/handlers/compositor.rs @@ -281,6 +281,10 @@ impl CompositorHandler for State { if let Some(popup) = self.common.popups.find_popup(surface) { xdg_popup_ensure_initial_configure(&popup); + // The IME popup need to be repositioned when the size changed + if let PopupKind::InputMethod(_) = popup { + shell.unconstrain_popup(&popup); + } return; } diff --git a/src/wayland/handlers/input_method.rs b/src/wayland/handlers/input_method.rs index 5b4aa59a..8b92461b 100644 --- a/src/wayland/handlers/input_method.rs +++ b/src/wayland/handlers/input_method.rs @@ -12,6 +12,11 @@ use tracing::warn; impl InputMethodHandler for State { fn new_popup(&mut self, surface: PopupSurface) { + self.common + .shell + .read() + .unconstrain_popup(&PopupKind::from(surface.clone())); + if let Err(err) = self.common.popups.track_popup(PopupKind::from(surface)) { warn!("Failed to track popup: {}", err); } @@ -32,7 +37,9 @@ impl InputMethodHandler for State { .unwrap_or_default() } - fn popup_repositioned(&mut self, _: PopupSurface) {} + fn popup_repositioned(&mut self, popup: PopupSurface) { + self.common.shell.read().unconstrain_popup(&popup.into()); + } } delegate_input_method_manager!(State); diff --git a/src/wayland/handlers/xdg_shell/popup.rs b/src/wayland/handlers/xdg_shell/popup.rs index 15aeed31..965e8908 100644 --- a/src/wayland/handlers/xdg_shell/popup.rs +++ b/src/wayland/handlers/xdg_shell/popup.rs @@ -4,7 +4,7 @@ use crate::{shell::Shell, utils::prelude::*}; use smithay::{ desktop::{ LayerSurface, PopupKind, PopupManager, WindowSurfaceType, get_popup_toplevel_coords, - layer_map_for_output, space::SpaceElement, + layer_map_for_output, space::SpaceElement, utils, }, output::Output, reexports::{ @@ -175,7 +175,33 @@ fn position_popup_within_rect( }); rect.contains_rect(geometry) } - PopupKind::InputMethod(_) => false, + PopupKind::InputMethod(popup) => { + let input_rect = popup.text_input_rectangle(); + + // We basically place the IME popup below the input rect. + let mut popup_bbox = utils::bbox_from_surface_tree(popup.wl_surface(), input_rect.loc); + popup_bbox.loc.y += input_rect.size.h; + // tracing::debug!( + // "IME input_rect: {:?}, popup_bbox: {:?}", + // input_rect, + // popup_bbox + // ); + + // Handle the right edge overflow + let popup_right = popup_bbox.loc.x + popup_bbox.size.w; + let rect_right = rect.loc.x + rect.size.w; + popup_bbox.loc.x -= (popup_right - rect_right).max(0); + + // Flip vertically if the bottom edge overflows + let popup_bottom = popup_bbox.loc.y + popup_bbox.size.h; + let rect_bottom = rect.loc.y + rect.size.h; + if popup_bottom > rect_bottom { + popup_bbox.loc.y = input_rect.loc.y - popup_bbox.size.h; + } + + popup.set_location(popup_bbox.loc); + rect.as_logical().contains_rect(popup_bbox) + } } }