Skip to content

Commit

Permalink
Make numlock state on boot configurable
Browse files Browse the repository at this point in the history
This will expose 3 settings for numlock behavior:
1. Numlock is off on boot (this is the current default behavior)
2. Numlock is on on boot
3. Numlock will restore the state from the last boot

Fixes pop-os#369
  • Loading branch information
Nashenas88 committed Dec 21, 2024
1 parent 1118aa2 commit a66e749
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 19 deletions.
18 changes: 17 additions & 1 deletion cosmic-comp-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,29 @@ use std::collections::HashMap;
pub mod input;
pub mod workspace;

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct KeyboardConfig {
/// Boot state for numlock
pub numlock_state: NumlockState,
}

#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum NumlockState {
BootOn,
#[default]
BootOff,
LastBoot,
}

#[derive(Clone, Debug, PartialEq, CosmicConfigEntry)]
#[version = 1]
#[version = 2]
pub struct CosmicCompConfig {
pub workspaces: workspace::WorkspaceConfig,
pub input_default: input::InputConfig,
pub input_touchpad: input::InputConfig,
pub input_devices: HashMap<String, input::InputConfig>,
pub xkb_config: XkbConfig,
pub keyboard_config: KeyboardConfig,
/// Autotiling enabled
pub autotile: bool,
/// Determines the behavior of the autotile variable
Expand Down Expand Up @@ -53,6 +68,7 @@ impl Default for CosmicCompConfig {
},
input_devices: Default::default(),
xkb_config: Default::default(),
keyboard_config: Default::default(),
autotile: Default::default(),
autotile_behavior: Default::default(),
active_hint: true,
Expand Down
37 changes: 36 additions & 1 deletion src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

use crate::state::State;
use anyhow::{Context, Result};
use cosmic_comp_config::NumlockState;
use smithay::backend::input::{self as smithay_input};
use smithay::reexports::{calloop::EventLoop, wayland_server::DisplayHandle};
use smithay::utils::SERIAL_COUNTER;
use tracing::{info, warn};
use xkbcommon::xkb::keysyms;

pub mod render;

Expand Down Expand Up @@ -51,13 +55,44 @@ pub fn init_backend_auto(
.next()
.with_context(|| "Backend initialized without output")
.cloned()?;
let initial_seat = crate::shell::create_seat(
let (initial_seat, keyboard) = crate::shell::create_seat(
dh,
&mut state.common.seat_state,
&output,
&state.common.config,
"seat-0".into(),
);

// Restore numlock state based on config.
let turn_on = match state
.common
.config
.cosmic_conf
.keyboard_config
.numlock_state
{
NumlockState::BootOff => false,
NumlockState::BootOn => true,
NumlockState::LastBoot => state.common.config.dynamic_conf.numlock().last_state,
};

// If we're enabling numlock...
if turn_on {
let mut input = |key_state| {
keyboard.input(
state,
smithay_input::Keycode::from(keysyms::KEY_Num_Lock),
key_state,
SERIAL_COUNTER.next_serial(),
0,
// TODO update internal modifiers?
|_, _, _| smithay::input::keyboard::FilterResult::Intercept(()),
)
};
// Press and release the numlock key to get modifiers updated.
input(smithay_input::KeyState::Pressed);
input(smithay_input::KeyState::Released);
}
state
.common
.shell
Expand Down
36 changes: 36 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub struct Config {
#[derive(Debug)]
pub struct DynamicConfig {
outputs: (Option<PathBuf>, OutputsConfig),
numlock: (Option<PathBuf>, NumlockStateConfig),
}

#[derive(Debug, Deserialize, Serialize)]
Expand All @@ -88,6 +89,11 @@ impl From<Output> for OutputInfo {
}
}

#[derive(Default, Debug, Deserialize, Serialize)]
pub struct NumlockStateConfig {
pub last_state: bool,
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum OutputState {
Expand Down Expand Up @@ -318,9 +324,13 @@ impl Config {
let output_path =
xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok());
let outputs = Self::load_outputs(&output_path);
let numlock_path =
xdg.and_then(|base| base.place_state_file("cosmic-comp/numlock.ron").ok());
let numlock = Self::load_numlock(&numlock_path);

DynamicConfig {
outputs: (output_path, outputs),
numlock: (numlock_path, numlock),
}
}

Expand Down Expand Up @@ -368,6 +378,24 @@ impl Config {
}
}

fn load_numlock(path: &Option<PathBuf>) -> NumlockStateConfig {
path.as_deref()
.filter(|path| path.exists())
.and_then(|path| {
ron::de::from_reader::<_, NumlockStateConfig>(
OpenOptions::new().read(true).open(path).unwrap(),
)
.map_err(|err| {
warn!(?err, "Failed to read numlock.ron, resetting..");
if let Err(err) = std::fs::remove_file(path) {
error!(?err, "Failed to remove numlock.ron.");
}
})
.ok()
})
.unwrap_or_else(|| Default::default())
}

pub fn shortcut_for_action(&self, action: &shortcuts::Action) -> Option<String> {
self.shortcuts.shortcut_for_action(action)
}
Expand Down Expand Up @@ -609,6 +637,14 @@ impl DynamicConfig {
pub fn outputs_mut(&mut self) -> PersistenceGuard<'_, OutputsConfig> {
PersistenceGuard(self.outputs.0.clone(), &mut self.outputs.1)
}

pub fn numlock(&self) -> &NumlockStateConfig {
&self.numlock.1
}

pub fn numlock_mut(&mut self) -> PersistenceGuard<'_, NumlockStateConfig> {
PersistenceGuard(self.numlock.0.clone(), &mut self.numlock.1)
}
}

fn get_config<T: Default + serde::de::DeserializeOwned>(
Expand Down
17 changes: 15 additions & 2 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use calloop::{
timer::{TimeoutAction, Timer},
RegistrationToken,
};
use cosmic_comp_config::workspace::WorkspaceLayout;
use cosmic_comp_config::{workspace::WorkspaceLayout, NumlockState};
use cosmic_settings_config::shortcuts;
use cosmic_settings_config::shortcuts::action::{Direction, ResizeDirection};
use smithay::{
Expand Down Expand Up @@ -69,7 +69,7 @@ use smithay::{
},
};
use tracing::{error, trace};
use xkbcommon::xkb::{Keycode, Keysym};
use xkbcommon::xkb::{keysyms, Keycode, Keysym};

use std::{
any::Any,
Expand Down Expand Up @@ -1449,6 +1449,19 @@ impl State {
event.time() as u64 * 1000,
);

// If we want to track numlock state so it can be reused on the next boot...
if let NumlockState::LastBoot = self.common.config.cosmic_conf.keyboard_config.numlock_state
{
// ... and the numlock key is pressed ...
if event.key_code().raw() == keysyms::KEY_Num_Lock && event.state() == KeyState::Pressed
{
// ... then record the updated config.
// The call to `numlock_mut` will generate a `PersistenceGuard`. The
// `PersistenceGuard` will write to a file when it's dropped here.
self.common.config.dynamic_conf.numlock_mut().last_state = modifiers.num_lock;
}
}

// Leave move overview mode, if any modifier was released
if let Some(Trigger::KeyboardMove(action_modifiers)) =
shell.overview_mode().0.active_trigger()
Expand Down
32 changes: 17 additions & 15 deletions src/shell/seats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use smithay::{
backend::input::{Device, DeviceCapability},
desktop::utils::bbox_from_surface_tree,
input::{
keyboard::{LedState, XkbConfig},
keyboard::{KeyboardHandle, LedState, XkbConfig},
pointer::{CursorImageAttributes, CursorImageStatus},
Seat, SeatState,
},
Expand Down Expand Up @@ -172,7 +172,7 @@ pub fn create_seat(
output: &Output,
config: &Config,
name: String,
) -> Seat<State> {
) -> (Seat<State>, KeyboardHandle<State>) {
let mut seat = seat_state.new_wl_seat(dh, name);
let userdata = seat.user_data();
userdata.insert_if_missing_threadsafe(SeatId::default);
Expand All @@ -197,26 +197,28 @@ pub fn create_seat(
// So instead of doing the right thing (and initialize these capabilities as matching
// devices appear), we have to surrender to reality and just always expose a keyboard and pointer.
let conf = config.xkb_config();
if let Err(err) = seat.add_keyboard(
xkb_config_to_wl(&conf),
(conf.repeat_delay as i32).abs(),
(conf.repeat_rate as i32).abs(),
) {
warn!(
?err,
"Failed to load provided xkb config. Trying default...",
);
seat.add_keyboard(
XkbConfig::default(),
let keyboard = seat
.add_keyboard(
xkb_config_to_wl(&conf),
(conf.repeat_delay as i32).abs(),
(conf.repeat_rate as i32).abs(),
)
.or_else(|err| {
warn!(
?err,
"Failed to load provided xkb config. Trying default...",
);
seat.add_keyboard(
XkbConfig::default(),
(conf.repeat_delay as i32).abs(),
(conf.repeat_rate as i32).abs(),
)
})
.expect("Failed to load xkb configuration files");
}
seat.add_pointer();
seat.add_touch();

seat
(seat, keyboard)
}

pub trait SeatExt {
Expand Down

0 comments on commit a66e749

Please sign in to comment.