aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-05 12:58:51 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-05 12:58:59 +0400
commit5225bc9e558cd87ed54271e47dcddaac2d5bcf62 (patch)
tree554fa51a59abc2abad1aefac6d1cf2d5e246b5ec /src
parentbdc86032e44a5c84b4552cd1ad2bbbca07955e23 (diff)
downloadniri-5225bc9e558cd87ed54271e47dcddaac2d5bcf62.tar.gz
niri-5225bc9e558cd87ed54271e47dcddaac2d5bcf62.tar.bz2
niri-5225bc9e558cd87ed54271e47dcddaac2d5bcf62.zip
Add configuration file
Diffstat (limited to 'src')
-rw-r--r--src/config.rs297
-rw-r--r--src/input.rs190
-rw-r--r--src/main.rs22
-rw-r--r--src/niri.rs27
4 files changed, 413 insertions, 123 deletions
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 00000000..a7d6fd7d
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,297 @@
+use std::path::PathBuf;
+use std::str::FromStr;
+
+use bitflags::bitflags;
+use directories::ProjectDirs;
+use miette::{miette, Context, IntoDiagnostic};
+use smithay::input::keyboard::xkb::{keysym_from_name, KEY_NoSymbol, KEYSYM_CASE_INSENSITIVE};
+use smithay::input::keyboard::Keysym;
+
+#[derive(knuffel::Decode, Debug, PartialEq)]
+pub struct Config {
+ #[knuffel(child, default)]
+ pub input: Input,
+ #[knuffel(child, default)]
+ pub binds: Binds,
+}
+
+// FIXME: Add other devices.
+#[derive(knuffel::Decode, Debug, Default, PartialEq)]
+pub struct Input {
+ #[knuffel(child, default)]
+ pub keyboard: Keyboard,
+ #[knuffel(child, default)]
+ pub touchpad: Touchpad,
+}
+
+#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
+pub struct Keyboard {
+ #[knuffel(child, default)]
+ pub xkb: Xkb,
+}
+
+#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
+pub struct Xkb {
+ #[knuffel(child, unwrap(argument), default)]
+ pub rules: String,
+ #[knuffel(child, unwrap(argument), default)]
+ pub model: String,
+ #[knuffel(child, unwrap(argument))]
+ pub layout: Option<String>,
+ #[knuffel(child, unwrap(argument), default)]
+ pub variant: String,
+ #[knuffel(child, unwrap(argument))]
+ pub options: Option<String>,
+}
+
+// FIXME: Add the rest of the settings.
+#[derive(knuffel::Decode, Debug, Default, PartialEq)]
+pub struct Touchpad {
+ #[knuffel(child)]
+ pub tap: bool,
+ #[knuffel(child)]
+ pub natural_scroll: bool,
+ #[knuffel(child, unwrap(argument), default)]
+ pub accel_speed: f64,
+}
+
+#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
+pub struct Binds(#[knuffel(children)] pub Vec<Bind>);
+
+#[derive(knuffel::Decode, Debug, PartialEq, Eq)]
+pub struct Bind {
+ #[knuffel(node_name)]
+ pub key: Key,
+ #[knuffel(children)]
+ pub actions: Vec<Action>,
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct Key {
+ pub keysym: Keysym,
+ pub modifiers: Modifiers,
+}
+
+bitflags! {
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub struct Modifiers : u8 {
+ const CTRL = 1;
+ const SHIFT = 2;
+ const ALT = 4;
+ const SUPER = 8;
+ const COMPOSITOR = 16;
+ }
+}
+
+#[derive(knuffel::Decode, Debug, Clone, PartialEq, Eq)]
+pub enum Action {
+ #[knuffel(skip)]
+ None,
+ Quit,
+ #[knuffel(skip)]
+ ChangeVt(i32),
+ Suspend,
+ ToggleDebugTint,
+ Spawn(#[knuffel(arguments)] Vec<String>),
+ Screenshot,
+ CloseWindow,
+ FullscreenWindow,
+ FocusColumnLeft,
+ FocusColumnRight,
+ FocusWindowDown,
+ FocusWindowUp,
+ MoveColumnLeft,
+ MoveColumnRight,
+ MoveWindowDown,
+ MoveWindowUp,
+ ConsumeWindowIntoColumn,
+ ExpelWindowFromColumn,
+ FocusWorkspaceDown,
+ FocusWorkspaceUp,
+ MoveWindowToWorkspaceDown,
+ MoveWindowToWorkspaceUp,
+ FocusMonitorLeft,
+ FocusMonitorRight,
+ FocusMonitorDown,
+ FocusMonitorUp,
+ MoveWindowToMonitorLeft,
+ MoveWindowToMonitorRight,
+ MoveWindowToMonitorDown,
+ MoveWindowToMonitorUp,
+ SwitchPresetColumnWidth,
+ MaximizeColumn,
+}
+
+impl Config {
+ pub fn load(path: Option<PathBuf>) -> miette::Result<Self> {
+ let path = if let Some(path) = path {
+ path
+ } else {
+ let mut path = ProjectDirs::from("", "", "niri")
+ .ok_or_else(|| miette!("error retrieving home directory"))?
+ .config_dir()
+ .to_owned();
+ path.push("config.kdl");
+ path
+ };
+
+ let contents = std::fs::read_to_string(&path)
+ .into_diagnostic()
+ .with_context(|| format!("error reading {path:?}"))?;
+
+ let config = Self::parse("config.kdl", &contents).context("error parsing")?;
+ debug!("loaded config from {path:?}");
+ Ok(config)
+ }
+
+ pub fn parse(filename: &str, text: &str) -> Result<Self, knuffel::Error> {
+ knuffel::parse(filename, text)
+ }
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Config::parse(
+ "default-config.kdl",
+ include_str!("../resources/default-config.kdl"),
+ )
+ .unwrap()
+ }
+}
+
+impl FromStr for Key {
+ type Err = miette::Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let mut modifiers = Modifiers::empty();
+
+ let mut split = s.split('+');
+ let key = split.next_back().unwrap();
+
+ for part in split {
+ let part = part.trim();
+ if part.eq_ignore_ascii_case("mod") {
+ modifiers |= Modifiers::COMPOSITOR
+ } else if part.eq_ignore_ascii_case("ctrl") || part.eq_ignore_ascii_case("control") {
+ modifiers |= Modifiers::CTRL;
+ } else if part.eq_ignore_ascii_case("shift") {
+ modifiers |= Modifiers::SHIFT;
+ } else if part.eq_ignore_ascii_case("alt") {
+ modifiers |= Modifiers::ALT;
+ } else if part.eq_ignore_ascii_case("super") || part.eq_ignore_ascii_case("win") {
+ modifiers |= Modifiers::SUPER;
+ } else {
+ return Err(miette!("invalid modifier: {part}"));
+ }
+ }
+
+ let keysym = keysym_from_name(key, KEYSYM_CASE_INSENSITIVE);
+ if keysym == KEY_NoSymbol {
+ return Err(miette!("invalid key: {key}"));
+ }
+
+ Ok(Key { keysym, modifiers })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use smithay::input::keyboard::xkb::keysyms::*;
+
+ use super::*;
+
+ #[track_caller]
+ fn check(text: &str, expected: Config) {
+ let parsed = Config::parse("test.kdl", text)
+ .map_err(miette::Report::new)
+ .unwrap();
+ assert_eq!(parsed, expected);
+ }
+
+ #[test]
+ fn parse() {
+ check(
+ r#"
+ input {
+ keyboard {
+ xkb {
+ layout "us,ru"
+ options "grp:win_space_toggle"
+ }
+ }
+
+ touchpad {
+ tap
+ accel-speed 0.2
+ }
+ }
+
+ binds {
+ Mod+T { spawn "alacritty"; }
+ Mod+Q { close-window; }
+ Mod+Shift+H { focus-monitor-left; }
+ Mod+Ctrl+Shift+L { move-window-to-monitor-right; }
+ Mod+Comma { consume-window-into-column; }
+ }
+ "#,
+ Config {
+ input: Input {
+ keyboard: Keyboard {
+ xkb: Xkb {
+ layout: Some("us,ru".to_owned()),
+ options: Some("grp:win_space_toggle".to_owned()),
+ ..Default::default()
+ },
+ },
+ touchpad: Touchpad {
+ tap: true,
+ natural_scroll: false,
+ accel_speed: 0.2,
+ },
+ },
+ binds: Binds(vec![
+ Bind {
+ key: Key {
+ keysym: KEY_t,
+ modifiers: Modifiers::COMPOSITOR,
+ },
+ actions: vec![Action::Spawn(vec!["alacritty".to_owned()])],
+ },
+ Bind {
+ key: Key {
+ keysym: KEY_q,
+ modifiers: Modifiers::COMPOSITOR,
+ },
+ actions: vec![Action::CloseWindow],
+ },
+ Bind {
+ key: Key {
+ keysym: KEY_h,
+ modifiers: Modifiers::COMPOSITOR | Modifiers::SHIFT,
+ },
+ actions: vec![Action::FocusMonitorLeft],
+ },
+ Bind {
+ key: Key {
+ keysym: KEY_l,
+ modifiers: Modifiers::COMPOSITOR | Modifiers::SHIFT | Modifiers::CTRL,
+ },
+ actions: vec![Action::MoveWindowToMonitorRight],
+ },
+ Bind {
+ key: Key {
+ keysym: KEY_comma,
+ modifiers: Modifiers::COMPOSITOR,
+ },
+ actions: vec![Action::ConsumeWindowIntoColumn],
+ },
+ ]),
+ },
+ );
+ }
+
+ #[test]
+ fn can_create_default_config() {
+ let _ = Config::default();
+ }
+}
diff --git a/src/input.rs b/src/input.rs
index 514dcd2c..ad83d331 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -17,45 +17,10 @@ use smithay::input::pointer::{
use smithay::utils::SERIAL_COUNTER;
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
+use crate::config::{Action, Config, Modifiers};
use crate::niri::State;
use crate::utils::get_monotonic_time;
-enum Action {
- None,
- Quit,
- ChangeVt(i32),
- Suspend,
- ToggleDebugTint,
- Spawn(String),
- Screenshot,
- CloseWindow,
- ToggleFullscreen,
- FocusLeft,
- FocusRight,
- FocusDown,
- FocusUp,
- MoveLeft,
- MoveRight,
- MoveDown,
- MoveUp,
- ConsumeIntoColumn,
- ExpelFromColumn,
- SwitchWorkspaceDown,
- SwitchWorkspaceUp,
- MoveToWorkspaceDown,
- MoveToWorkspaceUp,
- FocusMonitorLeft,
- FocusMonitorRight,
- FocusMonitorDown,
- FocusMonitorUp,
- MoveToMonitorLeft,
- MoveToMonitorRight,
- MoveToMonitorDown,
- MoveToMonitorUp,
- ToggleWidth,
- ToggleFullWidth,
-}
-
pub enum CompositorMod {
Super,
Alt,
@@ -70,13 +35,17 @@ impl From<Action> for FilterResult<Action> {
}
}
-fn action(comp_mod: CompositorMod, keysym: KeysymHandle, mods: ModifiersState) -> Action {
+fn action(
+ config: &Config,
+ comp_mod: CompositorMod,
+ keysym: KeysymHandle,
+ mods: ModifiersState,
+) -> Action {
use keysyms::*;
- let modified = keysym.modified_sym();
-
+ // Handle hardcoded binds.
#[allow(non_upper_case_globals)] // wat
- match modified {
+ match keysym.modified_sym() {
modified @ KEY_XF86Switch_VT_1..=KEY_XF86Switch_VT_12 => {
let vt = (modified - KEY_XF86Switch_VT_1 + 1) as i32;
return Action::ChangeVt(vt);
@@ -85,59 +54,45 @@ fn action(comp_mod: CompositorMod, keysym: KeysymHandle, mods: ModifiersState) -
_ => (),
}
- let mod_down = match comp_mod {
- CompositorMod::Super => mods.logo,
- CompositorMod::Alt => mods.alt,
+ // Handle configured binds.
+ let mut modifiers = Modifiers::empty();
+ if mods.ctrl {
+ modifiers |= Modifiers::CTRL;
+ }
+ if mods.shift {
+ modifiers |= Modifiers::SHIFT;
+ }
+ if mods.alt {
+ modifiers |= Modifiers::ALT;
+ }
+ if mods.logo {
+ modifiers |= Modifiers::SUPER;
+ }
+
+ let (mod_down, mut comp_mod) = match comp_mod {
+ CompositorMod::Super => (mods.logo, Modifiers::SUPER),
+ CompositorMod::Alt => (mods.alt, Modifiers::ALT),
};
+ if mod_down {
+ modifiers |= Modifiers::COMPOSITOR;
+ } else {
+ comp_mod = Modifiers::empty();
+ }
- if !mod_down {
+ let Some(&raw) = keysym.raw_syms().first() else {
return Action::None;
- }
+ };
+ for bind in &config.binds.0 {
+ if bind.key.keysym != raw {
+ continue;
+ }
- // FIXME: these don't work in the Russian layout. I guess I'll need to
- // find a US keymap, then map keys somehow.
- #[allow(non_upper_case_globals)] // wat
- match modified {
- KEY_E => Action::Quit,
- KEY_t => Action::Spawn("alacritty".to_owned()),
- KEY_d => Action::Spawn("fuzzel".to_owned()),
- KEY_n => Action::Spawn("nautilus".to_owned()),
- // Alt + PrtSc = SysRq
- KEY_Sys_Req | KEY_Print => Action::Screenshot,
- KEY_T if mods.shift && mods.ctrl => Action::ToggleDebugTint,
- KEY_q => Action::CloseWindow,
- KEY_F => Action::ToggleFullscreen,
- KEY_comma => Action::ConsumeIntoColumn,
- KEY_period => Action::ExpelFromColumn,
- KEY_r => Action::ToggleWidth,
- KEY_f => Action::ToggleFullWidth,
- // Move to monitor.
- KEY_H | KEY_Left if mods.shift && mods.ctrl => Action::MoveToMonitorLeft,
- KEY_L | KEY_Right if mods.shift && mods.ctrl => Action::MoveToMonitorRight,
- KEY_J | KEY_Down if mods.shift && mods.ctrl => Action::MoveToMonitorDown,
- KEY_K | KEY_Up if mods.shift && mods.ctrl => Action::MoveToMonitorUp,
- // Focus monitor.
- KEY_H | KEY_Left if mods.shift => Action::FocusMonitorLeft,
- KEY_L | KEY_Right if mods.shift => Action::FocusMonitorRight,
- KEY_J | KEY_Down if mods.shift => Action::FocusMonitorDown,
- KEY_K | KEY_Up if mods.shift => Action::FocusMonitorUp,
- // Move.
- KEY_h | KEY_Left if mods.ctrl => Action::MoveLeft,
- KEY_l | KEY_Right if mods.ctrl => Action::MoveRight,
- KEY_j | KEY_Down if mods.ctrl => Action::MoveDown,
- KEY_k | KEY_Up if mods.ctrl => Action::MoveUp,
- // Focus.
- KEY_h | KEY_Left => Action::FocusLeft,
- KEY_l | KEY_Right => Action::FocusRight,
- KEY_j | KEY_Down => Action::FocusDown,
- KEY_k | KEY_Up => Action::FocusUp,
- // Workspaces.
- KEY_u if mods.ctrl => Action::MoveToWorkspaceDown,
- KEY_i if mods.ctrl => Action::MoveToWorkspaceUp,
- KEY_u => Action::SwitchWorkspaceDown,
- KEY_i => Action::SwitchWorkspaceUp,
- _ => Action::None,
+ if bind.key.modifiers | comp_mod == modifiers {
+ return bind.actions.first().cloned().unwrap_or(Action::None);
+ }
}
+
+ Action::None
}
impl State {
@@ -166,9 +121,9 @@ impl State {
event.state(),
serial,
time,
- |_, mods, keysym| {
+ |self_, mods, keysym| {
if event.state() == KeyState::Pressed {
- action(comp_mod, keysym, *mods).into()
+ action(&self_.config, comp_mod, keysym, *mods).into()
} else {
FilterResult::Forward
}
@@ -192,8 +147,10 @@ impl State {
self.backend.toggle_debug_tint();
}
Action::Spawn(command) => {
- if let Err(err) = Command::new(command).spawn() {
- warn!("error spawning alacritty: {err}");
+ if let Some((command, args)) = command.split_first() {
+ if let Err(err) = Command::new(command).args(args).spawn() {
+ warn!("error spawning {command}: {err}");
+ }
}
}
Action::Screenshot => {
@@ -211,78 +168,78 @@ impl State {
window.toplevel().send_close();
}
}
- Action::ToggleFullscreen => {
+ Action::FullscreenWindow => {
let focus = self.niri.monitor_set.focus().cloned();
if let Some(window) = focus {
self.niri.monitor_set.toggle_fullscreen(&window);
}
}
- Action::MoveLeft => {
+ Action::MoveColumnLeft => {
self.niri.monitor_set.move_left();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::MoveRight => {
+ Action::MoveColumnRight => {
self.niri.monitor_set.move_right();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::MoveDown => {
+ Action::MoveWindowDown => {
self.niri.monitor_set.move_down();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::MoveUp => {
+ Action::MoveWindowUp => {
self.niri.monitor_set.move_up();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::FocusLeft => {
+ Action::FocusColumnLeft => {
self.niri.monitor_set.focus_left();
}
- Action::FocusRight => {
+ Action::FocusColumnRight => {
self.niri.monitor_set.focus_right();
}
- Action::FocusDown => {
+ Action::FocusWindowDown => {
self.niri.monitor_set.focus_down();
}
- Action::FocusUp => {
+ Action::FocusWindowUp => {
self.niri.monitor_set.focus_up();
}
- Action::MoveToWorkspaceDown => {
+ Action::MoveWindowToWorkspaceDown => {
self.niri.monitor_set.move_to_workspace_down();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::MoveToWorkspaceUp => {
+ Action::MoveWindowToWorkspaceUp => {
self.niri.monitor_set.move_to_workspace_up();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::SwitchWorkspaceDown => {
+ Action::FocusWorkspaceDown => {
self.niri.monitor_set.switch_workspace_down();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::SwitchWorkspaceUp => {
+ Action::FocusWorkspaceUp => {
self.niri.monitor_set.switch_workspace_up();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::ConsumeIntoColumn => {
+ Action::ConsumeWindowIntoColumn => {
self.niri.monitor_set.consume_into_column();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::ExpelFromColumn => {
+ Action::ExpelWindowFromColumn => {
self.niri.monitor_set.expel_from_column();
// FIXME: granular
self.niri.queue_redraw_all();
}
- Action::ToggleWidth => {
+ Action::SwitchPresetColumnWidth => {
self.niri.monitor_set.toggle_width();
}
- Action::ToggleFullWidth => {
+ Action::MaximizeColumn => {
self.niri.monitor_set.toggle_full_width();
}
Action::FocusMonitorLeft => {
@@ -309,25 +266,25 @@ impl State {
self.move_cursor_to_output(&output);
}
}
- Action::MoveToMonitorLeft => {
+ Action::MoveWindowToMonitorLeft => {
if let Some(output) = self.niri.output_left() {
self.niri.monitor_set.move_to_output(&output);
self.move_cursor_to_output(&output);
}
}
- Action::MoveToMonitorRight => {
+ Action::MoveWindowToMonitorRight => {
if let Some(output) = self.niri.output_right() {
self.niri.monitor_set.move_to_output(&output);
self.move_cursor_to_output(&output);
}
}
- Action::MoveToMonitorDown => {
+ Action::MoveWindowToMonitorDown => {
if let Some(output) = self.niri.output_down() {
self.niri.monitor_set.move_to_output(&output);
self.move_cursor_to_output(&output);
}
}
- Action::MoveToMonitorUp => {
+ Action::MoveWindowToMonitorUp => {
if let Some(output) = self.niri.output_up() {
self.niri.monitor_set.move_to_output(&output);
self.move_cursor_to_output(&output);
@@ -740,9 +697,10 @@ impl State {
// According to Mutter code, this setting is specific to touchpads.
let is_touchpad = device.config_tap_finger_count() > 0;
if is_touchpad {
- let _ = device.config_tap_set_enabled(true);
- let _ = device.config_scroll_set_natural_scroll_enabled(true);
- let _ = device.config_accel_set_speed(0.2);
+ let c = &self.config.input.touchpad;
+ let _ = device.config_tap_set_enabled(c.tap);
+ let _ = device.config_scroll_set_natural_scroll_enabled(c.natural_scroll);
+ let _ = device.config_accel_set_speed(c.accel_speed);
}
}
}
diff --git a/src/main.rs b/src/main.rs
index 9af30d43..f71a959a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ extern crate tracing;
mod animation;
mod backend;
+mod config;
mod dbus;
mod frame_clock;
mod handlers;
@@ -13,8 +14,11 @@ mod utils;
use std::env;
use std::ffi::OsString;
+use std::path::PathBuf;
use clap::Parser;
+use config::Config;
+use miette::Context;
use niri::{Niri, State};
use smithay::reexports::calloop::EventLoop;
use smithay::reexports::wayland_server::Display;
@@ -23,6 +27,9 @@ use tracing_subscriber::EnvFilter;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
+ /// Path to config file (default: `$XDG_CONFIG_HOME/niri/config.kdl`).
+ #[arg(short, long)]
+ config: Option<PathBuf>,
/// Command to run upon compositor startup.
#[arg(last = true)]
command: Vec<OsString>,
@@ -47,9 +54,22 @@ fn main() {
let _client = tracy_client::Client::start();
+ let config = match Config::load(cli.config).context("error loading config") {
+ Ok(config) => config,
+ Err(err) => {
+ warn!("{err:?}");
+ Config::default()
+ }
+ };
+
let mut event_loop = EventLoop::try_new().unwrap();
let mut display = Display::new().unwrap();
- let state = State::new(event_loop.handle(), event_loop.get_signal(), &mut display);
+ let state = State::new(
+ config,
+ event_loop.handle(),
+ event_loop.get_signal(),
+ &mut display,
+ );
let mut data = LoopData { display, state };
if let Some((command, args)) = cli.command.split_first() {
diff --git a/src/niri.rs b/src/niri.rs
index 88a11e8f..23b8f3b1 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -56,6 +56,7 @@ use smithay::wayland::tablet_manager::TabletManagerState;
use time::OffsetDateTime;
use crate::backend::{Backend, Tty, Winit};
+use crate::config::Config;
use crate::dbus::mutter_service_channel::ServiceChannel;
use crate::frame_clock::FrameClock;
use crate::layout::{MonitorRenderElement, MonitorSet};
@@ -115,12 +116,14 @@ pub struct OutputState {
}
pub struct State {
+ pub config: Config,
pub backend: Backend,
pub niri: Niri,
}
impl State {
pub fn new(
+ config: Config,
event_loop: LoopHandle<'static, LoopData>,
stop_signal: LoopSignal,
display: &mut Display<State>,
@@ -134,10 +137,20 @@ impl State {
Backend::Tty(Tty::new(event_loop.clone()))
};
- let mut niri = Niri::new(event_loop, stop_signal, display, backend.seat_name());
+ let mut niri = Niri::new(
+ &config,
+ event_loop,
+ stop_signal,
+ display,
+ backend.seat_name(),
+ );
backend.init(&mut niri);
- Self { backend, niri }
+ Self {
+ config,
+ backend,
+ niri,
+ }
}
pub fn move_cursor(&mut self, location: Point<f64, Logical>) {
@@ -178,6 +191,7 @@ impl State {
impl Niri {
pub fn new(
+ config: &Config,
event_loop: LoopHandle<'static, LoopData>,
stop_signal: LoopSignal,
display: &mut Display<State>,
@@ -202,11 +216,12 @@ impl Niri {
PresentationState::new::<State>(&display_handle, CLOCK_MONOTONIC as u32);
let mut seat: Seat<State> = seat_state.new_wl_seat(&display_handle, seat_name);
- // FIXME: get Xkb and repeat interval from GNOME dconf.
let xkb = XkbConfig {
- layout: "us,ru",
- options: Some("grp:win_space_toggle,compose:ralt,ctrl:nocaps".to_owned()),
- ..Default::default()
+ rules: &config.input.keyboard.xkb.rules,
+ model: &config.input.keyboard.xkb.model,
+ layout: &config.input.keyboard.xkb.layout.as_deref().unwrap_or("us"),
+ variant: &config.input.keyboard.xkb.variant,
+ options: config.input.keyboard.xkb.options.clone(),
};
seat.add_keyboard(xkb, 400, 30).unwrap();
seat.add_pointer();