diff options
| author | Kirill Chibisov <contact@kchibisov.com> | 2024-04-19 18:46:39 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-04-23 00:09:42 -0700 |
| commit | 279659ac90eef4082157f427f006c9a4c5a02ac2 (patch) | |
| tree | 6dd7e8a3173727927c091c65b22f575ee7c7dc0c | |
| parent | c2d03d82ceb47322fbe0d93af5a452a83de3b1e1 (diff) | |
| download | niri-279659ac90eef4082157f427f006c9a4c5a02ac2.tar.gz niri-279659ac90eef4082157f427f006c9a4c5a02ac2.tar.bz2 niri-279659ac90eef4082157f427f006c9a4c5a02ac2.zip | |
Unconstrain InputMethod's PopupSurface
Make IME popup to be visible inside the parent and not obscure the
text input rectangle region.
Fixes https://github.com/YaLTeR/niri/issues/221
| -rw-r--r-- | Cargo.lock | 42 | ||||
| -rw-r--r-- | src/handlers/mod.rs | 13 | ||||
| -rw-r--r-- | src/handlers/xdg_shell.rs | 60 | ||||
| -rw-r--r-- | src/niri.rs | 2 |
4 files changed, 87 insertions, 30 deletions
@@ -889,13 +889,13 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "drm" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde" +checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" dependencies = [ "bitflags 2.5.0", "bytemuck", - "drm-ffi", + "drm-ffi 0.8.0", "drm-fourcc", "rustix 0.38.32", ] @@ -906,7 +906,17 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6" dependencies = [ - "drm-sys", + "drm-sys 0.6.1", + "rustix 0.38.32", +] + +[[package]] +name = "drm-ffi" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" +dependencies = [ + "drm-sys 0.7.0", "rustix 0.38.32", ] @@ -927,6 +937,16 @@ dependencies = [ ] [[package]] +name = "drm-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" +dependencies = [ + "libc", + "linux-raw-sys 0.6.4", +] + +[[package]] name = "edid-rs" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1239,11 +1259,11 @@ dependencies = [ [[package]] name = "gbm" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313702b30cdeb83ddc72bc14dcee67803cd0ae2d12282ea06e368c25a900c844" +checksum = "45bf55ba6dd53ad0ac115046ff999c5324c283444ee6e0be82454c4e8eb2f36a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "drm", "drm-fourcc", "gbm-sys", @@ -2149,7 +2169,7 @@ dependencies = [ "calloop 0.13.0", "clap", "directories", - "drm-ffi", + "drm-ffi 0.7.1", "futures-util", "git-version", "glam", @@ -3116,7 +3136,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/Smithay/smithay.git#c5e9a697e41f50dc56b918d9ef1e3d2e52c84ac0" +source = "git+https://github.com/Smithay/smithay.git#40acc58b83400aa10fc62a51a235d1991ab46be5" dependencies = [ "appendlist", "bitflags 2.5.0", @@ -3126,7 +3146,7 @@ dependencies = [ "cursor-icon", "downcast-rs", "drm", - "drm-ffi", + "drm-ffi 0.8.0", "drm-fourcc", "errno", "gbm", @@ -3188,7 +3208,7 @@ dependencies = [ [[package]] name = "smithay-drm-extras" version = "0.1.0" -source = "git+https://github.com/Smithay/smithay.git#c5e9a697e41f50dc56b918d9ef1e3d2e52c84ac0" +source = "git+https://github.com/Smithay/smithay.git#40acc58b83400aa10fc62a51a235d1991ab46be5" dependencies = [ "drm", "edid-rs", diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 28b21b9f..080dd161 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -133,25 +133,34 @@ delegate_pointer_constraints!(State); impl InputMethodHandler for State { fn new_popup(&mut self, surface: PopupSurface) { - let popup = PopupKind::from(surface.clone()); + let popup = PopupKind::InputMethod(surface); if let Some(output) = self.output_for_popup(&popup) { let scale = output.current_scale().integer_scale(); let transform = output.current_transform(); - let wl_surface = surface.wl_surface(); + let wl_surface = popup.wl_surface(); with_states(wl_surface, |data| { send_surface_state(wl_surface, data, scale, transform); }); } + self.unconstrain_popup(&popup); + if let Err(err) = self.niri.popups.track_popup(popup) { warn!("error tracking ime popup {err:?}"); } } + + fn popup_repositioned(&mut self, surface: PopupSurface) { + let popup = PopupKind::InputMethod(surface); + self.unconstrain_popup(&popup); + } + fn dismiss_popup(&mut self, surface: PopupSurface) { if let Some(parent) = surface.get_parent().map(|parent| parent.surface.clone()) { let _ = PopupManager::dismiss_popup(&parent, &PopupKind::from(surface)); } } + fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, Logical> { self.niri .layout diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 1fde1eee..8c496e8e 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -1,5 +1,5 @@ use smithay::desktop::{ - find_popup_root_surface, get_popup_toplevel_coords, layer_map_for_output, LayerSurface, + find_popup_root_surface, get_popup_toplevel_coords, layer_map_for_output, utils, LayerSurface, PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab, PopupUngrabStrategy, Window, WindowSurfaceType, }; @@ -177,7 +177,7 @@ impl XdgShellHandler for State { trace!("new grab for root {:?}", root); keyboard.set_focus(self, grab.current_grab(), serial); - keyboard.set_grab(PopupKeyboardGrab::new(&grab), serial); + keyboard.set_grab(self, PopupKeyboardGrab::new(&grab), serial); pointer.set_grab(self, PopupPointerGrab::new(&grab), serial, Focus::Keep); self.niri.popup_grab = Some(PopupGrabState { root, grab }); } @@ -649,8 +649,11 @@ impl State { popup.send_configure().expect("initial configure failed"); } } - // Input method popups don't require a configure. - PopupKind::InputMethod(_) => (), + // Input method popup can arbitrary change its geometry, so we need to unconstraint + // it on commit. + PopupKind::InputMethod(_) => { + self.unconstrain_popup(&popup); + } } } } @@ -696,14 +699,7 @@ impl State { target.loc.y -= self.niri.layout.window_y(window).unwrap(); target.loc -= get_popup_toplevel_coords(popup); - match popup { - PopupKind::Xdg(popup) => { - popup.with_pending_state(|state| { - state.geometry = unconstrain_with_padding(state.positioner, target); - }); - } - PopupKind::InputMethod(_) => todo!(), - } + self.position_popup_within_rect(popup, target); } pub fn unconstrain_layer_shell_popup( @@ -724,11 +720,43 @@ impl State { target.loc -= layer_geo.loc; target.loc -= get_popup_toplevel_coords(popup); + self.position_popup_within_rect(popup, target); + } + + fn position_popup_within_rect(&self, popup: &PopupKind, target: Rectangle<i32, Logical>) { match popup { - PopupKind::Xdg(popup) => popup.with_pending_state(|state| { - state.geometry = unconstrain_with_padding(state.positioner, target); - }), - PopupKind::InputMethod(_) => todo!(), + PopupKind::Xdg(popup) => { + popup.with_pending_state(|state| { + state.geometry = unconstrain_with_padding(state.positioner, target); + }); + } + PopupKind::InputMethod(popup) => { + let text_input_rectangle = popup.text_input_rectangle(); + let mut bbox = + utils::bbox_from_surface_tree(popup.wl_surface(), text_input_rectangle.loc); + + // Position bbox horizontally first. + let overflow_x = (bbox.loc.x + bbox.size.w) - (target.loc.x + target.size.w); + if overflow_x > 0 { + bbox.loc.x -= overflow_x; + } + + // Ensure that the popup starts within the window. + bbox.loc.x = bbox.loc.x.max(target.loc.x); + + // Try to position IME popup below the text input rectangle. + let mut below = bbox; + below.loc.y += text_input_rectangle.size.h; + + let mut above = bbox; + above.loc.y -= bbox.size.h; + + if target.loc.y + target.size.h >= below.loc.y + below.size.h { + popup.set_location(below.loc); + } else { + popup.set_location(above.loc); + } + } } } diff --git a/src/niri.rs b/src/niri.rs index ae099704..605f5c60 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -768,7 +768,7 @@ impl State { ); grab.grab.ungrab(PopupUngrabStrategy::All); - keyboard.unset_grab(); + keyboard.unset_grab(self); self.niri.seat.get_pointer().unwrap().unset_grab( self, SERIAL_COUNTER.next_serial(), |
