@@ -47,6 +47,10 @@ enum Command { |
| 47 | 47 | /// Include cursor in screenshot. |
| 48 | 48 | #[arg(short, long)] |
| 49 | 49 | cursor: bool, |
| 50 | + |
| 51 | + /// Don't copy to clipboard (default: copy to clipboard). |
| 52 | + #[arg(long)] |
| 53 | + no_clipboard: bool, |
| 50 | 54 | }, |
| 51 | 55 | |
| 52 | 56 | /// Capture a region by geometry. |
@@ -66,6 +70,10 @@ enum Command { |
| 66 | 70 | /// Include cursor in screenshot. |
| 67 | 71 | #[arg(short, long)] |
| 68 | 72 | cursor: bool, |
| 73 | + |
| 74 | + /// Don't copy to clipboard (default: copy to clipboard). |
| 75 | + #[arg(long)] |
| 76 | + no_clipboard: bool, |
| 69 | 77 | }, |
| 70 | 78 | |
| 71 | 79 | /// Capture a window. |
@@ -89,6 +97,10 @@ enum Command { |
| 89 | 97 | /// Include cursor in screenshot. |
| 90 | 98 | #[arg(short, long)] |
| 91 | 99 | cursor: bool, |
| 100 | + |
| 101 | + /// Don't copy to clipboard (default: copy to clipboard). |
| 102 | + #[arg(long)] |
| 103 | + no_clipboard: bool, |
| 92 | 104 | }, |
| 93 | 105 | |
| 94 | 106 | /// Interactive region selection with blur overlay. |
@@ -108,6 +120,10 @@ enum Command { |
| 108 | 120 | /// Blur radius for overlay (default: 15). |
| 109 | 121 | #[arg(short, long, default_value = "15")] |
| 110 | 122 | blur: usize, |
| 123 | + |
| 124 | + /// Don't copy to clipboard (default: copy to clipboard). |
| 125 | + #[arg(long)] |
| 126 | + no_clipboard: bool, |
| 111 | 127 | }, |
| 112 | 128 | |
| 113 | 129 | /// List available monitors. |
@@ -134,6 +150,7 @@ fn main() -> anyhow::Result<()> { |
| 134 | 150 | let format = &config.general.format; |
| 135 | 151 | let output = default_output(&config, format); |
| 136 | 152 | capture_screen(&output, format, None, config.general.include_cursor)?; |
| 153 | + copy_to_clipboard(&output)?; |
| 137 | 154 | println!("{}", output.display()); |
| 138 | 155 | } |
| 139 | 156 | |
@@ -142,9 +159,13 @@ fn main() -> anyhow::Result<()> { |
| 142 | 159 | format, |
| 143 | 160 | monitor, |
| 144 | 161 | cursor, |
| 162 | + no_clipboard, |
| 145 | 163 | }) => { |
| 146 | 164 | let output = output.unwrap_or_else(|| default_output(&config, &format)); |
| 147 | 165 | capture_screen(&output, &format, monitor.as_deref(), cursor)?; |
| 166 | + if !no_clipboard { |
| 167 | + copy_to_clipboard(&output)?; |
| 168 | + } |
| 148 | 169 | println!("{}", output.display()); |
| 149 | 170 | } |
| 150 | 171 | |
@@ -153,9 +174,13 @@ fn main() -> anyhow::Result<()> { |
| 153 | 174 | output, |
| 154 | 175 | format, |
| 155 | 176 | cursor, |
| 177 | + no_clipboard, |
| 156 | 178 | }) => { |
| 157 | 179 | let output = output.unwrap_or_else(|| default_output(&config, &format)); |
| 158 | 180 | capture_region_cmd(&output, &format, &geometry, cursor)?; |
| 181 | + if !no_clipboard { |
| 182 | + copy_to_clipboard(&output)?; |
| 183 | + } |
| 159 | 184 | println!("{}", output.display()); |
| 160 | 185 | } |
| 161 | 186 | |
@@ -165,9 +190,13 @@ fn main() -> anyhow::Result<()> { |
| 165 | 190 | output, |
| 166 | 191 | format, |
| 167 | 192 | cursor, |
| 193 | + no_clipboard, |
| 168 | 194 | }) => { |
| 169 | 195 | let output = output.unwrap_or_else(|| default_output(&config, &format)); |
| 170 | 196 | capture_window_cmd(&output, &format, id.as_deref(), decorations, cursor)?; |
| 197 | + if !no_clipboard { |
| 198 | + copy_to_clipboard(&output)?; |
| 199 | + } |
| 171 | 200 | println!("{}", output.display()); |
| 172 | 201 | } |
| 173 | 202 | |
@@ -176,9 +205,13 @@ fn main() -> anyhow::Result<()> { |
| 176 | 205 | format, |
| 177 | 206 | cursor, |
| 178 | 207 | blur, |
| 208 | + no_clipboard, |
| 179 | 209 | }) => { |
| 180 | 210 | let output = output.unwrap_or_else(|| default_output(&config, &format)); |
| 181 | 211 | capture_select_cmd(&output, &format, cursor, blur)?; |
| 212 | + if !no_clipboard { |
| 213 | + copy_to_clipboard(&output)?; |
| 214 | + } |
| 182 | 215 | println!("{}", output.display()); |
| 183 | 216 | } |
| 184 | 217 | |
@@ -409,6 +442,51 @@ fn capture_select_cmd( |
| 409 | 442 | save_image(&result.data, result.width, result.height, output, format) |
| 410 | 443 | } |
| 411 | 444 | |
| 445 | +fn copy_to_clipboard(path: &PathBuf) -> anyhow::Result<()> { |
| 446 | + let mime_type = match path.extension().and_then(|e| e.to_str()) { |
| 447 | + Some("png") => "image/png", |
| 448 | + Some("jpg") | Some("jpeg") => "image/jpeg", |
| 449 | + Some("webp") => "image/webp", |
| 450 | + Some("ppm") | Some("pam") => "image/x-portable-pixmap", |
| 451 | + _ => "image/png", // Default to PNG |
| 452 | + }; |
| 453 | + |
| 454 | + // Try xclip first, then xsel |
| 455 | + let result = std::process::Command::new("xclip") |
| 456 | + .args(["-selection", "clipboard", "-t", mime_type, "-i"]) |
| 457 | + .arg(path) |
| 458 | + .status(); |
| 459 | + |
| 460 | + match result { |
| 461 | + Ok(status) if status.success() => { |
| 462 | + tracing::debug!("Copied {} to clipboard via xclip", path.display()); |
| 463 | + Ok(()) |
| 464 | + } |
| 465 | + _ => { |
| 466 | + // Fallback to xsel (doesn't support MIME types as well) |
| 467 | + let result = std::process::Command::new("xsel") |
| 468 | + .args(["--clipboard", "--input"]) |
| 469 | + .stdin(std::fs::File::open(path)?) |
| 470 | + .status(); |
| 471 | + |
| 472 | + match result { |
| 473 | + Ok(status) if status.success() => { |
| 474 | + tracing::debug!("Copied {} to clipboard via xsel", path.display()); |
| 475 | + Ok(()) |
| 476 | + } |
| 477 | + Ok(status) => { |
| 478 | + tracing::warn!("xsel exited with status: {}", status); |
| 479 | + anyhow::bail!("Failed to copy to clipboard") |
| 480 | + } |
| 481 | + Err(e) => { |
| 482 | + tracing::warn!("Neither xclip nor xsel available: {}", e); |
| 483 | + anyhow::bail!("No clipboard tool available (install xclip or xsel)") |
| 484 | + } |
| 485 | + } |
| 486 | + } |
| 487 | + } |
| 488 | +} |
| 489 | + |
| 412 | 490 | fn run_daemon() -> anyhow::Result<()> { |
| 413 | 491 | use std::sync::Arc; |
| 414 | 492 | use tokio::sync::Mutex; |