diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.rs | 13 | ||||
| -rw-r--r-- | src/niri.rs | 43 |
2 files changed, 52 insertions, 4 deletions
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(); } |
