Add --path argument for niri msg screenshot* commands (#2126)

* Check for empty screenshot parent before creating

Avoids a warning.

* Add --path argument for niri msg screenshot* commands

* fix

---------

Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
This commit is contained in:
Lin Xianyi
2025-10-19 11:22:31 +00:00
committed by GitHub
parent 8c8447918f
commit 23cd5aa78a
8 changed files with 178 additions and 58 deletions
+26 -6
View File
@@ -118,16 +118,27 @@ pub enum Action {
CancelScreenshot, CancelScreenshot,
#[knuffel(skip)] #[knuffel(skip)]
ScreenshotTogglePointer, ScreenshotTogglePointer,
Screenshot(#[knuffel(property(name = "show-pointer"), default = true)] bool), Screenshot(
#[knuffel(property(name = "show-pointer"), default = true)] bool,
// Path; not settable from knuffel
Option<String>,
),
ScreenshotScreen( ScreenshotScreen(
#[knuffel(property(name = "write-to-disk"), default = true)] bool, #[knuffel(property(name = "write-to-disk"), default = true)] bool,
#[knuffel(property(name = "show-pointer"), default = true)] bool, #[knuffel(property(name = "show-pointer"), default = true)] bool,
// Path; not settable from knuffel
Option<String>,
),
ScreenshotWindow(
#[knuffel(property(name = "write-to-disk"), default = true)] bool,
// Path; not settable from knuffel
Option<String>,
), ),
ScreenshotWindow(#[knuffel(property(name = "write-to-disk"), default = true)] bool),
#[knuffel(skip)] #[knuffel(skip)]
ScreenshotWindowById { ScreenshotWindowById {
id: u64, id: u64,
write_to_disk: bool, write_to_disk: bool,
path: Option<String>,
}, },
ToggleKeyboardShortcutsInhibit, ToggleKeyboardShortcutsInhibit,
CloseWindow, CloseWindow,
@@ -364,19 +375,28 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::Spawn { command } => Self::Spawn(command), niri_ipc::Action::Spawn { command } => Self::Spawn(command),
niri_ipc::Action::SpawnSh { command } => Self::SpawnSh(command), niri_ipc::Action::SpawnSh { command } => Self::SpawnSh(command),
niri_ipc::Action::DoScreenTransition { delay_ms } => Self::DoScreenTransition(delay_ms), niri_ipc::Action::DoScreenTransition { delay_ms } => Self::DoScreenTransition(delay_ms),
niri_ipc::Action::Screenshot { show_pointer } => Self::Screenshot(show_pointer), niri_ipc::Action::Screenshot { show_pointer, path } => {
Self::Screenshot(show_pointer, path)
}
niri_ipc::Action::ScreenshotScreen { niri_ipc::Action::ScreenshotScreen {
write_to_disk, write_to_disk,
show_pointer, show_pointer,
} => Self::ScreenshotScreen(write_to_disk, show_pointer), path,
} => Self::ScreenshotScreen(write_to_disk, show_pointer, path),
niri_ipc::Action::ScreenshotWindow { niri_ipc::Action::ScreenshotWindow {
id: None, id: None,
write_to_disk, write_to_disk,
} => Self::ScreenshotWindow(write_to_disk), path,
} => Self::ScreenshotWindow(write_to_disk, path),
niri_ipc::Action::ScreenshotWindow { niri_ipc::Action::ScreenshotWindow {
id: Some(id), id: Some(id),
write_to_disk, write_to_disk,
} => Self::ScreenshotWindowById { id, write_to_disk }, path,
} => Self::ScreenshotWindowById {
id,
write_to_disk,
path,
},
niri_ipc::Action::ToggleKeyboardShortcutsInhibit {} => { niri_ipc::Action::ToggleKeyboardShortcutsInhibit {} => {
Self::ToggleKeyboardShortcutsInhibit Self::ToggleKeyboardShortcutsInhibit
} }
+24
View File
@@ -220,6 +220,14 @@ pub enum Action {
/// Whether to show the mouse pointer by default in the screenshot UI. /// Whether to show the mouse pointer by default in the screenshot UI.
#[cfg_attr(feature = "clap", arg(short = 'p', long, action = clap::ArgAction::Set, default_value_t = true))] #[cfg_attr(feature = "clap", arg(short = 'p', long, action = clap::ArgAction::Set, default_value_t = true))]
show_pointer: bool, show_pointer: bool,
/// Path to save the screenshot to.
///
/// The path must be absolute, otherwise an error is returned.
///
/// If `None`, the screenshot is saved according to the `screenshot-path` config setting.
#[cfg_attr(feature = "clap", arg(long, action = clap::ArgAction::Set))]
path: Option<String>,
}, },
/// Screenshot the focused screen. /// Screenshot the focused screen.
ScreenshotScreen { ScreenshotScreen {
@@ -232,6 +240,14 @@ pub enum Action {
/// Whether to include the mouse pointer in the screenshot. /// Whether to include the mouse pointer in the screenshot.
#[cfg_attr(feature = "clap", arg(short = 'p', long, action = clap::ArgAction::Set, default_value_t = true))] #[cfg_attr(feature = "clap", arg(short = 'p', long, action = clap::ArgAction::Set, default_value_t = true))]
show_pointer: bool, show_pointer: bool,
/// Path to save the screenshot to.
///
/// The path must be absolute, otherwise an error is returned.
///
/// If `None`, the screenshot is saved according to the `screenshot-path` config setting.
#[cfg_attr(feature = "clap", arg(long, action = clap::ArgAction::Set))]
path: Option<String>,
}, },
/// Screenshot a window. /// Screenshot a window.
#[cfg_attr(feature = "clap", clap(about = "Screenshot the focused window"))] #[cfg_attr(feature = "clap", clap(about = "Screenshot the focused window"))]
@@ -246,6 +262,14 @@ pub enum Action {
/// The screenshot is saved according to the `screenshot-path` config setting. /// The screenshot is saved according to the `screenshot-path` config setting.
#[cfg_attr(feature = "clap", arg(short = 'd', long, action = clap::ArgAction::Set, default_value_t = true))] #[cfg_attr(feature = "clap", arg(short = 'd', long, action = clap::ArgAction::Set, default_value_t = true))]
write_to_disk: bool, write_to_disk: bool,
/// Path to save the screenshot to.
///
/// The path must be absolute, otherwise an error is returned.
///
/// If `None`, the screenshot is saved according to the `screenshot-path` config setting.
#[cfg_attr(feature = "clap", arg(long, action = clap::ArgAction::Set))]
path: Option<String>,
}, },
/// Enable or disable the keyboard shortcuts inhibitor (if any) for the focused surface. /// Enable or disable the keyboard shortcuts inhibitor (if any) for the focused surface.
ToggleKeyboardShortcutsInhibit {}, ToggleKeyboardShortcutsInhibit {},
+30 -17
View File
@@ -605,14 +605,17 @@ impl State {
self.niri.do_screen_transition(renderer, delay_ms); self.niri.do_screen_transition(renderer, delay_ms);
}); });
} }
Action::ScreenshotScreen(write_to_disk, show_pointer) => { Action::ScreenshotScreen(write_to_disk, show_pointer, path) => {
let active = self.niri.layout.active_output().cloned(); let active = self.niri.layout.active_output().cloned();
if let Some(active) = active { if let Some(active) = active {
self.backend.with_primary_renderer(|renderer| { self.backend.with_primary_renderer(|renderer| {
if let Err(err) = if let Err(err) = self.niri.screenshot(
self.niri renderer,
.screenshot(renderer, &active, write_to_disk, show_pointer) &active,
{ write_to_disk,
show_pointer,
path,
) {
warn!("error taking screenshot: {err:?}"); warn!("error taking screenshot: {err:?}");
} }
}); });
@@ -636,32 +639,42 @@ impl State {
self.niri.screenshot_ui.toggle_pointer(); self.niri.screenshot_ui.toggle_pointer();
self.niri.queue_redraw_all(); self.niri.queue_redraw_all();
} }
Action::Screenshot(show_cursor) => { Action::Screenshot(show_cursor, path) => {
self.open_screenshot_ui(show_cursor); self.open_screenshot_ui(show_cursor, path);
} }
Action::ScreenshotWindow(write_to_disk) => { Action::ScreenshotWindow(write_to_disk, path) => {
let focus = self.niri.layout.focus_with_output(); let focus = self.niri.layout.focus_with_output();
if let Some((mapped, output)) = focus { if let Some((mapped, output)) = focus {
self.backend.with_primary_renderer(|renderer| { self.backend.with_primary_renderer(|renderer| {
if let Err(err) = if let Err(err) = self.niri.screenshot_window(
self.niri renderer,
.screenshot_window(renderer, output, mapped, write_to_disk) output,
{ mapped,
write_to_disk,
path,
) {
warn!("error taking screenshot: {err:?}"); warn!("error taking screenshot: {err:?}");
} }
}); });
} }
} }
Action::ScreenshotWindowById { id, write_to_disk } => { Action::ScreenshotWindowById {
id,
write_to_disk,
path,
} => {
let mut windows = self.niri.layout.windows(); let mut windows = self.niri.layout.windows();
let window = windows.find(|(_, m)| m.id().get() == id); let window = windows.find(|(_, m)| m.id().get() == id);
if let Some((Some(monitor), mapped)) = window { if let Some((Some(monitor), mapped)) = window {
let output = monitor.output(); let output = monitor.output();
self.backend.with_primary_renderer(|renderer| { self.backend.with_primary_renderer(|renderer| {
if let Err(err) = if let Err(err) = self.niri.screenshot_window(
self.niri renderer,
.screenshot_window(renderer, output, mapped, write_to_disk) output,
{ mapped,
write_to_disk,
path,
) {
warn!("error taking screenshot: {err:?}"); warn!("error taking screenshot: {err:?}");
} }
}); });
+31 -4
View File
@@ -1,20 +1,34 @@
use std::io::ErrorKind; use std::io::ErrorKind;
use std::iter::Peekable; use std::iter::Peekable;
use std::slice; use std::path::Path;
use std::{env, slice};
use anyhow::{anyhow, bail, Context}; use anyhow::{anyhow, bail, Context};
use niri_config::OutputName; use niri_config::OutputName;
use niri_ipc::socket::Socket; use niri_ipc::socket::Socket;
use niri_ipc::{ use niri_ipc::{
Event, KeyboardLayouts, LogicalOutput, Mode, Output, OutputConfigChanged, Overview, Request, Action, Event, KeyboardLayouts, LogicalOutput, Mode, Output, OutputConfigChanged, Overview,
Response, Transform, Window, WindowLayout, Request, Response, Transform, Window, WindowLayout,
}; };
use serde_json::json; use serde_json::json;
use crate::cli::Msg; use crate::cli::Msg;
use crate::utils::version; use crate::utils::version;
pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> { pub fn handle_msg(mut msg: Msg, json: bool) -> anyhow::Result<()> {
// For actions taking paths, prepend the niri CLI's working directory.
if let Msg::Action {
action:
Action::Screenshot { path, .. }
| Action::ScreenshotScreen { path, .. }
| Action::ScreenshotWindow { path, .. },
} = &mut msg
{
if let Some(path) = path {
ensure_absolute_path(path).context("error making the path absolute")?;
}
}
let request = match &msg { let request = match &msg {
Msg::Version => Request::Version, Msg::Version => Request::Version,
Msg::Outputs => Request::Outputs, Msg::Outputs => Request::Outputs,
@@ -668,6 +682,19 @@ fn fmt_rounded(x: f64) -> String {
} }
} }
fn ensure_absolute_path(path: &mut String) -> anyhow::Result<()> {
let p = Path::new(path);
if p.is_relative() {
let mut cwd = env::current_dir().context("error getting current working directory")?;
cwd.push(p);
match cwd.into_os_string().into_string() {
Ok(absolute) => *path = absolute,
Err(cwd) => bail!("couldn't convert absolute path to string: {cwd:?}"),
}
}
Ok(())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use insta::assert_snapshot; use insta::assert_snapshot;
+22 -3
View File
@@ -2,7 +2,7 @@ use std::cell::RefCell;
use std::collections::HashSet; use std::collections::HashSet;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::os::unix::net::{UnixListener, UnixStream}; use std::os::unix::net::{UnixListener, UnixStream};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::{env, io, process}; use std::{env, io, process};
@@ -17,8 +17,8 @@ use futures_util::{select_biased, AsyncBufReadExt, AsyncWrite, AsyncWriteExt, Fu
use niri_config::OutputName; use niri_config::OutputName;
use niri_ipc::state::{EventStreamState, EventStreamStatePart as _}; use niri_ipc::state::{EventStreamState, EventStreamStatePart as _};
use niri_ipc::{ use niri_ipc::{
Event, KeyboardLayouts, OutputConfigChanged, Overview, Reply, Request, Response, WindowLayout, Action, Event, KeyboardLayouts, OutputConfigChanged, Overview, Reply, Request, Response,
Workspace, WindowLayout, Workspace,
}; };
use smithay::desktop::layer_map_for_output; use smithay::desktop::layer_map_for_output;
use smithay::input::pointer::{ use smithay::input::pointer::{
@@ -379,6 +379,8 @@ async fn process(ctx: &ClientCtx, request: Request) -> Reply {
Response::PickedColor(color) Response::PickedColor(color)
} }
Request::Action(action) => { Request::Action(action) => {
validate_action(&action)?;
let (tx, rx) = async_channel::bounded(1); let (tx, rx) = async_channel::bounded(1);
let action = niri_config::Action::from(action); let action = niri_config::Action::from(action);
@@ -451,6 +453,23 @@ async fn process(ctx: &ClientCtx, request: Request) -> Reply {
Ok(response) Ok(response)
} }
fn validate_action(action: &Action) -> Result<(), String> {
if let Action::Screenshot { path, .. }
| Action::ScreenshotScreen { path, .. }
| Action::ScreenshotWindow { path, .. } = action
{
if let Some(path) = path {
// Relative paths are resolved against the niri compositor's working directory, which
// is almost certainly not what you want.
if !Path::new(path).is_absolute() {
return Err(format!("path must be absolute: {path}"));
}
}
}
Ok(())
}
async fn handle_event_stream_client(client: EventStreamClient) -> anyhow::Result<()> { async fn handle_event_stream_client(client: EventStreamClient) -> anyhow::Result<()> {
let EventStreamClient { let EventStreamClient {
events, events,
+24 -10
View File
@@ -1835,7 +1835,7 @@ impl State {
self.niri.output_management_state.notify_changes(new_config); self.niri.output_management_state.notify_changes(new_config);
} }
pub fn open_screenshot_ui(&mut self, show_pointer: bool) { pub fn open_screenshot_ui(&mut self, show_pointer: bool, path: Option<String>) {
if self.niri.is_locked() || self.niri.screenshot_ui.is_open() { if self.niri.is_locked() || self.niri.screenshot_ui.is_open() {
return; return;
} }
@@ -1876,7 +1876,7 @@ impl State {
self.backend.with_primary_renderer(|renderer| { self.backend.with_primary_renderer(|renderer| {
self.niri self.niri
.screenshot_ui .screenshot_ui
.open(renderer, screenshots, default_output, show_pointer) .open(renderer, screenshots, default_output, show_pointer, path)
}); });
self.niri self.niri
@@ -1902,14 +1902,15 @@ impl State {
} }
pub fn confirm_screenshot(&mut self, write_to_disk: bool) { pub fn confirm_screenshot(&mut self, write_to_disk: bool) {
if !self.niri.screenshot_ui.is_open() { let ScreenshotUi::Open { path, .. } = &mut self.niri.screenshot_ui else {
return; return;
} };
let path = path.take();
self.backend.with_primary_renderer(|renderer| { self.backend.with_primary_renderer(|renderer| {
match self.niri.screenshot_ui.capture(renderer) { match self.niri.screenshot_ui.capture(renderer) {
Ok((size, pixels)) => { Ok((size, pixels)) => {
if let Err(err) = self.niri.save_screenshot(size, pixels, write_to_disk) { if let Err(err) = self.niri.save_screenshot(size, pixels, write_to_disk, path) {
warn!("error saving screenshot: {err:?}"); warn!("error saving screenshot: {err:?}");
} }
} }
@@ -5533,6 +5534,7 @@ impl Niri {
output: &Output, output: &Output,
write_to_disk: bool, write_to_disk: bool,
include_pointer: bool, include_pointer: bool,
path: Option<String>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let _span = tracy_client::span!("Niri::screenshot"); let _span = tracy_client::span!("Niri::screenshot");
@@ -5559,7 +5561,7 @@ impl Niri {
elements, elements,
)?; )?;
self.save_screenshot(size, pixels, write_to_disk) self.save_screenshot(size, pixels, write_to_disk, path)
.context("error saving screenshot") .context("error saving screenshot")
} }
@@ -5569,6 +5571,7 @@ impl Niri {
output: &Output, output: &Output,
mapped: &Mapped, mapped: &Mapped,
write_to_disk: bool, write_to_disk: bool,
path: Option<String>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let _span = tracy_client::span!("Niri::screenshot_window"); let _span = tracy_client::span!("Niri::screenshot_window");
@@ -5600,7 +5603,7 @@ impl Niri {
elements, elements,
)?; )?;
self.save_screenshot(geo.size, pixels, write_to_disk) self.save_screenshot(geo.size, pixels, write_to_disk, path)
.context("error saving screenshot") .context("error saving screenshot")
} }
@@ -5609,14 +5612,20 @@ impl Niri {
size: Size<i32, Physical>, size: Size<i32, Physical>,
pixels: Vec<u8>, pixels: Vec<u8>,
write_to_disk: bool, write_to_disk: bool,
path_arg: Option<String>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let path = write_to_disk let path = write_to_disk
.then(|| match make_screenshot_path(&self.config.borrow()) { .then(|| {
Ok(path) => path, // When given an explicit path, don't try to strftime it or create parents.
path_arg.map(|p| (PathBuf::from(p), false)).or_else(|| {
match make_screenshot_path(&self.config.borrow()) {
Ok(path) => path.map(|p| (p, true)),
Err(err) => { Err(err) => {
warn!("error making screenshot path: {err:?}"); warn!("error making screenshot path: {err:?}");
None None
} }
}
})
}) })
.flatten(); .flatten();
@@ -5652,16 +5661,21 @@ impl Niri {
let mut image_path = None; let mut image_path = None;
if let Some(path) = path { if let Some((path, create_parent)) = path {
debug!("saving screenshot to {path:?}"); debug!("saving screenshot to {path:?}");
if create_parent {
if let Some(parent) = path.parent() { if let Some(parent) = path.parent() {
// Relative paths with one component, i.e. "test.png", have Some("") parent.
if !parent.as_os_str().is_empty() {
if let Err(err) = std::fs::create_dir(parent) { if let Err(err) = std::fs::create_dir(parent) {
if err.kind() != std::io::ErrorKind::AlreadyExists { if err.kind() != std::io::ErrorKind::AlreadyExists {
warn!("error creating screenshot directory: {err:?}"); warn!("error creating screenshot directory: {err:?}");
} }
} }
} }
}
}
match std::fs::write(&path, buf) { match std::fs::write(&path, buf) {
Ok(()) => image_path = Some(path), Ok(()) => image_path = Some(path),
+10 -10
View File
@@ -263,7 +263,7 @@ fn collect_actions(config: &Config) -> Vec<&Action> {
// Screenshot is not as important, can omit if not bound. // Screenshot is not as important, can omit if not bound.
if let Some(bind) = binds if let Some(bind) = binds
.iter() .iter()
.find(|bind| matches!(bind.action, Action::Screenshot(_))) .find(|bind| matches!(bind.action, Action::Screenshot(_, _)))
{ {
actions.push(&bind.action); actions.push(&bind.action);
} }
@@ -479,7 +479,7 @@ fn action_name(action: &Action) -> String {
String::from("Switch Focus Between Floating and Tiling") String::from("Switch Focus Between Floating and Tiling")
} }
Action::ToggleOverview => String::from("Open the Overview"), Action::ToggleOverview => String::from("Open the Overview"),
Action::Screenshot(_) => String::from("Take a Screenshot"), Action::Screenshot(_, _) => String::from("Take a Screenshot"),
Action::Spawn(args) => format!( Action::Spawn(args) => format!(
"Spawn <span face='monospace' bgcolor='#000000'>{}</span>", "Spawn <span face='monospace' bgcolor='#000000'>{}</span>",
args.first().unwrap_or(&String::new()) args.first().unwrap_or(&String::new())
@@ -620,7 +620,7 @@ mod tests {
#[test] #[test]
fn test_format_bind() { fn test_format_bind() {
// Not bound. // Not bound.
assert_snapshot!(check("", Action::Screenshot(true)), @" (not bound) : Take a Screenshot"); assert_snapshot!(check("", Action::Screenshot(true, None)), @" (not bound) : Take a Screenshot");
// Bound with a default title. // Bound with a default title.
assert_snapshot!( assert_snapshot!(
@@ -628,7 +628,7 @@ mod tests {
r#"binds { r#"binds {
Mod+P { screenshot; } Mod+P { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@" Super + P : Take a Screenshot" @" Super + P : Take a Screenshot"
); );
@@ -639,7 +639,7 @@ mod tests {
r#"binds { r#"binds {
Mod+P hotkey-overlay-title="Hello" { screenshot; } Mod+P hotkey-overlay-title="Hello" { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@" Super + P : Hello" @" Super + P : Hello"
); );
@@ -651,7 +651,7 @@ mod tests {
Mod+P { screenshot; } Mod+P { screenshot; }
Print { screenshot; } Print { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@" Super + P : Take a Screenshot" @" Super + P : Take a Screenshot"
); );
@@ -663,7 +663,7 @@ mod tests {
Mod+P { screenshot; } Mod+P { screenshot; }
Print hotkey-overlay-title="My Cool Bind" { screenshot; } Print hotkey-overlay-title="My Cool Bind" { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@" PrtSc : My Cool Bind" @" PrtSc : My Cool Bind"
); );
@@ -675,7 +675,7 @@ mod tests {
Mod+P hotkey-overlay-title="First" { screenshot; } Mod+P hotkey-overlay-title="First" { screenshot; }
Print hotkey-overlay-title="My Cool Bind" { screenshot; } Print hotkey-overlay-title="My Cool Bind" { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@" Super + P : First" @" Super + P : First"
); );
@@ -687,7 +687,7 @@ mod tests {
Mod+P { screenshot; } Mod+P { screenshot; }
Print hotkey-overlay-title=null { screenshot; } Print hotkey-overlay-title=null { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@"None" @"None"
); );
@@ -699,7 +699,7 @@ mod tests {
Mod+P hotkey-overlay-title="Hello" { screenshot; } Mod+P hotkey-overlay-title="Hello" { screenshot; }
Print hotkey-overlay-title=null { screenshot; } Print hotkey-overlay-title=null { screenshot; }
}"#, }"#,
Action::Screenshot(true), Action::Screenshot(true, None),
), ),
@" Super + P : Hello" @" Super + P : Hello"
); );
+3
View File
@@ -63,6 +63,7 @@ pub enum ScreenshotUi {
open_anim: Animation, open_anim: Animation,
clock: Clock, clock: Clock,
config: Rc<RefCell<Config>>, config: Rc<RefCell<Config>>,
path: Option<String>,
}, },
} }
@@ -141,6 +142,7 @@ impl ScreenshotUi {
screenshots: HashMap<Output, [OutputScreenshot; 3]>, screenshots: HashMap<Output, [OutputScreenshot; 3]>,
default_output: Output, default_output: Output,
show_pointer: bool, show_pointer: bool,
path: Option<String>,
) -> bool { ) -> bool {
if screenshots.is_empty() { if screenshots.is_empty() {
return false; return false;
@@ -235,6 +237,7 @@ impl ScreenshotUi {
open_anim, open_anim,
clock: clock.clone(), clock: clock.clone(),
config: config.clone(), config: config.clone(),
path,
}; };
self.update_buffers(); self.update_buffers();