Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,34 @@ impl Clipboard {
self.set().html(html, alt_text)
}

/// Places RTF data onto the clipboard.
///
/// This method writes raw Rich Text Format bytes to the clipboard, under the
/// `public.rtf` type on macOS and equivalently on other platforms. The input is
/// expected to be valid UTF-8 or ASCII-compatible RTF data.
///
/// # Errors
///
/// Returns an error if the data failed to be stored on the clipboard.
#[cfg(target_os = "macos")]
pub fn set_rtf<'a, T: Into<Cow<'a, [u8]>>>(&mut self, data: T) -> Result<(), Error> {
self.set().rtf(data)
}

/// Places RTFD data onto the clipboard.
///
/// This method writes Rich Text Format Directory (RTFD) content to the clipboard.
/// RTFD is similar to RTF but can include embedded resources such as images or
/// attachments, and is only meaningfully supported on macOS.
///
/// # Errors
///
/// Returns an error if the data failed to be stored on the clipboard.
#[cfg(target_os = "macos")]
pub fn set_rtfd<'a, T: Into<Cow<'a, [u8]>>>(&mut self, data: T) -> Result<(), Error> {
self.set().rtfd(data)
}

/// Fetches image data from the clipboard, and returns the decoded pixels.
///
/// Any image data placed on the clipboard with `set_image` will be possible read back, using
Expand Down Expand Up @@ -235,6 +263,35 @@ impl Set<'_> {
self.platform.html(html, alt_text)
}

/// Completes the "set" operation by placing RTF data onto the clipboard.
///
/// The RTF data must be provided as raw bytes, encoded in a way that is valid
/// according to the Rich Text Format specification.
///
/// # Errors
///
/// Returns an error if the data failed to be stored on the clipboard.
#[cfg(target_os = "macos")]
pub fn rtf<'a, T: Into<Cow<'a, [u8]>>>(self, data: T) -> Result<(), Error> {
let data = data.into();
self.platform.rtf(data)
}

/// Completes the "set" operation by placing RTFD data onto the clipboard.
///
/// RTFD (Rich Text Format Directory) is similar to RTF, but can also contain
/// embedded attachments such as images. On macOS, this type is represented by
/// `com.apple.rtfd`.
///
/// # Errors
///
/// Returns an error if the data failed to be stored on the clipboard.
#[cfg(target_os = "macos")]
pub fn rtfd<'a, T: Into<Cow<'a, [u8]>>>(self, data: T) -> Result<(), Error> {
let data = data.into();
self.platform.rtfd(data)
}

/// Completes the "set" operation by placing an image onto the clipboard.
///
/// The chosen output format, depending on the platform is the following:
Expand Down
40 changes: 37 additions & 3 deletions src/platform/osx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ use objc2::{
ClassType,
};
use objc2_app_kit::{
NSPasteboard, NSPasteboardTypeHTML, NSPasteboardTypeString,
NSPasteboardURLReadingFileURLsOnlyKey,
NSPasteboard, NSPasteboardTypeHTML, NSPasteboardTypeRTF, NSPasteboardTypeRTFD,
NSPasteboardTypeString, NSPasteboardURLReadingFileURLsOnlyKey,
};
use objc2_foundation::{ns_string, NSArray, NSDictionary, NSNumber, NSString, NSURL};
use objc2_foundation::{ns_string, NSArray, NSData, NSDictionary, NSNumber, NSString, NSURL};
use std::{
borrow::Cow,
panic::{RefUnwindSafe, UnwindSafe},
Expand Down Expand Up @@ -339,6 +339,40 @@ impl<'clipboard> Set<'clipboard> {
}
}

pub(crate) fn rtf(self, data: Cow<'_, [u8]>) -> Result<(), Error> {
self.clipboard.clear();

let rtf_data = NSData::with_bytes(data.as_ref());
let success = unsafe {
self.clipboard.pasteboard.setData_forType(Some(&rtf_data), NSPasteboardTypeRTF)
};

add_clipboard_exclusions(self.clipboard, self.exclude_from_history);

if success {
Ok(())
} else {
Err(Error::unknown("NSPasteboard#setData_forType(RTF): returned false"))
}
}

pub(crate) fn rtfd(self, data: Cow<'_, [u8]>) -> Result<(), Error> {
self.clipboard.clear();

let rtfd_data = NSData::with_bytes(data.as_ref());
let success = unsafe {
self.clipboard.pasteboard.setData_forType(Some(&rtfd_data), NSPasteboardTypeRTFD)
};

add_clipboard_exclusions(self.clipboard, self.exclude_from_history);

if success {
Ok(())
} else {
Err(Error::unknown("NSPasteboard#setData_forType(RTFD): returned false"))
}
}

#[cfg(feature = "image-data")]
pub(crate) fn image(self, data: ImageData) -> Result<(), Error> {
let pixels = data.bytes.into();
Expand Down