diff --git a/src/config/mod.rs b/src/config/mod.rs index 332c3333..777cff86 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -68,6 +68,7 @@ pub struct Config { pub struct DynamicConfig { outputs: (Option, OutputsConfig), numlock: (Option, NumlockStateConfig), + accessibility_zoom: (Option, ZoomState), } #[derive(Debug, Deserialize, Serialize)] @@ -176,6 +177,11 @@ impl OutputConfig { } } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] +pub struct ZoomState { + pub last_level: f64, +} + impl Config { pub fn load(loop_handle: &LoopHandle<'_, State>) -> Config { let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); @@ -314,7 +320,7 @@ impl Config { }; Config { - dynamic_conf: Self::load_dynamic(xdg.as_ref()), + dynamic_conf: Self::load_dynamic(xdg.as_ref(), &cosmic_comp_config), cosmic_conf: cosmic_comp_config, cosmic_helper: config, settings_context, @@ -324,7 +330,10 @@ impl Config { } } - fn load_dynamic(xdg: Option<&xdg::BaseDirectories>) -> DynamicConfig { + fn load_dynamic( + xdg: Option<&xdg::BaseDirectories>, + cosmic: &CosmicCompConfig, + ) -> DynamicConfig { let output_path = xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok()); let outputs = Self::load_outputs(&output_path); @@ -332,9 +341,14 @@ impl Config { xdg.and_then(|base| base.place_state_file("cosmic-comp/numlock.ron").ok()); let numlock = Self::load_numlock(&numlock_path); + let zoom_path = + xdg.and_then(|base| base.place_state_file("cosmic-comp/a11y_zoom.ron").ok()); + let zoom = Self::load_zoom_state(&zoom_path, cosmic); + DynamicConfig { outputs: (output_path, outputs), numlock: (numlock_path, numlock), + accessibility_zoom: (zoom_path, zoom), } } @@ -400,6 +414,35 @@ impl Config { .unwrap_or_default() } + fn load_zoom_state(path: &Option, cosmic: &CosmicCompConfig) -> ZoomState { + if let Some(path) = path.as_ref() { + if path.exists() { + match ron::de::from_reader::<_, ZoomState>( + OpenOptions::new().read(true).open(path).unwrap(), + ) { + Ok(mut config) => { + if config.last_level <= 1.0 { + warn!("Invalid level, resetting"); + config.last_level = + 1.0 + cosmic.accessibility_zoom.increment as f64 / 100.0; + } + return config; + } + Err(err) => { + warn!(?err, "Failed to read zoom_state, resetting.."); + if let Err(err) = std::fs::remove_file(path) { + error!(?err, "Failed to remove zoom_state."); + } + } + }; + } + } + + ZoomState { + last_level: 1.0 + cosmic.accessibility_zoom.increment as f64 / 100.0, + } + } + pub fn shortcut_for_action(&self, action: &shortcuts::Action) -> Option { self.shortcuts.shortcut_for_action(action) } @@ -674,6 +717,17 @@ impl DynamicConfig { pub fn numlock_mut(&mut self) -> PersistenceGuard<'_, NumlockStateConfig> { PersistenceGuard(self.numlock.0.clone(), &mut self.numlock.1) } + + pub fn zoom_state(&self) -> &ZoomState { + &self.accessibility_zoom.1 + } + + pub fn zoom_state_mut(&mut self) -> PersistenceGuard<'_, ZoomState> { + PersistenceGuard( + self.accessibility_zoom.0.clone(), + &mut self.accessibility_zoom.1, + ) + } } fn get_config( @@ -855,6 +909,30 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut "accessibility_zoom" => { let new = get_config::(&config, "accessibility_zoom"); if new != state.common.config.cosmic_conf.accessibility_zoom { + if new.start_on_login + && !state + .common + .config + .cosmic_conf + .accessibility_zoom + .start_on_login + { + let level = state + .common + .shell + .read() + .unwrap() + .zoom_level(None) + .map_or(1., |(_, _, level)| level); + state.common.config.dynamic_conf.zoom_state_mut().last_level = if level + != 1. + { + level + } else { + 1. + state.common.config.cosmic_conf.accessibility_zoom.increment as f64 + / 100. + }; + } state.common.config.cosmic_conf.accessibility_zoom = new; } } diff --git a/src/input/actions.rs b/src/input/actions.rs index 428863d8..5f8e815e 100644 --- a/src/input/actions.rs +++ b/src/input/actions.rs @@ -1032,20 +1032,39 @@ impl State { .zoom_level(None) .map(|(s, _, l)| (s, l)) .unwrap_or_else(|| (seat.clone(), 1.0)); - if &zoom_seat == seat { + + if current_level == 1. && matches!(x, Action::ZoomOut) { + return; + } + let new_level = if current_level == 1. && matches!(x, Action::ZoomIn) { + self.common.config.dynamic_conf.zoom_state().last_level + } else { let increment = self.common.config.cosmic_conf.accessibility_zoom.increment as f64 / 100.0; + match x { + Action::ZoomIn => current_level + increment, + Action::ZoomOut => (current_level - increment).max(1.0), + _ => unreachable!(), + } + }; + + if &zoom_seat == seat { shell.trigger_zoom( seat, - match x { - Action::ZoomIn => current_level + increment, - Action::ZoomOut => (current_level - increment).max(1.0), - _ => unreachable!(), - }, + new_level, self.common.config.cosmic_conf.accessibility_zoom.view_moves, ); - // TODO: persist state, if enable_on_startup + if new_level > 1. + && self + .common + .config + .cosmic_conf + .accessibility_zoom + .start_on_login + { + self.common.config.dynamic_conf.zoom_state_mut().last_level = new_level; + } } }