fix(agents): attach pasted clipboard images on Linux (#2336)

WebKitGTK hands the composer an empty clipboardData when the clipboard
holds only an image, as after a GNOME screenshot, and refuses
navigator.clipboard.read(). Ctrl+V then attached nothing. A paste that
carries no data now reads the image through the GTK clipboard with the
new clipboard_image command.

Co-authored-by: NealimeKenna <[email protected]>
Цей коміт міститься в:
NealimeKennaтаNealimeKenna authored and GitHub committed 2026-11-09 19:59:30 +08:00
1 джерело ff2eb95b01
коміт e44a3af310
7 files changed
+79 -6

No files matched your search

+33
Переглянути файл
@@ -31,6 +31,39 @@ pub async fn clipboard_set_file_list(app: AppHandle, paths: Vec<PathBuf>) -> Ide
with_clipboard(app, move || Ok(ide_clipboard::set_files(&paths))).await
}
/// The clipboard's image as a PNG data URL, for a paste whose event carried no
/// files: WebKitGTK leaves `clipboardData` empty for a raw image (a screenshot).
/// None when the clipboard holds no image, and always on other platforms.
#[tauri::command]
#[specta::specta]
pub async fn clipboard_image(app: AppHandle) -> IdeResult<Option<String>> {
#[cfg(target_os = "linux")]
{
use base64::Engine;
let (tx, rx) = tokio::sync::oneshot::channel();
app.run_on_main_thread(move || {
let sender = std::cell::Cell::new(Some(tx));
gtk::Clipboard::get(&gtk::gdk::SELECTION_CLIPBOARD).request_image(move |_, pixbuf| {
let png = pixbuf.and_then(|image| image.save_to_bufferv("png", &[]).ok());
if let Some(sender) = sender.take() {
let _ = sender.send(png);
}
});
})
.map_err(|error| {
ide_core::IdeError::internal(format!("Cannot dispatch clipboard access to the main thread: {error}"))
})?;
let png = rx.await.ok().flatten();
Ok(png
.map(|bytes| format!("data:image/png;base64,{}", base64::engine::general_purpose::STANDARD.encode(bytes))))
}
#[cfg(not(target_os = "linux"))]
{
let _ = app;
Ok(None)
}
}
/// AppKit and WebKit share the general pasteboard, so a worker-side mutex cannot
/// protect its type cache. Await the main thread without blocking a command thread.
async fn with_clipboard<T: Send + 'static>(
+1
Переглянути файл
@@ -166,6 +166,7 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
fs::fs_read_text,
clipboard::clipboard_file_list,
clipboard::clipboard_has_files,
clipboard::clipboard_image,
clipboard::clipboard_set_file_list,
fonts::system_font_families,
doc::doc_open,