mod rustnsobject;
extern crate objc;
extern crate objc_foundation;
extern crate cocoa;
extern crate fruitbasket;
use self::fruitbasket::FruitApp;
pub use ::TStatusBar;
pub use ::NSCallback;
use objc::runtime::Class;
use self::cocoa::base::{nil, YES};
use self::cocoa::appkit::NSStatusBar;
use self::cocoa::foundation::NSString;
use self::cocoa::appkit::{NSMenu,
NSMenuItem,
NSImage,
NSVariableStatusItemLength,
NSStatusItem,
NSButton};
use self::rustnsobject::{NSObj, NSObjTrait, NSObjCallbackTrait};
use std::sync::mpsc::Sender;
use std::ptr;
use std::ffi::CStr;
pub type Object = objc::runtime::Object;
pub struct OSXStatusBar {
object: NSObj,
app: FruitApp,
status_bar_item: *mut objc::runtime::Object,
menu_bar: *mut objc::runtime::Object,
}
impl TStatusBar for OSXStatusBar {
type S = OSXStatusBar;
fn new(tx: Sender<String>) -> OSXStatusBar {
let mut bar;
unsafe {
let nsapp = FruitApp::new();
nsapp.set_activation_policy(fruitbasket::ActivationPolicy::Prohibited);
let status_bar = NSStatusBar::systemStatusBar(nil);
bar = OSXStatusBar {
app: nsapp,
status_bar_item: status_bar.statusItemWithLength_(NSVariableStatusItemLength),
menu_bar: NSMenu::new(nil),
object: NSObj::alloc(tx),
};
let _: () = msg_send![bar.status_bar_item, setHighlightMode:YES];
let title = NSString::alloc(nil).init_str("connectr");
NSButton::setTitle_(bar.status_bar_item, title);
let _: () = msg_send![title, release];
let icon_name = "connectr_80px_300dpi";
let img_path = match fruitbasket::FruitApp::bundled_resource_path(icon_name, "png") {
Some(path) => path,
None => format!("{}.png", icon_name),
};
let img = NSString::alloc(nil).init_str(&img_path);
let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
#[cfg(feature = "mac_white_icon")]
let _: () = msg_send![icon, setTemplate: YES]; bar.status_bar_item.button().setImage_(icon);
let _: () = msg_send![img, release];
let _: () = msg_send![icon, release];
let img = NSString::alloc(nil).init_str(&img_path);
let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
let _: () = msg_send![bar.status_bar_item.button(), setAlternateImage: icon];
let _: () = msg_send![img, release];
let _: () = msg_send![icon, release];
bar.status_bar_item.setMenu_(bar.menu_bar);
bar.object.cb_fn = Some(Box::new(
move |s, sender| {
let cb = s.get_value(sender);
cb(sender, &s.tx);
}
));
}
bar
}
fn can_redraw(&mut self) -> bool {
true
}
fn clear_items(&mut self) {
unsafe {
let old_menu = self.menu_bar;
self.menu_bar = NSMenu::new(nil);
self.status_bar_item.setMenu_(self.menu_bar);
let _: () = msg_send![old_menu, removeAllItems];
let _: () = msg_send![old_menu, release];
}
}
fn set_tooltip(&mut self, text: &str) {
unsafe {
let img = NSString::alloc(nil).init_str(text);
let _: () = msg_send![self.status_bar_item.button(), setToolTip: img];
let _: () = msg_send![img, release];
}
}
fn add_label(&mut self, label: &str) {
unsafe {
let txt = NSString::alloc(nil).init_str(label);
let quit_key = NSString::alloc(nil).init_str("");
let app_menu_item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
let _: () = msg_send![txt, release];
let _: () = msg_send![quit_key, release];
self.menu_bar.addItem_(app_menu_item);
let _: () = msg_send![app_menu_item, release];
}
}
fn add_quit(&mut self, label: &str) {
unsafe {
let txt = NSString::alloc(nil).init_str(label);
let quit_key = NSString::alloc(nil).init_str("");
let app_menu_item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(txt, sel!(terminate:), quit_key);
let _: () = msg_send![txt, release];
let _: () = msg_send![quit_key, release];
self.menu_bar.addItem_(app_menu_item);
let _: () = msg_send![app_menu_item, release];
}
}
fn add_separator(&mut self) {
unsafe {
let cls = Class::get("NSMenuItem").unwrap();
let sep: *mut Object = msg_send![cls, separatorItem];
self.menu_bar.addItem_(sep);
}
}
fn add_item(&mut self, menu: Option<*mut Object>,item: &str, callback: NSCallback, selected: bool) -> *mut Object {
unsafe {
let txt = NSString::alloc(nil).init_str(item);
let quit_key = NSString::alloc(nil).init_str("");
let app_menu_item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
let _: () = msg_send![txt, release];
let _: () = msg_send![quit_key, release];
self.object.add_callback(app_menu_item, callback);
let objc = self.object.take_objc();
let _: () = msg_send![app_menu_item, setTarget: objc];
if selected {
let _: () = msg_send![app_menu_item, setState: 1];
}
let item: *mut Object = app_menu_item;
match menu {
Some(menu) => { menu.addItem_(app_menu_item); },
None => { self.menu_bar.addItem_(app_menu_item); }
}
let _: () = msg_send![app_menu_item, release];
item
}
}
fn add_submenu(&mut self, label: &str, callback: NSCallback) -> *mut Object {
unsafe {
let submenu = NSMenu::new(nil);
let txt = NSString::alloc(nil).init_str(label);
let quit_key = NSString::alloc(nil).init_str("");
let app_menu_item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(txt,
self.object.selector(),
quit_key);
self.object.add_callback(app_menu_item, callback);
let objc = self.object.take_objc();
let _: () = msg_send![app_menu_item, setTarget: objc];
let _: () = msg_send![app_menu_item, setSubmenu: submenu];
let _: () = msg_send![txt, release];
let _: () = msg_send![quit_key, release];
self.menu_bar.addItem_(app_menu_item);
let _: () = msg_send![app_menu_item, release];
let _: () = msg_send![submenu, release];
submenu
}
}
fn update_item(&mut self, item: *mut Object, label: &str) {
unsafe {
let ns_label = NSString::alloc(nil).init_str(label);
let _: () = msg_send![item, setTitle: ns_label];
let _: () = msg_send![ns_label, release];
}
}
fn sel_item(&mut self, sender: u64) {
let target: *mut Object = sender as *mut Object;
unsafe {
let _: () = msg_send![target, setState: 1];
}
}
fn unsel_item(&mut self, sender: u64) {
let target: *mut Object = sender as *mut Object;
unsafe {
let _: () = msg_send![target, setState: 0];
}
}
fn register_url_handler(&mut self) {
unsafe {
let cls = Class::get("NSAppleEventManager").unwrap();
let manager: *mut Object = msg_send![cls, sharedAppleEventManager];
let objc = self.object.take_objc();
let _: () = msg_send![objc, handleURLEvent: 0 withReplyEvent: 0];
let _: () = msg_send![manager, setEventHandler: objc
andSelector: sel!(handleURLEvent:withReplyEvent:)
forEventClass: 0x4755524c
andEventID: 0x4755524c];
info!("Registered URL handler");
}
}
fn run(&mut self, block: bool) {
let period = match block {
true => fruitbasket::RunPeriod::Forever,
_ => fruitbasket::RunPeriod::Once,
};
let _ = self.app.run(period);
}
}
pub fn resource_dir() -> Option<String> {
unsafe {
let cls = Class::get("NSBundle").unwrap();
let bundle: *mut Object = msg_send![cls, mainBundle];
let path: *mut Object = msg_send![bundle, resourcePath];
let cstr: *const i8 = msg_send![path, UTF8String];
if cstr != ptr::null() {
let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
return Some(rstr);
}
None
}
}