use cocoa::appkit::NSPasteboardTypeString;
use cocoa::base::{id, nil, BOOL, YES};
use cocoa::foundation::{NSArray, NSInteger, NSUInteger};
use objc::{class, msg_send, sel, sel_impl};
use super::util;
use crate::clipboard::{ClipboardFormat, FormatId};
#[derive(Debug, Clone, Default)]
pub struct Clipboard;
impl Clipboard {
pub fn put_string(&mut self, s: impl AsRef<str>) {
let s = s.as_ref();
put_string_impl(s);
fn put_string_impl(s: &str) {
unsafe {
let nsstring = util::make_nsstring(s);
let pasteboard: id = msg_send![class!(NSPasteboard), generalPasteboard];
let _: NSInteger = msg_send![pasteboard, clearContents];
let result: BOOL =
msg_send![pasteboard, setString: nsstring forType: NSPasteboardTypeString];
if result != YES {
tracing::warn!("failed to set clipboard");
}
}
}
}
pub fn put_formats(&mut self, formats: &[ClipboardFormat]) {
unsafe {
let pasteboard: id = msg_send![class!(NSPasteboard), generalPasteboard];
let _: NSInteger = msg_send![pasteboard, clearContents];
let idents = formats
.iter()
.map(|f| util::make_nsstring(f.identifier))
.collect::<Vec<_>>();
let array = NSArray::arrayWithObjects(nil, &idents);
let _: NSInteger = msg_send![pasteboard, declareTypes: array owner: nil];
for (i, format) in formats.iter().enumerate() {
let data = util::make_nsdata(&format.data);
let data_type = idents[i];
let result: BOOL = msg_send![pasteboard, setData: data forType: data_type];
if result != YES {
tracing::warn!(
"failed to set clipboard contents for type '{}'",
format.identifier
);
}
}
}
}
pub fn get_string(&self) -> Option<String> {
unsafe {
let pasteboard: id = msg_send![class!(NSPasteboard), generalPasteboard];
let contents: id = msg_send![pasteboard, stringForType: NSPasteboardTypeString];
if contents.is_null() {
None
} else {
Some(util::from_nsstring(contents))
}
}
}
pub fn preferred_format(&self, formats: &[FormatId]) -> Option<FormatId> {
unsafe {
let pasteboard: id = msg_send![class!(NSPasteboard), generalPasteboard];
let nsstrings = formats
.iter()
.map(|s| util::make_nsstring(s))
.collect::<Vec<_>>();
let array = NSArray::arrayWithObjects(nil, &nsstrings);
let available: id = msg_send![pasteboard, availableTypeFromArray: array];
if available.is_null() {
None
} else {
let idx: NSUInteger = msg_send![array, indexOfObject: available];
let idx = idx as usize;
if idx > formats.len() {
tracing::error!("clipboard object not found");
None
} else {
Some(formats[idx])
}
}
}
}
pub fn get_format(&self, fmt: FormatId) -> Option<Vec<u8>> {
unsafe {
let pb_type = util::make_nsstring(fmt);
let pasteboard: id = msg_send![class!(NSPasteboard), generalPasteboard];
let data: id = msg_send![pasteboard, dataForType: pb_type];
if !data.is_null() {
let data = util::from_nsdata(data);
Some(data)
} else {
None
}
}
}
pub fn available_type_names(&self) -> Vec<String> {
unsafe {
let pasteboard: id = msg_send![class!(NSPasteboard), generalPasteboard];
let types: id = msg_send![pasteboard, types];
let types_len = types.count() as usize;
(0..types_len)
.map(|i| util::from_nsstring(types.objectAtIndex(i as NSUInteger)))
.collect()
}
}
}