mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
Add 'input.keyboard.track_layout' config option
Track layout for each window individually when user requested `Window` tracking mode, keeping the default as global.
This commit is contained in:
committed by
Ivan Molodetskikh
parent
eb7d20c638
commit
907e0a03ef
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
+39
-4
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user