cacao/src/bundle.rs
Ryan McGrath 2f9a5b5e67
Rework the Layout trait implementation.
- Adds a new `ObjcProperty` type, which wraps our Objective-C objects in
  a Rust-backed Rc/Refcell combo. This in general makes understanding
  reference counting/storage more digestable when reading through the
  codebase and leans more on Rust to do its thing than the Objective-C
  runtime.

- Most widgets that need to implement `Layout` now only need to provide
  a slot for running a handler with the underlying node.

- Further documentation work ongoing.
2021-03-26 13:29:39 -07:00

103 lines
3.2 KiB
Rust

//! Implements some functionality to handle dynamically setting the `NSBundle` identifier.
//!
//!
//
// This is not currently in use, but does have places where it's useful... and to be honest I'm
// kinda happy this is done as a swizzling implementation in pure Rust, which I couldn't find
// examples of anywhere else.
//
// Disregard until you can't, I guess.
use std::ffi::CString;
use std::mem;
use objc::{class, msg_send, sel, sel_impl, Encode, Encoding, EncodeArguments, Message};
use objc::runtime::{Class, Sel, Method, Object, Imp};
use objc::runtime::{
objc_getClass,
class_addMethod,
class_getInstanceMethod,
method_exchangeImplementations
};
use crate::foundation::{id, nil, BOOL, YES, NSString};
/// Types that can be used as the implementation of an Objective-C method.
pub trait MethodImplementation {
/// The callee type of the method.
type Callee: Message;
/// The return type of the method.
type Ret: Encode;
/// The argument types of the method.
type Args: EncodeArguments;
/// Returns self as an `Imp` of a method.
fn imp(self) -> Imp;
}
macro_rules! method_decl_impl {
(-$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
impl<$s, $r $(, $t)*> MethodImplementation for $f
where $s: Message, $r: Encode $(, $t: Encode)* {
type Callee = $s;
type Ret = $r;
type Args = ($($t,)*);
fn imp(self) -> Imp {
unsafe { mem::transmute(self) }
}
}
);
($($t:ident),*) => (
method_decl_impl!(-T, R, extern fn(&T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, extern fn(&mut T, Sel $(, $t)*) -> R, $($t),*);
);
}
method_decl_impl!();
method_decl_impl!(A);
extern fn get_bundle_id(this: &Object, s: Sel, v: id) -> id {
unsafe {
let bundle = class!(NSBundle);
let main_bundle: id = msg_send![bundle, mainBundle];
let e: BOOL = msg_send![this, isEqual:main_bundle];
if e == YES {
let url: id = msg_send![main_bundle, bundleURL];
let x: id = msg_send![url, absoluteString];
println!("Got here? {:?}", x);
unsafe {
NSString::alloc(nil).init_str("com.secretkeys.subatomic")
}
} else {
msg_send![this, __bundleIdentifier]
}
}
}
unsafe fn swizzle_bundle_id<F>(bundle_id: &str, func: F) where F: MethodImplementation<Callee=Object> {
let name = CString::new("NSBundle").unwrap();
let cls = objc_getClass(name.as_ptr());
// let mut cls = class!(NSBundle) as *mut Class;
// Class::get("NSBundle").unwrap();
// let types = format!("{}{}{}", Encoding::String, <*mut Object>::ENCODING, Sel::ENCODING);
let added = class_addMethod(
cls as *mut Class,
sel!(__bundleIdentifier),
func.imp(),
CString::new("*@:").unwrap().as_ptr()
);
let method1 = class_getInstanceMethod(cls, sel!(bundleIdentifier)) as *mut Method;
let method2 = class_getInstanceMethod(cls, sel!(__bundleIdentifier)) as *mut Method;
method_exchangeImplementations(method1, method2);
}
pub fn set_bundle_id(bundle_id: &str) {
unsafe {
swizzle_bundle_id(bundle_id, get_bundle_id as extern fn(&Object, _, _) -> id);
}
}