Last active
July 31, 2020 20:13
-
-
Save kettle11/3934c29c16b4b9893cee1a45d8a88b02 to your computer and use it in GitHub Desktop.
The minimal amount of code required to create a window on MacOS from Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use objc::runtime::{Object, NO}; | |
use objc::*; | |
// We must link with AppKit for all application and windowing related matters. | |
#[link(name = "AppKit", kind = "framework")] | |
extern "C" {} | |
// https://developer.apple.com/documentation/objectivec/nsuinteger | |
#[cfg(target_pointer_width = "32")] | |
pub type NSUInteger = u32; | |
#[cfg(target_pointer_width = "64")] | |
pub type NSUInteger = u64; | |
// https://developer.apple.com/documentation/coregraphics/cgfloat?language=objc | |
#[cfg(target_pointer_width = "32")] | |
pub type CGFloat = f32; | |
#[cfg(target_pointer_width = "64")] | |
pub type CGFloat = f64; | |
// https://developer.apple.com/documentation/coregraphics/cgpoint?language=objc | |
#[repr(C)] | |
pub struct CGPoint { | |
pub x: CGFloat, | |
pub y: CGFloat, | |
} | |
// https://developer.apple.com/documentation/coregraphics/cgsize?language=objc | |
#[repr(C)] | |
pub struct CGSize { | |
pub width: CGFloat, | |
pub height: CGFloat, | |
} | |
// https://developer.apple.com/documentation/coregraphics/cgrect?language=objc | |
#[repr(C)] | |
pub struct CGRect { | |
pub origin: CGPoint, | |
pub size: CGSize, | |
} | |
// https://developer.apple.com/documentation/foundation/nsrect?language=objc | |
pub type NSRect = CGRect; | |
// https://developer.apple.com/documentation/objectivec/nil | |
pub const nil: *mut Object = 0 as *mut Object; | |
// https://developer.apple.com/documentation/appkit/nsapplicationactivationpolicy/nsapplicationactivationpolicyregular?language=objc | |
pub const NSApplicationActivationPolicyRegular: NSUInteger = 0; | |
// https://developer.apple.com/documentation/appkit/nsbackingstoretype/nsbackingstorebuffered?language=objc | |
pub const NSBackingStoreBuffered: NSUInteger = 2; | |
// https://developer.apple.com/documentation/appkit/nswindowstylemask | |
pub const NSWindowStyleMaskTitled: NSUInteger = 1; | |
pub const NSWindowStyleMaskClosable: NSUInteger = 1 << 1; | |
pub const NSWindowStyleMaskMiniaturizable: NSUInteger = 1 << 2; | |
pub const NSWindowStyleMaskResizable: NSUInteger = 1 << 3; | |
unsafe fn setup_application() { | |
// https://developer.apple.com/documentation/appkit/nsapplication | |
// Retrieve the global 'sharedApplication' | |
let ns_application: *mut Object = msg_send![class!(NSApplication), sharedApplication]; | |
// https://developer.apple.com/documentation/appkit/nsapplicationactivationpolicy/nsapplicationactivationpolicyregular?language=objc | |
// "The application is an ordinary app that appears in the Dock and may have a user interface." | |
// Apple claims this is the default, but without manually setting it the application does not appear. | |
// | |
// Objective-C works with a message passing system. The 'msg_send!' macro abstracts some of the details of the | |
// message passing system and requires a peculiar syntax. | |
// The first item in msg_send! is the item being sent the message. | |
// The following items are the names of the parameters followed by the argument. | |
// A quirk of the `objc` crate is that it needs to know the return type of the msg_send! | |
// call. So even though nothing is returned that must be specified with `let () = `. | |
let () = msg_send![ | |
ns_application, | |
setActivationPolicy: NSApplicationActivationPolicyRegular | |
]; | |
// Allocate the window before we initialize it. | |
let ns_window: *mut Object = msg_send![class!(NSWindow), alloc]; | |
// The size and location of the window we're about to create. | |
let window_rectangle = NSRect { | |
origin: CGPoint { x: 0., y: 0. }, | |
size: CGSize { | |
width: 500., | |
height: 500., | |
}, | |
}; | |
// We'd like a window that is resizable, has a title, is closable, and can be minimized. | |
let style = NSWindowStyleMaskResizable | |
| NSWindowStyleMaskTitled | |
| NSWindowStyleMaskClosable | |
| NSWindowStyleMaskMiniaturizable; | |
// https://developer.apple.com/documentation/appkit/nswindow/1419477-initwithcontentrect?language=objc | |
// Initialize the window with our settings. | |
let () = msg_send![ | |
ns_window, | |
initWithContentRect: window_rectangle | |
styleMask: style | |
backing:NSBackingStoreBuffered // The Apple recommended setting. See above documentation link for more info. | |
defer:NO // Create the window immediately. | |
]; | |
// https://developer.apple.com/documentation/appkit/nswindow/1419208-makekeyandorderfront?language=objc | |
// This call actually displays the window. Without it the window won't appear | |
let () = msg_send![ns_window, makeKeyAndOrderFront: nil]; | |
// Run the application forever | |
let () = msg_send![ns_application, run]; | |
} | |
fn main() { | |
unsafe { | |
setup_application(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment