Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions niri-config/src/binds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ pub enum Action {
#[knuffel(skip)]
ConfirmScreenshot {
write_to_disk: bool,
copy_path: bool,
},
#[knuffel(skip)]
CancelScreenshot,
Expand Down
13 changes: 8 additions & 5 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,8 +747,11 @@ impl State {
});
}
}
Action::ConfirmScreenshot { write_to_disk } => {
self.confirm_screenshot(write_to_disk);
Action::ConfirmScreenshot {
write_to_disk,
copy_path,
} => {
self.confirm_screenshot(write_to_disk, copy_path);
}
Action::CancelScreenshot => {
if !self.niri.screenshot_ui.is_open() {
Expand Down Expand Up @@ -3061,7 +3064,7 @@ impl State {
}
} else if let Some(capture) = self.niri.screenshot_ui.pointer_up(None) {
if capture {
self.confirm_screenshot(true);
self.confirm_screenshot(true, false);
} else {
self.niri.queue_redraw_all();
}
Expand Down Expand Up @@ -3689,7 +3692,7 @@ impl State {
TabletToolTipState::Up => {
if let Some(capture) = self.niri.screenshot_ui.pointer_up(None) {
if capture {
self.confirm_screenshot(true);
self.confirm_screenshot(true, false);
} else {
self.niri.queue_redraw_all();
}
Expand Down Expand Up @@ -4219,7 +4222,7 @@ impl State {

if let Some(capture) = self.niri.screenshot_ui.pointer_up(Some(slot)) {
if capture {
self.confirm_screenshot(true);
self.confirm_screenshot(true, false);
} else {
self.niri.queue_redraw_all();
}
Expand Down
46 changes: 35 additions & 11 deletions src/niri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2003,7 +2003,7 @@ impl State {
self.niri.queue_redraw_all();
}

pub fn confirm_screenshot(&mut self, write_to_disk: bool) {
pub fn confirm_screenshot(&mut self, write_to_disk: bool, copy_path: bool) {
let ScreenshotUi::Open { path, .. } = &mut self.niri.screenshot_ui else {
return;
};
Expand All @@ -2012,7 +2012,10 @@ impl State {
self.backend.with_primary_renderer(|renderer| {
match self.niri.screenshot_ui.capture(renderer) {
Ok((size, pixels)) => {
if let Err(err) = self.niri.save_screenshot(size, pixels, write_to_disk, path) {
if let Err(err) =
self.niri
.save_screenshot(size, pixels, write_to_disk, copy_path, path)
{
warn!("error saving screenshot: {err:?}");
}
}
Expand Down Expand Up @@ -5219,7 +5222,7 @@ impl Niri {
elements,
)?;

self.save_screenshot(size, pixels, write_to_disk, path)
self.save_screenshot(size, pixels, write_to_disk, false, path)
.context("error saving screenshot")
}

Expand Down Expand Up @@ -5282,7 +5285,7 @@ impl Niri {
elements,
)?;

self.save_screenshot(geo.size, pixels, write_to_disk, path)
self.save_screenshot(geo.size, pixels, write_to_disk, false, path)
.context("error saving screenshot")
}

Expand All @@ -5291,6 +5294,7 @@ impl Niri {
size: Size<i32, Physical>,
pixels: Vec<u8>,
write_to_disk: bool,
copy_path: bool,
path_arg: Option<String>,
) -> anyhow::Result<()> {
let path = write_to_disk
Expand All @@ -5308,17 +5312,17 @@ impl Niri {
})
.flatten();

// Prepare to set the encoded image as our clipboard selection. This must be done from the
// main thread.
let (tx, rx) = calloop::channel::sync_channel::<Arc<[u8]>>(1);
// Prepare to set the clipboard selection. This must be done from the main thread.
// The channel sends (mime_types, data).
let (tx, rx) = calloop::channel::sync_channel::<(Vec<String>, Arc<[u8]>)>(1);
self.event_loop
.insert_source(rx, move |event, _, state| match event {
calloop::channel::Event::Msg(buf) => {
calloop::channel::Event::Msg((mime_types, buf)) => {
set_data_device_selection(
&state.niri.display_handle,
&state.niri.seat,
vec![String::from("image/png")],
buf.clone(),
mime_types,
buf,
);
}
calloop::channel::Event::Closed => (),
Expand Down Expand Up @@ -5347,7 +5351,11 @@ impl Niri {
}

let buf: Arc<[u8]> = Arc::from(buf.into_boxed_slice());
let _ = tx.send(buf.clone());

// If not copying path, copy the image to clipboard now.
if !copy_path {
let _ = tx.send((vec![String::from("image/png")], buf.clone()));
}

let mut image_path = None;

Expand Down Expand Up @@ -5377,6 +5385,22 @@ impl Niri {
debug!("not saving screenshot to disk");
}

// If copying path, copy it to clipboard now that we know the path.
if copy_path {
if let Some(path) = &image_path {
if let Some(path_str) = path.to_str() {
let path_bytes: Arc<[u8]> = Arc::from(path_str.as_bytes());
let _ = tx.send((
vec![
String::from("text/plain;charset=utf-8"),
String::from("text/plain"),
],
path_bytes,
));
}
}
}

#[cfg(feature = "dbus")]
if let Err(err) = crate::utils::show_screenshot_notification(image_path.as_deref()) {
warn!("error showing screenshot notification: {err:?}");
Expand Down
12 changes: 12 additions & 0 deletions src/ui/screenshot_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,13 @@ const FONT: &str = "sans 14px";
const BORDER: i32 = 4;
const TEXT_HIDE_P: &str =
"Press <span face='mono' bgcolor='#2C2C2C'> Space </span> to save the screenshot.\n\
Press <span face='mono' bgcolor='#2C2C2C'> Ctrl+C </span> to copy to clipboard.\n\
Press <span face='mono' bgcolor='#2C2C2C'> Ctrl+Space </span> to save and copy path to clipboard.\n\
Press <span face='mono' bgcolor='#2C2C2C'> P </span> to hide the pointer.";
const TEXT_SHOW_P: &str =
"Press <span face='mono' bgcolor='#2C2C2C'> Space </span> to save the screenshot.\n\
Press <span face='mono' bgcolor='#2C2C2C'> Ctrl+C </span> to copy to clipboard.\n\
Press <span face='mono' bgcolor='#2C2C2C'> Ctrl+Space </span> to save and copy path to clipboard.\n\
Press <span face='mono' bgcolor='#2C2C2C'> P </span> to show the pointer.";

// Ideally the screenshot UI should support cross-output selections. However, that poses some
Expand Down Expand Up @@ -1055,11 +1059,19 @@ fn action(raw: Keysym, mods: ModifiersState) -> Option<Action> {
if !mods.ctrl && (raw == Keysym::space || raw == Keysym::Return) {
return Some(Action::ConfirmScreenshot {
write_to_disk: true,
copy_path: false,
});
}
if mods.ctrl && raw == Keysym::c {
return Some(Action::ConfirmScreenshot {
write_to_disk: false,
copy_path: false,
});
}
if mods.ctrl && raw == Keysym::space {
return Some(Action::ConfirmScreenshot {
write_to_disk: true,
copy_path: true,
});
}

Expand Down