Skip to content

Commit dd43f44

Browse files
authored
Add support for excluding macos clipboard items from history (#159)
* Adds support for excluding macos clipboard items from history
1 parent ee39c47 commit dd43f44

File tree

4 files changed

+47
-7
lines changed

4 files changed

+47
-7
lines changed

src/common.rs

-3
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,6 @@ impl<F: FnOnce()> Drop for ScopeGuard<F> {
174174

175175
/// Common trait for sealing platform extension traits.
176176
pub(crate) mod private {
177-
// This is currently unused on macOS, so silence the warning which appears
178-
// since there's no extension traits making use of this trait sealing structure.
179-
#[cfg_attr(target_vendor = "apple", allow(unreachable_pub, dead_code))]
180177
pub trait Sealed {}
181178

182179
impl Sealed for crate::Get<'_> {}

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub use platform::{ClearExtLinux, GetExtLinux, LinuxClipboardKind, SetExtLinux};
2727
#[cfg(windows)]
2828
pub use platform::SetExtWindows;
2929

30+
#[cfg(target_os = "macos")]
31+
pub use platform::SetExtApple;
32+
3033
/// The OS independent struct for accessing the clipboard.
3134
///
3235
/// Any number of `Clipboard` instances are allowed to exist at a single point in time. Note however

src/platform/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ pub use windows::*;
1414
#[cfg(target_os = "macos")]
1515
mod osx;
1616
#[cfg(target_os = "macos")]
17-
pub(crate) use osx::*;
17+
pub use osx::*;

src/platform/osx.rs

+43-3
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ the Apache 2.0 or the MIT license at the licensee's choice. The terms
88
and conditions of the chosen license apply to this file.
99
*/
1010

11-
use crate::common::Error;
1211
#[cfg(feature = "image-data")]
1312
use crate::common::ImageData;
13+
use crate::common::{private, Error};
1414
use objc2::{
1515
msg_send_id,
1616
rc::{autoreleasepool, Id},
1717
runtime::ProtocolObject,
1818
ClassType,
1919
};
2020
use objc2_app_kit::{NSPasteboard, NSPasteboardTypeHTML, NSPasteboardTypeString};
21-
use objc2_foundation::{NSArray, NSString};
21+
use objc2_foundation::{ns_string, NSArray, NSString};
2222
use std::{
2323
borrow::Cow,
2424
panic::{RefUnwindSafe, UnwindSafe},
@@ -235,11 +235,12 @@ impl<'clipboard> Get<'clipboard> {
235235

236236
pub(crate) struct Set<'clipboard> {
237237
clipboard: &'clipboard mut Clipboard,
238+
exclude_from_history: bool,
238239
}
239240

240241
impl<'clipboard> Set<'clipboard> {
241242
pub(crate) fn new(clipboard: &'clipboard mut Clipboard) -> Self {
242-
Self { clipboard }
243+
Self { clipboard, exclude_from_history: false }
243244
}
244245

245246
pub(crate) fn text(self, data: Cow<'_, str>) -> Result<(), Error> {
@@ -248,6 +249,9 @@ impl<'clipboard> Set<'clipboard> {
248249
let string_array =
249250
NSArray::from_vec(vec![ProtocolObject::from_id(NSString::from_str(&data))]);
250251
let success = unsafe { self.clipboard.pasteboard.writeObjects(&string_array) };
252+
253+
add_clipboard_exclusions(self.clipboard, self.exclude_from_history);
254+
251255
if success {
252256
Ok(())
253257
} else {
@@ -279,6 +283,9 @@ impl<'clipboard> Set<'clipboard> {
279283
};
280284
}
281285
}
286+
287+
add_clipboard_exclusions(self.clipboard, self.exclude_from_history);
288+
282289
if success {
283290
Ok(())
284291
} else {
@@ -296,6 +303,9 @@ impl<'clipboard> Set<'clipboard> {
296303

297304
let image_array = NSArray::from_vec(vec![ProtocolObject::from_id(image)]);
298305
let success = unsafe { self.clipboard.pasteboard.writeObjects(&image_array) };
306+
307+
add_clipboard_exclusions(self.clipboard, self.exclude_from_history);
308+
299309
if success {
300310
Ok(())
301311
} else {
@@ -322,3 +332,33 @@ impl<'clipboard> Clear<'clipboard> {
322332
Ok(())
323333
}
324334
}
335+
336+
fn add_clipboard_exclusions(clipboard: &mut Clipboard, exclude_from_history: bool) {
337+
// On Mac there isn't an official standard for excluding data from clipboard, however
338+
// there is an unofficial standard which is to set `org.nspasteboard.ConcealedType`.
339+
//
340+
// See http://nspasteboard.org/ for details about the community standard.
341+
if exclude_from_history {
342+
unsafe {
343+
clipboard
344+
.pasteboard
345+
.setString_forType(ns_string!(""), ns_string!("org.nspasteboard.ConcealedType"));
346+
}
347+
}
348+
}
349+
350+
/// Apple-specific extensions to the [`Set`](crate::Set) builder.
351+
pub trait SetExtApple: private::Sealed {
352+
/// Excludes the data which will be set on the clipboard from being added to
353+
/// third party clipboard history software.
354+
///
355+
/// See http://nspasteboard.org/ for details about the community standard.
356+
fn exclude_from_history(self) -> Self;
357+
}
358+
359+
impl SetExtApple for crate::Set<'_> {
360+
fn exclude_from_history(mut self) -> Self {
361+
self.platform.exclude_from_history = true;
362+
self
363+
}
364+
}

0 commit comments

Comments
 (0)