Merge pull request #1711 from pop-os/clipboard-fixes

fix: handle slight delay in availability of clipboard data
This commit is contained in:
Jeremy Soller 2026-04-13 14:09:00 -06:00 committed by GitHub
commit 109f83799d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 10 deletions

View file

@ -422,6 +422,7 @@ pub enum Message {
CheckClipboardImage,
CheckClipboardVideo,
CheckClipboardText,
RetryCheckClipboard(ClipboardCache),
ClipboardCached(ClipboardCache),
PendingCancel(u64),
PendingCancelAll,
@ -3889,6 +3890,24 @@ impl Application for App {
// Use cached clipboard data if available (needed for Wayland popups)
match &self.clipboard_cache {
ClipboardCache::Files(contents) => {
if contents.paths.is_empty() {
return iced::Task::future(tokio::time::sleep(
std::time::Duration::from_millis(300),
))
.discard()
.chain(
clipboard::read_data::<ClipboardPaste>().map(
move |contents_opt| match contents_opt {
Some(contents) => cosmic::action::app(
Message::PasteContents(to.clone(), contents),
),
None => {
cosmic::action::app(Message::PasteImage(to.clone()))
}
},
),
);
}
return self
.update(Message::PasteContents(to.clone(), contents.clone()));
}
@ -4036,9 +4055,12 @@ impl Application for App {
// Check if clipboard has any paste-able content and cache it
return clipboard::read_data::<ClipboardPaste>().map(|contents_opt| {
match contents_opt {
Some(contents) if !contents.paths.is_empty() => cosmic::action::app(
Message::ClipboardCached(ClipboardCache::Files(contents)),
Some(contents) if contents.paths.is_empty() => cosmic::action::app(
Message::RetryCheckClipboard(ClipboardCache::Files(contents)),
),
Some(contents) => cosmic::action::app(Message::ClipboardCached(
ClipboardCache::Files(contents),
)),
_ => cosmic::action::app(Message::CheckClipboardImage),
}
});
@ -4071,6 +4093,28 @@ impl Application for App {
}))
});
}
Message::RetryCheckClipboard(cache) => {
let mut cmds = Vec::new();
cmds.push(self.update(Message::ClipboardCached(cache)));
cmds.push(
iced::Task::future(tokio::time::sleep(Duration::from_millis(300)))
.discard()
.chain(
clipboard::read_data::<ClipboardPaste>().map(|contents_opt| {
match contents_opt {
Some(contents) if !contents.paths.is_empty() => {
cosmic::action::app(Message::ClipboardCached(
ClipboardCache::Files(contents),
))
}
_ => cosmic::action::app(Message::CheckClipboardImage),
}
}),
),
);
return Task::batch(cmds);
}
Message::ClipboardCached(cache) => {
self.clipboard_cache = cache;
}
@ -4478,6 +4522,7 @@ impl Application for App {
widget::Id::unique(),
)),
);
commands.push(self.update(Message::CheckClipboard));
commands.push(self.update(Message::Surface(
cosmic::surface::action::app_popup(
move |app: &mut Self| -> SctkPopupSettings {
@ -5344,7 +5389,11 @@ impl Application for App {
};
}
// Check clipboard when window gains focus
return self.update(Message::CheckClipboard);
// HACK: Wait a moment for the data to be available.
return cosmic::task::future(async {
_ = tokio::time::sleep(Duration::from_millis(300)).await;
cosmic::action::app(Message::CheckClipboard)
});
}
Message::Surface(action) => {
return cosmic::task::message(cosmic::Action::Cosmic(

View file

@ -133,9 +133,7 @@ impl TryFrom<(Vec<u8>, String)> for ClipboardPaste {
"text/uri-list" => {
let text = str::from_utf8(&data)?;
let lines = text.lines();
if text.is_empty() || lines.count() == 0 {
Err(format!("Empty file url"))?;
}
for line in text.lines() {
let url = Url::parse(line)?;
match url.to_file_path() {
@ -146,10 +144,7 @@ impl TryFrom<(Vec<u8>, String)> for ClipboardPaste {
}
"x-special/gnome-copied-files" => {
let text = str::from_utf8(&data)?;
let lines = text.lines();
if text.is_empty() || lines.count() == 0 {
Err(format!("Empty file url"))?;
}
for (i, line) in text.lines().enumerate() {
if i == 0 {
kind = match line {