use crate::clipboard::{ClipboardFormat, FormatId};
use gdk::Atom;
use gtk::{TargetEntry, TargetFlags};
#[derive(Debug, Clone)]
pub struct Clipboard;
impl Clipboard {
pub fn put_string(&mut self, s: impl AsRef<str>) {
let display = gdk::Display::get_default().unwrap();
let clipboard = gtk::Clipboard::get_default(&display).unwrap();
clipboard.set_text(s.as_ref())
}
pub fn put_formats(&mut self, formats: &[ClipboardFormat]) {
let entries = make_entries(formats);
let display = gdk::Display::get_default().unwrap();
let clipboard = gtk::Clipboard::get_default(&display).unwrap();
let formats = formats.to_owned();
let success = clipboard.set_with_data(&entries, move |_, sel, idx| {
log::info!("got paste callback {}", idx);
let idx = idx as usize;
if idx < formats.len() {
let item = &formats[idx];
if item.identifier == ClipboardFormat::TEXT {
sel.set_text(unsafe { std::str::from_utf8_unchecked(&item.data) });
} else {
let atom = Atom::intern(item.identifier);
let stride = 8;
sel.set(&atom, stride, item.data.as_slice());
}
}
});
if !success {
log::warn!("failed to set clipboard data.");
}
}
pub fn get_string(&self) -> Option<String> {
let display = gdk::Display::get_default().unwrap();
let clipboard = gtk::Clipboard::get_default(&display).unwrap();
clipboard.wait_for_text().map(|s| s.to_string())
}
pub fn preferred_format(&self, formats: &[FormatId]) -> Option<FormatId> {
let display = gdk::Display::get_default().unwrap();
let clipboard = gtk::Clipboard::get_default(&display).unwrap();
let targets = clipboard.wait_for_targets()?;
let format_atoms = formats
.iter()
.map(|fmt| Atom::intern(fmt))
.collect::<Vec<_>>();
for atom in targets.iter() {
if let Some(idx) = format_atoms.iter().position(|fmt| fmt == atom) {
return Some(formats[idx]);
}
}
None
}
pub fn get_format(&self, format: FormatId) -> Option<Vec<u8>> {
let display = gdk::Display::get_default().unwrap();
let clipboard = gtk::Clipboard::get_default(&display).unwrap();
let atom = Atom::intern(format);
clipboard
.wait_for_contents(&atom)
.map(|data| data.get_data())
}
pub fn available_type_names(&self) -> Vec<String> {
let display = gdk::Display::get_default().unwrap();
let clipboard = gtk::Clipboard::get_default(&display).unwrap();
let targets = clipboard.wait_for_targets().unwrap_or_default();
targets
.iter()
.map(|atom| unsafe { format!("{} ({})", atom.name(), atom.value()) })
.collect()
}
}
fn make_entries(formats: &[ClipboardFormat]) -> Vec<TargetEntry> {
formats
.iter()
.enumerate()
.map(|(i, fmt)| TargetEntry::new(fmt.identifier, TargetFlags::all(), i as u32))
.collect()
}