cacao/appkit/pasteboard/mod.rs

97 lines
3.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! A wrapper for NSPasteBoard, which is the interface for copy/paste and general transferring
//! (think: drag and drop between applications). It exposes a Rust interface that tries to be
//! complete, but might not cover everything 100% right now - feel free to pull request.
use std::error::Error;
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use url::Url;
use crate::foundation::{id, nil, NSString, NSArray};
use crate::error::AppKitError;
pub mod types;
pub use types::{PasteboardName, PasteboardType};
/// Represents an `NSPasteboard`, enabling you to handle copy/paste/drag and drop.
pub struct Pasteboard(pub Id<Object>);
impl Default for Pasteboard {
fn default() -> Self {
Pasteboard(unsafe {
Id::from_retained_ptr(msg_send![class!(NSPasteboard), generalPasteboard])
})
}
}
impl Pasteboard {
/// Used internally for wrapping a Pasteboard returned from operations (say, drag and drop).
pub(crate) fn with(existing: id) -> Self {
Pasteboard(unsafe {
Id::from_retained_ptr(existing)
})
}
/// Retrieves the system Pasteboard for the given name/type.
pub fn named(name: PasteboardName) -> Self {
Pasteboard(unsafe {
let name: NSString = name.into();
Id::from_retained_ptr(msg_send![class!(NSPasteboard), pasteboardWithName:&*name.0])
})
}
/// Creates and returns a new pasteboard with a name that is guaranteed to be unique with
/// respect to other pasteboards in the system.
pub fn unique() -> Self {
Pasteboard(unsafe {
Id::from_ptr(msg_send![class!(NSPasteboard), pasteboardWithUniqueName])
})
}
/// Releases the receivers resources in the pasteboard server. It's rare-ish to need to use
/// this, but considering this stuff happens on the Objective-C side you may need it.
pub fn release_globally(&self) {
unsafe {
let _: () = msg_send![&*self.0, releaseGlobally];
}
}
/// Clears the existing contents of the pasteboard.
pub fn clear_contents(&self) {
unsafe {
let _: () = msg_send![&*self.0, clearContents];
}
}
/// Looks inside the pasteboard contents and extracts what FileURLs are there, if any.
pub fn get_file_urls(&self) -> Result<Vec<Url>, Box<dyn Error>> {
unsafe {
let class: id = msg_send![class!(NSURL), class];
let classes = NSArray::new(&[class]);
let contents: id = msg_send![&*self.0, readObjectsForClasses:classes options:nil];
// This can happen if the Pasteboard server has an error in returning items.
// In our case, we'll bubble up an error by checking the pasteboard.
if contents == nil {
// This error is not necessarily "correct", but in the event of an error in
// Pasteboard server retrieval I'm not sure where to check... and this stuff is
// kinda ancient and has conflicting docs in places. ;P
return Err(Box::new(AppKitError {
code: 666,
domain: "com.appkit-rs.pasteboard".to_string(),
description: "Pasteboard server returned no data.".to_string()
}));
}
let urls = NSArray::wrap(contents).map(|url| {
let path = NSString::wrap(msg_send![url, path]);
Url::parse(&format!("file://{}", path.to_str()))
}).into_iter().filter_map(|r| r.ok()).collect();
Ok(urls)
}
}
}