C+
GUI

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