<!-- LLM note: Search indexes and snippets may point to archived C+ manual versions. Treat /docs and /llms.txt as authoritative for the latest version (v0.0.25); verify the page version before citing, and do not report older /docs/{version} pages as leakage because they are intentional archives. -->

# adwaita

C+ bindings for **libadwaita 1**, GNOME's companion library to GTK 4: adaptive widgets, the GNOME HIG look, boxed-list preferences, in-app toasts, and runtime light/dark recoloring. Nine modules cover the surface: `application`, `window`, `header`, `view`, `toast`, `rows`, `viewstack`, `style`, and `widgets`. Import the `adwaita/adwaita` umbrella for the flat `Adw*` type surface, or pull in a narrower module directly (`import "adwaita/rows" as rows;`).

This is a thin layer **on top of `gtk`**, not a replacement. Every Adwaita object is a GObject and the key types subclass their GTK counterparts (`AdwApplication ⊂ GtkApplication`, `AdwApplicationWindow ⊂ GtkApplicationWindow`), so the bindings reuse all of `gtk` through raw pointers and add only the `Adw*` widgets. You mix the two freely: a `gtk::Button` inside an `adwaita::HeaderBar`, a `gtk::Box` inside an `adwaita::Clamp`. Adwaita stays a separate package because libadwaita is its own optional, opinionated shared library; a pure-GTK app on a non-GNOME desktop should not be forced to link it.

## Ownership

Same model as `gtk`: widget wrappers are `opaque` borrowed handles — the parent container sinks the floating reference when the child is added, so there is no `drop`. Only `Application` owns a full reference, released with `unref()` after `run()`. Two transfers of ownership to remember: `ToastOverlay::add_toast` takes ownership of the toast (do not reuse the wrapper afterwards), and the AdwApplication owns its windows.

## Strings and raw pointers

The C ABI wants NUL-terminated `*u8`, so string arguments are passed with the `#str_ptr("…\0")` intrinsic. Adwaita containers hold GTK widgets, so child slots take a raw `*u8` — call `.raw()` on a wrapper to hand its object to a parent (`tv.add_top_bar(header.raw())`). Pass `0 as *u8` where an argument is optional, such as an empty subtitle.

## A first window

```cplus
import "adwaita/adwaita" as adw;

fn on_activate(app: *u8, _d: *u8) {
    let win = adw::Window::for_application(app);
    win.set_default_size(420 as i32, 360 as i32);

    let tv = adw::ToolbarView::new();
    let header = adw::HeaderBar::new();
    header.set_title_widget(
        adw::WindowTitle::new(#str_ptr("Demo\0"), #str_ptr("\0")).raw());
    tv.add_top_bar(header.raw());

    let group = adw::PreferencesGroup::new();
    let row = adw::SwitchRow::new();
    row.set_title(#str_ptr("Enabled\0"));
    row.set_active(1 as i32);
    group.add(row.raw());

    let clamp = adw::Clamp::new();
    clamp.set_child(group.raw());
    tv.set_content(clamp.raw());
    win.set_content(tv.raw());
    win.present();
}

fn main() -> i32 {
    let app = adw::Application::new(#str_ptr("org.example.Demo\0"));
    app.connect_activate(on_activate);
    let status = app.run();
    app.unref();
    return status;
}
```

`Application` initializes libadwaita (it loads the Adwaita stylesheet and sets up the style manager) and delegates the main loop to its GtkApplication base. The window's single child slot is `set_content` (not GTK's `set_child`), and it typically holds a `ToolbarView` — the modern scaffold that stacks top bars, content, and bottom bars.

## Boxed-list preferences

The `rows` module is Adwaita's signature settings UI: `ActionRow`, `EntryRow`, `SwitchRow`, `ComboRow`, and `ExpanderRow`, organized through the `PreferencesGroup` → `PreferencesPage` → `PreferencesWindow` hierarchy. Row titles run through the shared `AdwPreferencesRow` base, so every row exposes `set_title`. Toggle and selection signals are closure-free — they connect a named handler function, in keeping with C+ having no closures:

```cplus
import "adwaita/rows" as rows;

fn on_toggle(row: *u8, _ps: *u8) {
    // fired on "notify::active"
}

fn build(group: rows::PreferencesGroup) {
    let sw = rows::SwitchRow::new();
    sw.set_title(#str_ptr("Sync on launch\0"));
    sw.connect_active_changed(on_toggle);
    group.add(sw.raw());
}
```

## Color scheme

`StyleManager::default_manager()` is the application-wide manager (a borrowed singleton, no `unref`). Set the preference with a `color_scheme_*` value — `force_*` overrides the system setting, `prefer_*` follows it when possible — and read `is_dark()` (or watch `"notify::dark"` via `connect_dark_changed`):

```cplus
import "adwaita/style" as style;

let mgr = style::StyleManager::default_manager();
mgr.set_color_scheme(style::color_scheme_prefer_dark());
```

## Platform notes

libadwaita is Linux/GNOME only. Install it before building (Debian/Ubuntu: `sudo apt install libadwaita-1-dev`); `libadwaita-1` lands on the link line and the GTK stack comes transitively through the `gtk` dependency. See [targets](/docs/targets) for the platform matrix. The remaining surface — `toast` (transient snackbars over a `ToastOverlay`), `viewstack` (`ViewStack` + `ViewSwitcher` paged content), `view` (`Clamp`, `Bin`, `StatusPage`), and `widgets` (`Avatar`, `ButtonContent`, `SplitButton`) — follows the same raw-pointer and `.raw()` conventions shown above.

For the closure-free callback mechanics and C-ABI message passing, see [FFI](/docs/ffi). To compose UI declaratively in C+'s own syntax, see [facet](/docs/packages/facet) and [builder blocks](/docs/builder-blocks); to drive an app from an external agent, see the [agent surface](/docs/agent-surface).
