diff options
| author | Kirill Chibisov <contact@kchibisov.com> | 2023-11-02 00:10:22 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-11-08 19:09:11 +0400 |
| commit | 907e0a03efcce6ba35aa6405e130f316bc217c5a (patch) | |
| tree | a7e7aa34c0fabdd055baf69df9f3f2dc17746123 | |
| parent | eb7d20c638e8912747ee21a4b8de95dd27bb7aba (diff) | |
| download | niri-907e0a03efcce6ba35aa6405e130f316bc217c5a.tar.gz niri-907e0a03efcce6ba35aa6405e130f316bc217c5a.tar.bz2 niri-907e0a03efcce6ba35aa6405e130f316bc217c5a.zip | |
Add 'input.keyboard.track_layout' config option
Track layout for each window individually when user requested `Window`
tracking mode, keeping the default as global.
| -rw-r--r-- | resources/default-config.kdl | 5 | ||||
| -rw-r--r-- | src/config.rs | 13 | ||||
| -rw-r--r-- | src/niri.rs | 43 |
3 files changed, 57 insertions, 4 deletions
diff --git a/resources/default-config.kdl b/resources/default-config.kdl index cede85b5..02cbac63 100644 --- a/resources/default-config.kdl +++ b/resources/default-config.kdl @@ -16,6 +16,11 @@ input { // Delay is in milliseconds before the repeat starts. Rate is in characters per second. // repeat-delay 600 // repeat-rate 25 + + // Niri can remember the keyboard layout globally (the default) or per-window. + // - "global" - layout change is global for all windows. + // - "window" - layout is tracked for each window individually. + // track-layout "global" } // Next sections include libinput settings. diff --git a/src/config.rs b/src/config.rs index ac1917bc..b7510d8d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -62,6 +62,8 @@ pub struct Keyboard { pub repeat_delay: u16, #[knuffel(child, unwrap(argument), default = 25)] pub repeat_rate: u8, + #[knuffel(child, unwrap(argument), default)] + pub track_layout: TrackLayout, } #[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)] @@ -78,6 +80,15 @@ pub struct Xkb { pub options: Option<String>, } +#[derive(knuffel::DecodeScalar, Debug, Default, PartialEq, Eq)] +pub enum TrackLayout { + /// The layout change is global. + #[default] + Global, + /// The layout change is window local. + Window, +} + // FIXME: Add the rest of the settings. #[derive(knuffel::Decode, Debug, Default, PartialEq)] pub struct Touchpad { @@ -514,6 +525,7 @@ mod tests { keyboard { repeat-delay 600 repeat-rate 25 + track-layout "window" xkb { layout "us,ru" options "grp:win_space_toggle" @@ -587,6 +599,7 @@ mod tests { }, repeat_delay: 600, repeat_rate: 25, + track_layout: TrackLayout::Window, }, touchpad: Touchpad { tap: true, diff --git a/src/niri.rs b/src/niri.rs index eb1cd243..275358b8 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -1,4 +1,4 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::ffi::OsString; use std::path::PathBuf; @@ -29,7 +29,7 @@ use smithay::desktop::utils::{ under_from_surface_tree, update_surface_primary_scanout_output, OutputPresentationFeedback, }; use smithay::desktop::{layer_map_for_output, PopupManager, Space, Window, WindowSurfaceType}; -use smithay::input::keyboard::XkbConfig; +use smithay::input::keyboard::{Layout as KeyboardLayout, XkbConfig, XkbContextHandler}; use smithay::input::pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus, MotionEvent}; use smithay::input::{Seat, SeatState}; use smithay::output::Output; @@ -76,7 +76,7 @@ use smithay::wayland::text_input::TextInputManagerState; use smithay::wayland::virtual_keyboard::VirtualKeyboardManagerState; use crate::backend::{Backend, RenderResult, Tty, Winit}; -use crate::config::Config; +use crate::config::{Config, TrackLayout}; use crate::cursor::{CursorManager, CursorTextureCache, RenderCursor, XCursor}; #[cfg(feature = "dbus")] use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri}; @@ -382,8 +382,43 @@ impl State { }; let keyboard = self.niri.seat.get_keyboard().unwrap(); - if keyboard.current_focus() != focus { + let current_focus = keyboard.current_focus(); + if current_focus != focus { + if self.niri.config.borrow().input.keyboard.track_layout == TrackLayout::Window { + let current_layout = + keyboard.with_kkb_state(self, |context| context.active_layout()); + + let mut new_layout = current_layout; + // Store the currently active layout for the surface. + if let Some(current_focus) = current_focus.as_ref() { + with_states(current_focus, |data| { + let cell = data + .data_map + .get_or_insert::<Cell<KeyboardLayout>, _>(Cell::default); + cell.set(current_layout); + }); + } + + if let Some(focus) = focus.as_ref() { + new_layout = with_states(focus, |data| { + let cell = data.data_map.get_or_insert::<Cell<KeyboardLayout>, _>(|| { + // The default layout is effectively the first layout in the + // keymap, so use it for new windows. + Cell::new(KeyboardLayout::default()) + }); + cell.get() + }); + } + if new_layout != current_layout && focus.is_some() { + keyboard.set_focus(self, None, SERIAL_COUNTER.next_serial()); + keyboard.with_kkb_state(self, |mut context| { + context.set_layout(new_layout); + }); + } + } + keyboard.set_focus(self, focus, SERIAL_COUNTER.next_serial()); + // FIXME: can be more granular. self.niri.queue_redraw_all(); } |
