From d82818962b709e3229a1d733975573102a63883a Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Thu, 29 Jul 2021 00:29:33 +0200 Subject: [PATCH 01/13] fix mac os memory leak TLDR; I did not find an easy way to clean up NSArray, but there is a better option to get NSString from pasteboard - stringForType. Next up. Even if send release to NSString, there are leftovers after conversion NSString to Rust string. Right now, conversion happens in INSString.as_str(), which internally uses NSString.UTF8String. UTF8String, according to Apple docs, is a pointer lifetime of which is less or equal NSString. This is not true if the clipboard contains characters outside the ASCII range. That's why nsstring_to_rust_string function. I tried to describe the full process here https://barhamon.com/post/rust_and_nsstring --- Cargo.toml | 1 + src/osx_clipboard.rs | 70 +++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 34e001c..13a7844 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ clipboard-win = "3.0.2" objc = "0.2" objc_id = "0.1" objc-foundation = "0.1" +libc = "0.2" [target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="ios", target_os="emscripten"))))'.dependencies] x11-clipboard = { version = "0.5.1", optional = true } diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index ef1e7d9..9d1e6fa 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -12,23 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::mem::transmute; - -use objc::runtime::{Class, Object}; -use objc::{msg_send, sel, sel_impl}; -use objc_foundation::{INSArray, INSObject, INSString}; -use objc_foundation::{NSArray, NSDictionary, NSObject, NSString}; -use objc_id::{Id, Owned}; - use crate::common::*; +use objc::{msg_send, sel, sel_impl}; +use objc::runtime::{Class, Object, Sel}; +use objc_foundation::{INSArray, INSString}; +use objc_foundation::{NSArray, NSString}; +use objc_id::Id; +use std::ffi::CStr; pub struct OSXClipboardContext { pasteboard: Id, } +#[allow(non_upper_case_globals)] +static NSUTF8StringEncoding: usize = 4; //apple documentation says it is 4 + // required to bring NSPasteboard into the path of the class-resolver #[link(name = "AppKit", kind = "framework")] -extern "C" {} +extern "C" { + pub static NSPasteboardTypeString: Sel; +} impl OSXClipboardContext { pub fn new() -> Result { @@ -38,33 +41,22 @@ impl OSXClipboardContext { return Err("NSPasteboard#generalPasteboard returned null".into()); } let pasteboard: Id = unsafe { Id::from_ptr(pasteboard) }; - Ok(OSXClipboardContext { pasteboard }) + Ok(OSXClipboardContext {pasteboard}) } } impl ClipboardProvider for OSXClipboardContext { fn get_contents(&mut self) -> Result { - let string_class: Id = { - let cls: Id = unsafe { Id::from_ptr(class("NSString")) }; - unsafe { transmute(cls) } - }; - let classes: Id> = NSArray::from_vec(vec![string_class]); - let options: Id> = NSDictionary::new(); - let string_array: Id> = unsafe { - let obj: *mut NSArray = - msg_send![self.pasteboard, readObjectsForClasses:&*classes options:&*options]; - if obj.is_null() { - return Err("pasteboard#readObjectsForClasses:options: returned null".into()); - } - Id::from_ptr(obj) - }; - if string_array.count() == 0 { - Err("pasteboard#readObjectsForClasses:options: returned empty".into()) + let string: *mut NSString = + unsafe { msg_send![self.pasteboard, stringForType: NSPasteboardTypeString] }; + if string.is_null() { + Err("pasteboard#stringForType returned null".into()) } else { - Ok(string_array[0].as_str().to_owned()) + let res: String = nsstring_to_rust_string(string).unwrap(); + let _: () = unsafe { msg_send![string, release] }; + Ok(res) } } - fn set_contents(&mut self, data: String) -> Result<()> { let string_array = NSArray::from_vec(vec![NSString::from_str(&data)]); let _: usize = unsafe { msg_send![self.pasteboard, clearContents] }; @@ -77,10 +69,20 @@ impl ClipboardProvider for OSXClipboardContext { } } -// this is a convenience function that both cocoa-rs and -// glutin define, which seems to depend on the fact that -// Option::None has the same representation as a null pointer -#[inline] -pub fn class(name: &str) -> *mut Class { - unsafe { transmute(Class::get(name)) } +fn nsstring_to_rust_string(nsstring: *mut NSString) -> Result { + unsafe { + let string_size: usize = + msg_send![nsstring, lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; + //we need +1 because getCString will return null terminated string + let char_ptr = libc::malloc(string_size + 1); + let res: bool = msg_send![nsstring, getCString:char_ptr maxLength:string_size + 1 encoding:NSUTF8StringEncoding]; + if res { + let c_string = CStr::from_ptr(char_ptr as *const i8); + libc::free(char_ptr); + Ok(c_string.to_string_lossy().into_owned()) + } else { + libc::free(char_ptr); + Err("Casting from NSString to Rust string has failed".into()) + } + } } From 063c2a8b058c6542b833819d8e79464f01aaed96 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Thu, 29 Jul 2021 01:33:56 +0200 Subject: [PATCH 02/13] cargo fmt --- src/osx_clipboard.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index 9d1e6fa..9163a37 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -13,8 +13,8 @@ // limitations under the License. use crate::common::*; -use objc::{msg_send, sel, sel_impl}; use objc::runtime::{Class, Object, Sel}; +use objc::{msg_send, sel, sel_impl}; use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; @@ -41,7 +41,7 @@ impl OSXClipboardContext { return Err("NSPasteboard#generalPasteboard returned null".into()); } let pasteboard: Id = unsafe { Id::from_ptr(pasteboard) }; - Ok(OSXClipboardContext {pasteboard}) + Ok(OSXClipboardContext { pasteboard }) } } From fba91c23f507f1edda32bef3e5351f7c002ca08e Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Thu, 29 Jul 2021 01:42:10 +0200 Subject: [PATCH 03/13] add spaces after double slash (nightly rustfmt complains about them) --- src/osx_clipboard.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index 9163a37..e5abeae 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -25,7 +25,7 @@ pub struct OSXClipboardContext { } #[allow(non_upper_case_globals)] -static NSUTF8StringEncoding: usize = 4; //apple documentation says it is 4 +static NSUTF8StringEncoding: usize = 4; // apple documentation says it is 4 // required to bring NSPasteboard into the path of the class-resolver #[link(name = "AppKit", kind = "framework")] @@ -73,7 +73,7 @@ fn nsstring_to_rust_string(nsstring: *mut NSString) -> Result { unsafe { let string_size: usize = msg_send![nsstring, lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; - //we need +1 because getCString will return null terminated string + // we need +1 because getCString will return null terminated string let char_ptr = libc::malloc(string_size + 1); let res: bool = msg_send![nsstring, getCString:char_ptr maxLength:string_size + 1 encoding:NSUTF8StringEncoding]; if res { From 09d4d742b640ed166142e3436518d7f824761484 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Thu, 29 Jul 2021 01:50:45 +0200 Subject: [PATCH 04/13] Okay. I give up. Installed nightly toolchain --- src/osx_clipboard.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index e5abeae..a69d341 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -57,6 +57,7 @@ impl ClipboardProvider for OSXClipboardContext { Ok(res) } } + fn set_contents(&mut self, data: String) -> Result<()> { let string_array = NSArray::from_vec(vec![NSString::from_str(&data)]); let _: usize = unsafe { msg_send![self.pasteboard, clearContents] }; From ca814d390618cc9938f4f6307c338489c99da977 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Sat, 2 Oct 2021 22:36:50 +0200 Subject: [PATCH 05/13] get rid of libc This should be done at rust_objc_fondation. Updating original pull request, just in case it need to be fixed right now --- src/osx_clipboard.rs | 56 ++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index a69d341..bc577f7 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -18,15 +18,12 @@ use objc::{msg_send, sel, sel_impl}; use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; -use std::ffi::CStr; +use std::ffi::CString; pub struct OSXClipboardContext { pasteboard: Id, } -#[allow(non_upper_case_globals)] -static NSUTF8StringEncoding: usize = 4; // apple documentation says it is 4 - // required to bring NSPasteboard into the path of the class-resolver #[link(name = "AppKit", kind = "framework")] extern "C" { @@ -52,8 +49,7 @@ impl ClipboardProvider for OSXClipboardContext { if string.is_null() { Err("pasteboard#stringForType returned null".into()) } else { - let res: String = nsstring_to_rust_string(string).unwrap(); - let _: () = unsafe { msg_send![string, release] }; + let res: String = nsstring_to_rust_string(string); Ok(res) } } @@ -70,20 +66,40 @@ impl ClipboardProvider for OSXClipboardContext { } } -fn nsstring_to_rust_string(nsstring: *mut NSString) -> Result { - unsafe { - let string_size: usize = - msg_send![nsstring, lengthOfBytesUsingEncoding: NSUTF8StringEncoding]; - // we need +1 because getCString will return null terminated string - let char_ptr = libc::malloc(string_size + 1); - let res: bool = msg_send![nsstring, getCString:char_ptr maxLength:string_size + 1 encoding:NSUTF8StringEncoding]; - if res { - let c_string = CStr::from_ptr(char_ptr as *const i8); - libc::free(char_ptr); - Ok(c_string.to_string_lossy().into_owned()) - } else { - libc::free(char_ptr); - Err("Casting from NSString to Rust string has failed".into()) + +/** +Function that converts NSString to rust string through CString to prevent a memory leak. + +encoding: + 4 = NSUTF8StringEncoding + https://developer.apple.com/documentation/foundation/1497293-string_encodings/nsutf8stringencoding?language=objc + +getCString: + Converts the string to a given encoding and stores it in a buffer. + https://developer.apple.com/documentation/foundation/nsstring/1415702-getcstring + +*/ +fn nsstring_to_rust_string(nsstring: *mut NSString) -> String { + let string_size: usize = unsafe { msg_send![nsstring, lengthOfBytesUsingEncoding: 4] }; + let mut buffer: Vec = vec![0_u8; string_size + 1]; + let is_success: bool = unsafe { + msg_send![nsstring, getCString:buffer.as_mut_ptr() maxLength:string_size+1 encoding:4] + }; + if is_success { + // before from_vec_with_nul can be used https://github.com/rust-lang/rust/pull/89292 + // nul termination from the buffer should be removed by hands + buffer.pop(); + + unsafe { + CString::from_vec_unchecked(buffer) + .to_str() + .unwrap() + .to_string() } + } else { + // In case getCString failed there is no point in creating CString + // Original NSString::as_str() swallows all the errors. + // Not sure if that is the correct approach, but we also don`t have errors here. + "".to_string() } } From f94e57d5874efed8fcf76119c87971a5445caaa4 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Sat, 2 Oct 2021 22:39:43 +0200 Subject: [PATCH 06/13] remove libc from dependencies --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 13a7844..34e001c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ clipboard-win = "3.0.2" objc = "0.2" objc_id = "0.1" objc-foundation = "0.1" -libc = "0.2" [target.'cfg(all(unix, not(any(target_os="macos", target_os="android", target_os="ios", target_os="emscripten"))))'.dependencies] x11-clipboard = { version = "0.5.1", optional = true } From 120a0144f420250ce12ebc7f50b92c67c4583a3f Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Sat, 2 Oct 2021 22:45:10 +0200 Subject: [PATCH 07/13] make nightly fmt happy --- src/osx_clipboard.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index bc577f7..c4ac5fe 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -66,19 +66,15 @@ impl ClipboardProvider for OSXClipboardContext { } } - -/** -Function that converts NSString to rust string through CString to prevent a memory leak. - -encoding: - 4 = NSUTF8StringEncoding - https://developer.apple.com/documentation/foundation/1497293-string_encodings/nsutf8stringencoding?language=objc - -getCString: - Converts the string to a given encoding and stores it in a buffer. - https://developer.apple.com/documentation/foundation/nsstring/1415702-getcstring - -*/ +/// Function that converts NSString to rust string through CString to prevent a memory leak. +/// +/// encoding: +/// 4 = NSUTF8StringEncoding +/// https://developer.apple.com/documentation/foundation/1497293-string_encodings/nsutf8stringencoding?language=objc +/// +/// getCString: +/// Converts the string to a given encoding and stores it in a buffer. +/// https://developer.apple.com/documentation/foundation/nsstring/1415702-getcstring fn nsstring_to_rust_string(nsstring: *mut NSString) -> String { let string_size: usize = unsafe { msg_send![nsstring, lengthOfBytesUsingEncoding: 4] }; let mut buffer: Vec = vec![0_u8; string_size + 1]; @@ -90,12 +86,7 @@ fn nsstring_to_rust_string(nsstring: *mut NSString) -> String { // nul termination from the buffer should be removed by hands buffer.pop(); - unsafe { - CString::from_vec_unchecked(buffer) - .to_str() - .unwrap() - .to_string() - } + unsafe { CString::from_vec_unchecked(buffer).to_str().unwrap().to_string() } } else { // In case getCString failed there is no point in creating CString // Original NSString::as_str() swallows all the errors. From 740055c2de8ebd758607d61a9b3eaa3a5032289a Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Tue, 12 Oct 2021 21:32:24 +0200 Subject: [PATCH 08/13] wrap NSString we got from pasteboard into objc_id::Id Since we get our string from pasteboard, we need to inform objc runtime that we finished using it. We can do it by ourselves by sending the release message or use Id::from_retained_ptr, and Id will release that NSString when it goes out of scope. --- src/osx_clipboard.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index c4ac5fe..17b1f97 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -49,14 +49,13 @@ impl ClipboardProvider for OSXClipboardContext { if string.is_null() { Err("pasteboard#stringForType returned null".into()) } else { - let res: String = nsstring_to_rust_string(string); - Ok(res) + Ok(nsstring_to_rust_string(unsafe { Id::from_retained_ptr(string) })) } } fn set_contents(&mut self, data: String) -> Result<()> { let string_array = NSArray::from_vec(vec![NSString::from_str(&data)]); - let _: usize = unsafe { msg_send![self.pasteboard, clearContents] }; + let _: () = unsafe { msg_send![self.pasteboard, clearContents] }; let success: bool = unsafe { msg_send![self.pasteboard, writeObjects: string_array] }; if success { Ok(()) @@ -75,7 +74,7 @@ impl ClipboardProvider for OSXClipboardContext { /// getCString: /// Converts the string to a given encoding and stores it in a buffer. /// https://developer.apple.com/documentation/foundation/nsstring/1415702-getcstring -fn nsstring_to_rust_string(nsstring: *mut NSString) -> String { +fn nsstring_to_rust_string(nsstring: Id) -> String { let string_size: usize = unsafe { msg_send![nsstring, lengthOfBytesUsingEncoding: 4] }; let mut buffer: Vec = vec![0_u8; string_size + 1]; let is_success: bool = unsafe { From 5923b2a603f52342947aa0b7c8984ece4091c36c Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Fri, 15 Oct 2021 21:35:59 +0200 Subject: [PATCH 09/13] get rid of memory leak with autoreleasepool --- src/osx_clipboard.rs | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index 17b1f97..a605f35 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -13,12 +13,12 @@ // limitations under the License. use crate::common::*; +use objc::rc::autoreleasepool; use objc::runtime::{Class, Object, Sel}; use objc::{msg_send, sel, sel_impl}; use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; -use std::ffi::CString; pub struct OSXClipboardContext { pasteboard: Id, @@ -44,12 +44,13 @@ impl OSXClipboardContext { impl ClipboardProvider for OSXClipboardContext { fn get_contents(&mut self) -> Result { - let string: *mut NSString = + let nsstring: *mut NSString = unsafe { msg_send![self.pasteboard, stringForType: NSPasteboardTypeString] }; - if string.is_null() { + if nsstring.is_null() { Err("pasteboard#stringForType returned null".into()) } else { - Ok(nsstring_to_rust_string(unsafe { Id::from_retained_ptr(string) })) + let nsstring: Id = unsafe { Id::from_retained_ptr(nsstring) }; + Ok(autoreleasepool(|| nsstring.as_str().to_owned())) } } @@ -64,32 +65,3 @@ impl ClipboardProvider for OSXClipboardContext { } } } - -/// Function that converts NSString to rust string through CString to prevent a memory leak. -/// -/// encoding: -/// 4 = NSUTF8StringEncoding -/// https://developer.apple.com/documentation/foundation/1497293-string_encodings/nsutf8stringencoding?language=objc -/// -/// getCString: -/// Converts the string to a given encoding and stores it in a buffer. -/// https://developer.apple.com/documentation/foundation/nsstring/1415702-getcstring -fn nsstring_to_rust_string(nsstring: Id) -> String { - let string_size: usize = unsafe { msg_send![nsstring, lengthOfBytesUsingEncoding: 4] }; - let mut buffer: Vec = vec![0_u8; string_size + 1]; - let is_success: bool = unsafe { - msg_send![nsstring, getCString:buffer.as_mut_ptr() maxLength:string_size+1 encoding:4] - }; - if is_success { - // before from_vec_with_nul can be used https://github.com/rust-lang/rust/pull/89292 - // nul termination from the buffer should be removed by hands - buffer.pop(); - - unsafe { CString::from_vec_unchecked(buffer).to_str().unwrap().to_string() } - } else { - // In case getCString failed there is no point in creating CString - // Original NSString::as_str() swallows all the errors. - // Not sure if that is the correct approach, but we also don`t have errors here. - "".to_string() - } -} From 314e4a2b9eb227dc46d40bbcf3a7648770a10992 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Sun, 17 Oct 2021 17:19:24 +0200 Subject: [PATCH 10/13] revert unnecessary changes --- src/osx_clipboard.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index a605f35..04e648d 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -12,14 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::common::*; use objc::rc::autoreleasepool; + use objc::runtime::{Class, Object, Sel}; use objc::{msg_send, sel, sel_impl}; use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; +use crate::common::*; + pub struct OSXClipboardContext { pasteboard: Id, } @@ -56,7 +58,7 @@ impl ClipboardProvider for OSXClipboardContext { fn set_contents(&mut self, data: String) -> Result<()> { let string_array = NSArray::from_vec(vec![NSString::from_str(&data)]); - let _: () = unsafe { msg_send![self.pasteboard, clearContents] }; + let _: usize = unsafe { msg_send![self.pasteboard, clearContents] }; let success: bool = unsafe { msg_send![self.pasteboard, writeObjects: string_array] }; if success { Ok(()) From bb033c6488affc4c6d0a5254411d6d6fdb272b97 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Tue, 19 Oct 2021 21:05:47 +0200 Subject: [PATCH 11/13] remove unnecessary whitespace --- src/osx_clipboard.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index 04e648d..2227c1c 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -13,13 +13,11 @@ // limitations under the License. use objc::rc::autoreleasepool; - use objc::runtime::{Class, Object, Sel}; use objc::{msg_send, sel, sel_impl}; use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; - use crate::common::*; pub struct OSXClipboardContext { From 1558d31af5a59f125c43fa8d315bff7bfef3d83b Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Tue, 19 Oct 2021 21:47:22 +0200 Subject: [PATCH 12/13] make nightly fmt happy --- src/osx_clipboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index 2227c1c..40daa75 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::common::*; use objc::rc::autoreleasepool; use objc::runtime::{Class, Object, Sel}; use objc::{msg_send, sel, sel_impl}; use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; -use crate::common::*; pub struct OSXClipboardContext { pasteboard: Id, From 34c0d76ee86be2c7d4d6652368f055861a6bed58 Mon Sep 17 00:00:00 2001 From: Sergey Bargamon Date: Wed, 20 Oct 2021 20:51:35 +0200 Subject: [PATCH 13/13] put use crate::common::*; back --- src/osx_clipboard.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/osx_clipboard.rs b/src/osx_clipboard.rs index 40daa75..713b810 100644 --- a/src/osx_clipboard.rs +++ b/src/osx_clipboard.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::common::*; use objc::rc::autoreleasepool; use objc::runtime::{Class, Object, Sel}; use objc::{msg_send, sel, sel_impl}; @@ -20,6 +19,8 @@ use objc_foundation::{INSArray, INSString}; use objc_foundation::{NSArray, NSString}; use objc_id::Id; +use crate::common::*; + pub struct OSXClipboardContext { pasteboard: Id, }