AppKit hello
This example is the docs/examples/recipes/appkit_hello recipe from the C+
source tree. It backs the plain GUI claim: C+ can build a native macOS AppKit app
with typed package APIs, dynamic text bridging, callbacks, and app.run().
| Claim | How this recipe checks it |
|---|---|
| Native macOS GUI | Builds a real Application, Window, TextField, and Button |
| Typed AppKit package | Uses vendor/appkit instead of raw objc_msgSend declarations in app code |
| String bridge works | Converts C+ Text to NSString, writes it to a label, reads it back, and compares |
| Callbacks work | The Quit button is wired with Button::set_on_click(fn(*u8)) |
| Event loop works | The app prints READY, activates the window, then enters app.run() |
Project layout
docs/examples/recipes/appkit_hello/
├── Cplus.toml
├── README.md
└── src/main.cplus
Core source
The app imports the typed AppKit modules and the conversion bridge:
import "appkit/application" as application;
import "appkit/window" as window;
import "appkit/controls" as controls;
import "appkit/graphics" as graphics;
import "appkit/convert" as bridge;
import "stdlib/text" as text;
The label text is built dynamically as C+ Text, converted to NSString, set
on a real AppKit text field, then read back into C+:
let greeting: text::Text = "Hello from C+".to_text();
let ns_greeting: *u8 = bridge::cplus_string_to_nsstring(greeting);
rt::msg_void_id(label.obj, rt::sel(#str_ptr("setStringValue:\0")), ns_greeting);
let current_ns: *u8 = label.string_value();
let back: text::Text = bridge::nsstring_to_cplus_string(current_ns);
if unsafe { back.as_str() } != "Hello from C+" {
return 1;
}
The Quit button is wired to a named C+ function. No closure support is required:
fn on_quit_click(sender: *u8) {
let app = application::Application::shared();
app.terminate(sender);
}
let quit_btn = controls::Button::new(btn_frame);
quit_btn.set_title(#str_ptr("Quit\0"));
quit_btn.set_on_click(on_quit_click);
The final check is that this is not just object construction. It shows and activates the window, prints the headless-test marker, then enters AppKit:
win.make_key_and_order_front(null_sender);
app.activate(1 as i8);
unsafe { puts(#str_ptr("READY\0")); }
app.run();
Reproduce
From docs/examples/recipes/appkit_hello in the C+ source tree:
cpc build
./target/debug/appkit_hello
Expected result: stdout prints READY, a window titled C+ AppKit Demo
appears, the label reads Hello from C+, and clicking Quit exits the app.
This complements the AppKit agent surface example: that one proves the agent bridge, while this one proves the ordinary native GUI path and the real AppKit event loop.
‹ Back to all examples