toolbar: --state, --set and --run for the Noctalia plugin
This commit is contained in:
1 parent
3d7a4de10a
commit
c8626dbe3e
2 files changed
+144
-10
No files matched your search
+42
-3
@@ -84,7 +84,17 @@ enum Command {
|
||||
file: PathBuf,
|
||||
},
|
||||
/// Pick a mode from a floating bar (Cmd+Shift+5).
|
||||
Toolbar,
|
||||
Toolbar {
|
||||
/// Print the remembered choices as one line of JSON (for the Noctalia plugin).
|
||||
#[arg(long, conflicts_with_all = ["set", "run"])]
|
||||
state: bool,
|
||||
/// Change a remembered choice: mode, timer, cursor, preview or sound.
|
||||
#[arg(long, value_name = "KEY=VALUE", conflicts_with = "run")]
|
||||
set: Vec<String>,
|
||||
/// Capture at once with the remembered choices, without the bar.
|
||||
#[arg(long, value_name = "MODE", num_args = 0..=1)]
|
||||
run: Option<Option<toolbar::state::Mode>>,
|
||||
},
|
||||
/// The paint shader behind niri's overview (keep it running; see the README).
|
||||
Backdrop,
|
||||
/// Report what the compositor and system support.
|
||||
@@ -218,9 +228,24 @@ fn run(cli: Cli) -> Result<()> {
|
||||
// Handled in main, before logging starts.
|
||||
Command::CheckConfig { file } => config::check(&file),
|
||||
Command::ComboDemo => sound::demo(&config::load(&config::default_path())?.sound),
|
||||
Command::Toolbar => {
|
||||
Command::Toolbar { state, set, run } => {
|
||||
let config = config::load(&config::default_path())?;
|
||||
let (mode, common) = from_toolbar(toolbar::run(&config)?);
|
||||
let path = toolbar::state::default_path();
|
||||
if state {
|
||||
println!(
|
||||
"{}",
|
||||
toolbar::state::to_json(&toolbar::state::load(&path, &config))
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
if !set.is_empty() {
|
||||
return toolbar::state::set(&path, &config, &set);
|
||||
}
|
||||
let picked = match run {
|
||||
Some(mode) => toolbar::run_remembered(&config, mode)?,
|
||||
None => toolbar::run(&config)?,
|
||||
};
|
||||
let (mode, common) = from_toolbar(picked);
|
||||
capture(mode, common)
|
||||
}
|
||||
Command::Clipboard => {
|
||||
@@ -473,6 +498,20 @@ mod tests {
|
||||
assert!(!parses(&["edit"]));
|
||||
assert!(parses(&["__clipboard"]));
|
||||
assert!(parses(&["toolbar"]));
|
||||
assert!(parses(&["toolbar", "--state"]));
|
||||
assert!(parses(&[
|
||||
"toolbar",
|
||||
"--set",
|
||||
"timer=5",
|
||||
"--set",
|
||||
"sound=false"
|
||||
]));
|
||||
assert!(parses(&["toolbar", "--run"]));
|
||||
assert!(parses(&["toolbar", "--run", "zoom"]));
|
||||
assert!(!parses(&["toolbar", "--run", "video"]));
|
||||
assert!(!parses(&["toolbar", "--state", "--run"]));
|
||||
assert!(!parses(&["toolbar", "--state", "--set", "timer=5"]));
|
||||
assert!(!parses(&["toolbar", "--set", "timer=5", "--run", "zoom"]));
|
||||
assert!(parses(&["backdrop"]));
|
||||
assert!(parses(&["window", "--pick"]));
|
||||
assert!(parses(&["__combo-demo"]));
|
||||
|
||||
+102
-7
@@ -5,6 +5,7 @@ pub mod draw;
|
||||
pub mod layout;
|
||||
pub mod state;
|
||||
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
@@ -44,6 +45,17 @@ pub struct Picked {
|
||||
pub sound: bool,
|
||||
}
|
||||
|
||||
impl From<ToolbarState> for Picked {
|
||||
fn from(s: ToolbarState) -> Self {
|
||||
Picked {
|
||||
mode: s.mode,
|
||||
cursor: s.cursor,
|
||||
preview: s.preview,
|
||||
sound: s.sound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows the bar, waits for a pick, saves it, runs the countdown.
|
||||
pub fn run(config: &Config) -> Result<Picked> {
|
||||
let path = state::default_path();
|
||||
@@ -58,13 +70,33 @@ pub fn run(config: &Config) -> Result<Picked> {
|
||||
tracing::warn!("could not remember the toolbar choice: {e:#}");
|
||||
}
|
||||
countdown(&mut wl, &output, picked.0.timer)?;
|
||||
let s = picked.0;
|
||||
Ok(Picked {
|
||||
mode: picked.1,
|
||||
cursor: s.cursor,
|
||||
preview: s.preview,
|
||||
sound: s.sound,
|
||||
})
|
||||
Ok(Picked::from(picked.0))
|
||||
}
|
||||
|
||||
/// The remembered state, with `mode` (if given) remembered as the new mode.
|
||||
pub fn remember(path: &Path, config: &Config, mode: Option<Mode>) -> ToolbarState {
|
||||
let mut s = state::load(path, config);
|
||||
if let Some(mode) = mode {
|
||||
s.mode = mode;
|
||||
if let Err(e) = state::save(path, &s) {
|
||||
tracing::warn!("could not remember the toolbar choice: {e:#}");
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// `valw toolbar --run`: the remembered options without the bar (for the
|
||||
/// Noctalia plugin), then the countdown.
|
||||
pub fn run_remembered(config: &Config, mode: Option<Mode>) -> Result<Picked> {
|
||||
let s = remember(&state::default_path(), config, mode);
|
||||
if s.timer > 0 {
|
||||
let mut wl = Wayland::connect()?;
|
||||
let outputs = wl.outputs();
|
||||
anyhow::ensure!(!outputs.is_empty(), "the compositor reported no outputs");
|
||||
let output = outputs[crate::focused_output(&outputs)].clone();
|
||||
countdown(&mut wl, &output, s.timer)?;
|
||||
}
|
||||
Ok(Picked::from(s))
|
||||
}
|
||||
|
||||
pub struct Toolbar {
|
||||
@@ -388,3 +420,66 @@ impl Pill {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn a_pick_carries_the_state_options() {
|
||||
let state = ToolbarState {
|
||||
mode: Mode::Window,
|
||||
timer: 5,
|
||||
cursor: true,
|
||||
preview: false,
|
||||
sound: true,
|
||||
};
|
||||
assert_eq!(
|
||||
Picked::from(state),
|
||||
Picked {
|
||||
mode: Mode::Window,
|
||||
cursor: true,
|
||||
preview: false,
|
||||
sound: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_remembers_a_given_mode() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let path = dir.path().join("toolbar.toml");
|
||||
let config = Config::default();
|
||||
state::save(
|
||||
&path,
|
||||
&ToolbarState {
|
||||
timer: 5,
|
||||
..state::defaults(&config)
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let state = remember(&path, &config, Some(Mode::Zoom));
|
||||
assert_eq!(
|
||||
(state.mode, state.timer),
|
||||
(Mode::Zoom, 5),
|
||||
"the options stay"
|
||||
);
|
||||
assert_eq!(state::load(&path, &config).mode, Mode::Zoom, "saved");
|
||||
|
||||
assert_eq!(
|
||||
remember(&path, &config, None).mode,
|
||||
Mode::Zoom,
|
||||
"no mode: the remembered one"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_without_a_mode_writes_nothing() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let path = dir.path().join("toolbar.toml");
|
||||
let config = Config::default();
|
||||
assert_eq!(remember(&path, &config, None), state::defaults(&config));
|
||||
assert!(!path.exists());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user