Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix mac os memory leak #33

Merged
merged 13 commits into from
Oct 21, 2021
51 changes: 16 additions & 35 deletions src/osx_clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@
// 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::*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whitespace before crate imports was intentional. Same as the whitespace after std. This way the alphabetic ordering doesn't get in the way of the logical ordering of relevance.

Please revert the removal of whitespace before the crate::common import.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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;
chrisduerr marked this conversation as resolved.
Show resolved Hide resolved

pub struct OSXClipboardContext {
pasteboard: Id<Object>,
}

// 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<OSXClipboardContext> {
Expand All @@ -44,30 +44,19 @@ impl OSXClipboardContext {

impl ClipboardProvider for OSXClipboardContext {
fn get_contents(&mut self) -> Result<String> {
let string_class: Id<NSObject> = {
let cls: Id<Class> = unsafe { Id::from_ptr(class("NSString")) };
unsafe { transmute(cls) }
};
let classes: Id<NSArray<NSObject, Owned>> = NSArray::from_vec(vec![string_class]);
let options: Id<NSDictionary<NSObject, NSObject>> = NSDictionary::new();
let string_array: Id<NSArray<NSString>> = unsafe {
let obj: *mut NSArray<NSString> =
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 nsstring: *mut NSString =
unsafe { msg_send![self.pasteboard, stringForType: NSPasteboardTypeString] };
if nsstring.is_null() {
Err("pasteboard#stringForType returned null".into())
} else {
Ok(string_array[0].as_str().to_owned())
let nsstring: Id<NSString> = unsafe { Id::from_retained_ptr(nsstring) };
Ok(autoreleasepool(|| nsstring.as_str().to_owned()))
chrisduerr marked this conversation as resolved.
Show resolved Hide resolved
}
}

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] };
chrisduerr marked this conversation as resolved.
Show resolved Hide resolved
let success: bool = unsafe { msg_send![self.pasteboard, writeObjects: string_array] };
if success {
Ok(())
Expand All @@ -76,11 +65,3 @@ 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)) }
}