Unconstrain the IME popup when it appeared, resized, requested to

repositioned

- places the IME popup correctly.
- adjusts its position to considering the output (screen) rect.
  - offset if right edge overflows
  - flip vertically if bottom edge overflows
This commit is contained in:
KENZ 2026-04-25 07:10:18 +09:00 committed by Jacob Kauffmann
parent 7a10fb1cc8
commit 677be79635
3 changed files with 40 additions and 3 deletions

View file

@ -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;
}

View file

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

View file

@ -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)
}
}
}