+- **v0.5.322** — Closes #216, #217, #218: 7 GTK4 FFIs that the doc-tests gate on Linux CI was tripping over. Each issue's symptom was an `undefined reference to perry_ui_<name>` link error against `libperry_ui_gtk4.a` for an FFI the macOS twin already wired. (1) **#216** `perry_ui_open_folder_dialog` (`docs/examples/ui/dialogs/snippets.ts`): factored `crates/perry-ui-gtk4/src/file_dialog.rs::open_dialog` into a private `open_dialog_with_action(callback, title, action, accept_label)` helper, then added `open_folder_dialog` that calls it with `FileChooserAction::SelectFolder` + "Choose Folder" / "Choose" labels. Same callback contract as `open_dialog`: NaN-boxed string on success, `TAG_UNDEFINED` (0x7FFC_0000_0000_0001) on cancel — matches the macOS `NSOpenPanel`-with-`canChooseDirectories: YES, canChooseFiles: NO` shape. (2) **#217** 4 widget-tree FFIs (`docs/examples/ui/layout/snippets.ts`): all in `crates/perry-ui-gtk4/src/widgets/mod.rs`. `widget_remove_child` dispatches by parent kind (`Box::remove`, `ScrolledWindow::set_child(None)`, `Overlay::set_child(None)` for main child or `remove_overlay` for overlays, `Frame` inner-box `remove`); the WIDGETS vec doesn't shrink because handles are positional indices, only the GTK4 parent link is severed (matches `removeFromSuperview`). `widget_reorder_child(parent, from_index, to_index)` snapshots `Box` siblings via `first_child()` walk, locates the child at `from_index`, then calls `Box::reorder_child_after(&child, anchor)` where the anchor index is `to` when moving forward or `to-1` when moving back (the macOS `arrangedSubviews + insertArrangedSubview:atIndex:` shape doesn't translate directly because `reorder_child_after` is positional-relative-to-sibling, not absolute-by-index). Out-of-range indices are clamped: `from > N-1` → no-op, `to >= N` → moves to end. `widget_add_overlay`: if parent is `gtk4::Overlay` → `add_overlay`; otherwise log a warning + fall through to `add_child` (GTK4 widgets have a single immutable parent slot — can't retroactively wrap a non-Overlay parent). `widget_set_overlay_frame(handle, x, y, w, h)`: GTK4's layout model is constraint-based not absolute-frame, so we approximate with `halign/valign = Start` + `set_margin_start(x)` + `set_margin_top(y)` + `set_size_request(w, h)` — works correctly when the parent is a ZStack (which is backed by `gtk4::Overlay` and honors child halign/valign), an OK approximation elsewhere. (3) **#218** SplitView (`docs/examples/ui/layout/snippets.ts`): new `crates/perry-ui-gtk4/src/widgets/splitview.rs` backed by `gtk4::Paned::new(Orientation::Horizontal)` (matches macOS `NSSplitView`'s vertical-divider/side-by-side default). `splitview_create(_left_width)` accepts the macOS arg for signature parity but ignores it — `Paned::set_position` is a separate setter. `splitview_add_child`: first call → `set_start_child`, second → `set_end_child`, third+ → no-op + warning. **2-vs-N caveat**: GTK4 `Paned` supports exactly 2 children where `NSSplitView` supports N; users wanting >2 panes on Linux nest SplitViews recursively. Verified: `cargo build --release -p perry-ui-gtk4` clean (only pre-existing `js_string_from_bytes` signature redeclaration warnings between `audio.rs` and `lib.rs`); all 7 new symbols present in `nm --defined-only target/release/libperry_ui_gtk4.a` (`perry_ui_open_folder_dialog`, `perry_ui_widget_remove_child`, `_reorder_child`, `_add_overlay`, `_set_overlay_frame`, `perry_ui_splitview_create`, `_add_child`); `cargo run --release -p perry-ui --bin styling-matrix -- --check` clean (none of these FFIs are styling props — folder dialog is "system", layout/splitview are container management — so no matrix rows are added); `PERRY_UI_TEST_MODE=1 ./perry compile docs/examples/ui/dialogs/snippets.ts -o /tmp/dialogs_snippets` produces a 0.9 MB ELF that exits 0 in test mode; same for `docs/examples/ui/layout/snippets.ts` → 1.0 MB ELF, exit 0. The layout snippet emits the documented `widget_add_overlay on non-Overlay parent — falling back to add_child` warnings at runtime because the example uses `widgetAddOverlay` on an HStack/VStack rather than a ZStack — the warning surface I added makes this discoverable so example authors can wrap with ZStack to get true float-above semantics on GTK4 (separate sample-update follow-up; not blocking the link gate the issues filed for).
0 commit comments