Fix button callbacks and avoid double-locks in listview.
This commit is contained in:
parent
2f9a5b5e67
commit
2894699ace
|
@ -23,7 +23,7 @@ use std::sync::Once;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use objc_id::Id;
|
use objc_id::ShareId;
|
||||||
use objc::declare::ClassDecl;
|
use objc::declare::ClassDecl;
|
||||||
use objc::runtime::{Class, Object, Sel};
|
use objc::runtime::{Class, Object, Sel};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
@ -157,8 +157,10 @@ impl Button {
|
||||||
/// Attaches a callback for button press events. Don't get too creative now...
|
/// Attaches a callback for button press events. Don't get too creative now...
|
||||||
/// best just to message pass or something.
|
/// best just to message pass or something.
|
||||||
pub fn set_action<F: Fn() + Send + Sync + 'static>(&mut self, action: F) {
|
pub fn set_action<F: Fn() + Send + Sync + 'static>(&mut self, action: F) {
|
||||||
//let handler = TargetActionHandler::new(&*self.objc, action);
|
// @TODO: This probably isn't ideal but gets the job done for now; needs revisiting.
|
||||||
//self.handler = Some(handler);
|
let this = self.objc.get(|obj| unsafe { ShareId::from_ptr(msg_send![obj, self]) });
|
||||||
|
let handler = TargetActionHandler::new(&*this, action);
|
||||||
|
self.handler = Some(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this to set the background color for the backing layer.
|
/// Call this to set the background color for the backing layer.
|
||||||
|
|
|
@ -428,14 +428,21 @@ impl<T> ListView<T> {
|
||||||
// Note that we need to thread the `with_mut` calls carefully, to avoid deadlocking.
|
// Note that we need to thread the `with_mut` calls carefully, to avoid deadlocking.
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
self.objc.with_mut(|obj| unsafe {
|
self.objc.get(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, beginUpdates];
|
let _: () = msg_send![obj, beginUpdates];
|
||||||
});
|
});
|
||||||
|
|
||||||
let handle = self.clone_as_handle();
|
let handle = self.clone_as_handle();
|
||||||
update(handle);
|
update(handle);
|
||||||
|
|
||||||
self.objc.with_mut(|obj| unsafe {
|
// This is cheating, but there's no good way around it at the moment. If we (mutably) lock in
|
||||||
|
// Rust here, firing this call will loop back around into `dequeue`, which will then
|
||||||
|
// hit a double lock.
|
||||||
|
//
|
||||||
|
// Personally, I can live with this - `endUpdates` is effectively just flushing the
|
||||||
|
// already added updates, so with this small hack here we're able to keep the mutable
|
||||||
|
// borrow structure everywhere else, which feels "correct".
|
||||||
|
self.objc.get(|obj| unsafe {
|
||||||
let _: () = msg_send![obj, endUpdates];
|
let _: () = msg_send![obj, endUpdates];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -461,6 +468,7 @@ impl<T> ListView<T> {
|
||||||
// We need to temporarily retain this; it can drop after the underlying NSTableView
|
// We need to temporarily retain this; it can drop after the underlying NSTableView
|
||||||
// has also retained it.
|
// has also retained it.
|
||||||
let x = ShareId::from_ptr(index_set);
|
let x = ShareId::from_ptr(index_set);
|
||||||
|
|
||||||
self.objc.with_mut(|obj| {
|
self.objc.with_mut(|obj| {
|
||||||
let _: () = msg_send![obj, insertRowsAtIndexes:&*x withAnimation:animation_options];
|
let _: () = msg_send![obj, insertRowsAtIndexes:&*x withAnimation:animation_options];
|
||||||
});
|
});
|
||||||
|
@ -483,7 +491,8 @@ impl<T> ListView<T> {
|
||||||
let ye: id = msg_send![class!(NSIndexSet), indexSetWithIndex:0];
|
let ye: id = msg_send![class!(NSIndexSet), indexSetWithIndex:0];
|
||||||
let y = ShareId::from_ptr(ye);
|
let y = ShareId::from_ptr(ye);
|
||||||
|
|
||||||
self.objc.with_mut(|obj| {
|
// Must use `get` to avoid a double lock.
|
||||||
|
self.objc.get(|obj| {
|
||||||
let _: () = msg_send![obj, reloadDataForRowIndexes:&*x columnIndexes:&*y];
|
let _: () = msg_send![obj, reloadDataForRowIndexes:&*x columnIndexes:&*y];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -620,7 +629,10 @@ impl<T> ListView<T> {
|
||||||
|
|
||||||
impl<T> Layout for ListView<T> {
|
impl<T> Layout for ListView<T> {
|
||||||
fn with_backing_node<F: Fn(id)>(&self, handler: F) {
|
fn with_backing_node<F: Fn(id)>(&self, handler: F) {
|
||||||
self.objc.with_mut(handler);
|
// On macOS, we need to provide the scrollview for layout purposes - iOS and tvOS will know
|
||||||
|
// what to do normally.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
self.scrollview.objc.with_mut(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,13 @@ impl ObjcProperty {
|
||||||
Id::from_ptr(obj)
|
Id::from_ptr(obj)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given an Objective-C object, retains it and wraps it as a `Property`.
|
||||||
|
pub fn from_retained(obj: id) -> Self {
|
||||||
|
ObjcProperty(Rc::new(RefCell::new(unsafe {
|
||||||
|
Id::from_retained_ptr(obj)
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs a handler with mutable access for the underlying Objective-C object.
|
/// Runs a handler with mutable access for the underlying Objective-C object.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in a new issue