Start work on a native application menu

Add an application menu with a quit command, bound to command-q
This commit is contained in:
Max Brunsfeld 2021-04-07 17:48:22 -07:00
parent 57a3207897
commit 7e5186e4a0
2 changed files with 46 additions and 14 deletions

View file

@ -1,8 +1,7 @@
use super::{BoolExt as _, Dispatcher, FontSystem, Window}; use super::{BoolExt as _, Dispatcher, FontSystem, Window};
use crate::{executor, platform}; use crate::{executor, platform};
use anyhow::Result; use anyhow::Result;
use cocoa::base::id; use cocoa::{appkit::NSApplication, base::nil};
use objc::{class, msg_send, sel, sel_impl};
use std::{rc::Rc, sync::Arc}; use std::{rc::Rc, sync::Arc};
pub struct App { pub struct App {
@ -26,8 +25,8 @@ impl platform::App for App {
fn activate(&self, ignoring_other_apps: bool) { fn activate(&self, ignoring_other_apps: bool) {
unsafe { unsafe {
let app: id = msg_send![class!(NSApplication), sharedApplication]; let app = NSApplication::sharedApplication(nil);
let _: () = msg_send![app, activateIgnoringOtherApps: ignoring_other_apps.to_objc()]; app.activateIgnoringOtherApps_(ignoring_other_apps.to_objc());
} }
} }

View file

@ -1,7 +1,10 @@
use crate::platform::Event; use crate::platform::Event;
use cocoa::{ use cocoa::{
appkit::NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, appkit::{
base::{id, nil}, NSApplication, NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular, NSMenu,
NSMenuItem, NSWindow,
},
base::{id, nil, selector},
foundation::{NSArray, NSAutoreleasePool, NSString}, foundation::{NSArray, NSAutoreleasePool, NSString},
}; };
use ctor::ctor; use ctor::ctor;
@ -106,16 +109,16 @@ impl crate::platform::Runner for Runner {
let pool = NSAutoreleasePool::new(nil); let pool = NSAutoreleasePool::new(nil);
let app: id = msg_send![APP_CLASS, sharedApplication]; let app: id = msg_send![APP_CLASS, sharedApplication];
let _: () = msg_send![
app,
setActivationPolicy: NSApplicationActivationPolicyRegular
];
(*app).set_ivar(RUNNER_IVAR, self_ptr as *mut c_void);
let app_delegate: id = msg_send![APP_DELEGATE_CLASS, new]; let app_delegate: id = msg_send![APP_DELEGATE_CLASS, new];
app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
(*app).set_ivar(RUNNER_IVAR, self_ptr as *mut c_void);
(*app_delegate).set_ivar(RUNNER_IVAR, self_ptr as *mut c_void); (*app_delegate).set_ivar(RUNNER_IVAR, self_ptr as *mut c_void);
let _: () = msg_send![app, setDelegate: app_delegate]; app.setMainMenu_(create_menu_bar());
let _: () = msg_send![app, run]; app.setDelegate_(app_delegate);
let _: () = msg_send![pool, drain]; app.run();
pool.drain();
// The Runner is done running when we get here, so we can reinstantiate the Box and drop it. // The Runner is done running when we get here, so we can reinstantiate the Box and drop it.
Box::from_raw(self_ptr); Box::from_raw(self_ptr);
} }
@ -186,3 +189,33 @@ extern "C" fn open_files(this: &mut Object, _: Sel, _: id, paths: id) {
callback(paths); callback(paths);
} }
} }
unsafe fn create_menu_bar() -> id {
let menu_bar = NSMenu::new(nil).autorelease();
// App menu
let app_menu_item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(
ns_string("Application"),
Sel::from_ptr(ptr::null()),
ns_string(""),
)
.autorelease();
let quit_item = NSMenuItem::alloc(nil)
.initWithTitle_action_keyEquivalent_(
ns_string("Quit"),
selector("terminate:"),
ns_string("q\0"),
)
.autorelease();
let app_menu = NSMenu::new(nil).autorelease();
app_menu.addItem_(quit_item);
app_menu_item.setSubmenu_(app_menu);
menu_bar.addItem_(app_menu_item);
menu_bar
}
unsafe fn ns_string(string: &str) -> id {
NSString::alloc(nil).init_str(string).autorelease()
}