feat: 🎉 add show-pointer for Screenshot and ScreenshotScreen

This commit is contained in:
Toby Bridle
2025-03-09 20:55:30 +00:00
committed by Ivan Molodetskikh
parent 87b6c12625
commit 47dd338340
7 changed files with 72 additions and 29 deletions

View File

@@ -1454,8 +1454,11 @@ pub enum Action {
CancelScreenshot,
#[knuffel(skip)]
ScreenshotTogglePointer,
Screenshot,
ScreenshotScreen(#[knuffel(property(name = "write-to-disk"), default = true)] bool),
Screenshot(#[knuffel(property(name = "show-pointer"), default = true)] bool),
ScreenshotScreen(
#[knuffel(property(name = "write-to-disk"), default = true)] bool,
#[knuffel(property(name = "show-pointer"), default = true)] bool,
),
ScreenshotWindow(#[knuffel(property(name = "write-to-disk"), default = true)] bool),
#[knuffel(skip)]
ScreenshotWindowById {
@@ -1641,10 +1644,11 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::PowerOnMonitors {} => Self::PowerOnMonitors,
niri_ipc::Action::Spawn { command } => Self::Spawn(command),
niri_ipc::Action::DoScreenTransition { delay_ms } => Self::DoScreenTransition(delay_ms),
niri_ipc::Action::Screenshot {} => Self::Screenshot,
niri_ipc::Action::ScreenshotScreen { write_to_disk } => {
Self::ScreenshotScreen(write_to_disk)
}
niri_ipc::Action::Screenshot { show_pointer } => Self::Screenshot(show_pointer),
niri_ipc::Action::ScreenshotScreen {
write_to_disk,
show_pointer,
} => Self::ScreenshotScreen(write_to_disk, show_pointer),
niri_ipc::Action::ScreenshotWindow {
id: None,
write_to_disk,

View File

@@ -169,7 +169,11 @@ pub enum Action {
delay_ms: Option<u16>,
},
/// Open the screenshot UI.
Screenshot {},
Screenshot {
/// 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))]
show_pointer: bool,
},
/// Screenshot the focused screen.
ScreenshotScreen {
/// Write the screenshot to disk in addition to putting it in your clipboard.
@@ -177,6 +181,10 @@ pub enum Action {
/// 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))]
write_to_disk: bool,
/// 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))]
show_pointer: bool,
},
/// Screenshot a window.
#[cfg_attr(feature = "clap", clap(about = "Screenshot the focused window"))]

View File

@@ -565,11 +565,14 @@ impl State {
self.niri.do_screen_transition(renderer, delay_ms);
});
}
Action::ScreenshotScreen(write_to_disk) => {
Action::ScreenshotScreen(write_to_disk, show_pointer) => {
let active = self.niri.layout.active_output().cloned();
if let Some(active) = active {
self.backend.with_primary_renderer(|renderer| {
if let Err(err) = self.niri.screenshot(renderer, &active, write_to_disk) {
if let Err(err) =
self.niri
.screenshot(renderer, &active, write_to_disk, show_pointer)
{
warn!("error taking screenshot: {err:?}");
}
});
@@ -615,8 +618,8 @@ impl State {
self.niri.screenshot_ui.toggle_pointer();
self.niri.queue_redraw_all();
}
Action::Screenshot => {
self.open_screenshot_ui();
Action::Screenshot(show_cursor) => {
self.open_screenshot_ui(show_cursor);
}
Action::ScreenshotWindow(write_to_disk) => {
let focus = self.niri.layout.focus_with_output();

View File

@@ -1538,7 +1538,7 @@ impl State {
self.niri.output_management_state.notify_changes(new_config);
}
pub fn open_screenshot_ui(&mut self) {
pub fn open_screenshot_ui(&mut self, show_pointer: bool) {
if self.niri.is_locked() || self.niri.screenshot_ui.is_open() {
return;
}
@@ -1570,7 +1570,7 @@ impl State {
self.backend.with_primary_renderer(|renderer| {
self.niri
.screenshot_ui
.open(renderer, screenshots, default_output)
.open(renderer, screenshots, default_output, show_pointer)
});
self.niri
@@ -4701,6 +4701,7 @@ impl Niri {
renderer: &mut GlesRenderer,
output: &Output,
write_to_disk: bool,
include_pointer: bool,
) -> anyhow::Result<()> {
let _span = tracy_client::span!("Niri::screenshot");
@@ -4711,8 +4712,12 @@ impl Niri {
let size = transform.transform_size(size);
let scale = Scale::from(output.current_scale().fractional_scale());
let elements =
self.render::<GlesRenderer>(renderer, output, true, RenderTarget::ScreenCapture);
let elements = self.render::<GlesRenderer>(
renderer,
output,
include_pointer,
RenderTarget::ScreenCapture,
);
let elements = elements.iter().rev();
let pixels = render_to_vec(
renderer,

View File

@@ -254,8 +254,11 @@ fn render(
]);
// Screenshot is not as important, can omit if not bound.
if binds.iter().any(|bind| bind.action == Action::Screenshot) {
actions.push(&Action::Screenshot);
if let Some(bind) = binds
.iter()
.find(|bind| matches!(bind.action, Action::Screenshot(_)))
{
actions.push(&bind.action);
}
// Add actions with a custom hotkey-overlay-title.
@@ -436,7 +439,7 @@ fn action_name(action: &Action) -> String {
Action::SwitchFocusBetweenFloatingAndTiling => {
String::from("Switch Focus Between Floating and Tiling")
}
Action::Screenshot => String::from("Take a Screenshot"),
Action::Screenshot(_) => String::from("Take a Screenshot"),
Action::Spawn(args) => format!(
"Spawn <span face='monospace' bgcolor='#000000'>{}</span>",
args.first().unwrap_or(&String::new())
@@ -545,7 +548,7 @@ mod tests {
#[test]
fn test_format_bind() {
// Not bound.
assert_snapshot!(check("", Action::Screenshot), @" (not bound) : Take a Screenshot");
assert_snapshot!(check("", Action::Screenshot(true)), @" (not bound) : Take a Screenshot");
// Bound with a default title.
assert_snapshot!(
@@ -553,7 +556,7 @@ mod tests {
r#"binds {
Mod+P { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@" Super + P : Take a Screenshot"
);
@@ -564,7 +567,7 @@ mod tests {
r#"binds {
Mod+P hotkey-overlay-title="Hello" { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@" Super + P : Hello"
);
@@ -576,7 +579,7 @@ mod tests {
Mod+P { screenshot; }
Print { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@" Super + P : Take a Screenshot"
);
@@ -588,7 +591,7 @@ mod tests {
Mod+P { screenshot; }
Print hotkey-overlay-title="My Cool Bind" { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@" PrtSc : My Cool Bind"
);
@@ -600,7 +603,7 @@ mod tests {
Mod+P hotkey-overlay-title="First" { screenshot; }
Print hotkey-overlay-title="My Cool Bind" { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@" Super + P : First"
);
@@ -612,7 +615,7 @@ mod tests {
Mod+P { screenshot; }
Print hotkey-overlay-title=null { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@"None"
);
@@ -624,7 +627,7 @@ mod tests {
Mod+P hotkey-overlay-title="Hello" { screenshot; }
Print hotkey-overlay-title=null { screenshot; }
}"#,
Action::Screenshot,
Action::Screenshot(true),
),
@" Super + P : Hello"
);

View File

@@ -101,6 +101,7 @@ impl ScreenshotUi {
// Output, screencast, screen capture.
screenshots: HashMap<Output, [OutputScreenshot; 3]>,
default_output: Output,
show_pointer: bool,
) -> bool {
if screenshots.is_empty() {
return false;
@@ -191,7 +192,7 @@ impl ScreenshotUi {
selection,
output_data,
mouse_down: false,
show_pointer: true,
show_pointer,
open_anim,
clock: clock.clone(),
config: config.clone(),

View File

@@ -306,9 +306,13 @@ binds {
}
```
#### `screenshot-screen`, `screenshot-window`
#### `screenshot`, `screenshot-screen`, `screenshot-window`
Actions for taking screenshots.
- `screenshot`: opens the built-in interactive screenshot UI.
- `screenshot-screen`, `screenshow-window`: takes a screenshot of the focused screen or window respectively.
Take a screenshot of the focused screen or window respectively.
The screenshot is both stored to the clipboard and saved to disk, according to the [`screenshot-path` option](./Configuration:-Miscellaneous.md).
<sup>Since: 25.02</sup> You can disable saving to disk for a specific bind with the `write-to-disk=false` property:
@@ -320,6 +324,21 @@ binds {
}
```
In the interactive screenshot UI, pressing <kbd>Ctrl</kbd><kbd>C</kbd> will copy the screenshot to the clipboard without writing it to disk.
<sup>Since: next release</sup> You can hide the mouse pointer in screenshots with the `show-pointer=false` property:
```kdl
binds {
// The pointer will be hidden by default
// (you can still show it by pressing P).
Print { screenshot show-pointer=false; }
// The pointer will be hidden on the screenshot.
Ctrl+Print { screenshot-screen show-pointer=false; }
}
```
#### `toggle-keyboard-shortcuts-inhibit`
<sup>Since: 25.02</sup>