C+
Packages · View as Markdown

appkit

Typed Cocoa / AppKit bindings for building native macOS desktop apps. The package is one generated module — the canonical entry point is import "appkit/appkit" as appkit; — produced by cpc-bindgen from the AppKit SDK headers, so it tracks the framework class-for-class: hundreds of Cocoa classes (Application, Window, View, Button, TextField, Menu, Toolbar, and the rest) each surface as a typed { _obj } wrapper carrying raw() and from_raw().

Callbacks are closure-free, in keeping with C+ having no closures. Action controls use Cocoa's target/action: a factory like Button::button_with_title(title, target, action) takes a target object and an action selector, and block-taking APIs accept a named fn(...) pointer plus a ctx: *u8 (for example DraggingItem::set_image_components_provider(cb, ctx)). Data crosses the boundary through objc/bridge: a str coerces to NSString, methods hand back Text, arrays arrive as Vec[T], and NSData is the Data wrapper; the geometry structs rt::Point, rt::Size, and rt::Rect cross verbatim.

Ownership: the "+1 normal form"

Types the generator recognizes as alloc/init-owned carry a drop(ref this) that releases their Objective-C object exactly once — Window, View, Menu, Toolbar, and the owned Foundation values (AttributedString, Data, and friends) all follow this one rule, so a wrapper that goes out of scope cannot leak. Objects handed back from autoreleasing factory methods (Button::button_with_title, TextField::label_with_string) or shared accessors (Application::shared_application) are non-owning wrappers with no drop, and are never released. Over 150 types carry the owning drop.

Drag and drop

AppKit supports both ends of a drag. A drop destination registers for dropped data, and a drag source can begin a drag from a mouseDragged: gesture by building DraggingItems (DraggingItem::new / DraggingItem::new_with_pasteboard_writer) and calling View::begin_dragging_session_with_items(items, event, source), which returns a DraggingSession. A runnable appkit_drag_drop recipe lives in the compiler repo.

Labels vs. fields

TextField::label_with_string is a true static label — non-editable and non-bezeled — so it does not behave like an input or accept dropped text. Use TextField::text_field_with_string (or the TextField initializers) when you want an editable field.

import "appkit/appkit" as appkit;

fn main() -> i32 {
    let app = appkit::Application::shared_application();
    app.set_activation_policy(appkit::ApplicationActivationPolicy::Regular);
    // ... build window + controls ...
    app.run();
    return 0;
}

Parenting, symbols, and widgets

Every wrapper exposes raw() to hand its Objective-C pointer to a parent that will own it and from_raw() to re-wrap one, so a view moved into a parent is not double-released. The bindings also cover SF SymbolsImage::image_with_system_symbol_name(name, description) returns Option[Image] — layer-backed views via View::set_wants_layer, and broad toolbar and text coverage.

A runnable reference app lives in the compiler repo at docs/examples/recipes/appkit_hello/; the public walkthrough is AppKit hello. For the underlying Objective-C message-send mechanics, see FFI. To drive an AppKit app from an external agent, see the agent surface and agent_appkit.