iOS simulator leg: listbox_demo driven through AetherUIDriver (#22) - #166
Merged
Merged
Conversation
Phase 1e2 on the macOS leg: `ae build --target=<arch>-ios-simulator --emit=staticlib` compiles the Aether runtime for the simulator (tests/ios/runtime_seed.ae), aetherc emits listbox_demo's portable C, clang links app + UIKit backend + driver against that archive and the frameworks, the binary goes into a bundle (tests/ios/Info.plist), the bundle into a booted iPhone simulator, and tests/listbox_demo's spec runs against the app over the driver port, unchanged from the desktop backends. This is the acceptance #22 set out and could not meet while the toolchain half (aether #1385) was open: an aether-ui app linked against the UIKit backend and an iOS build of libaether, running on iOS, widgets rendered, taps firing their closures.
The first run got as far as a booted simulator with the bundle installed and launched, and no driver answer in 20s, with nothing on the app's stdout or stderr. The phase now waits 40s and, on a silent app, prints whether the process is alive, the unified log for it, and the head of its crash report if it left one.
The simulator leg's first run found the driver's partial table: the app launched, the server bound, and the first /widgets request walked the view tree from the HTTP thread and died in -[__NSArrayM objectAtIndex:]. UIKit, like GTK4, is not for reading off its thread. The adapter now supplies run_on_ui_thread, so the shared server services every request on the main queue, and the rest of the table AppKit and Win32 fill: text, visibility, parent, children, rect, enabled, classes, focus, hover/pressed readback, screenshot, and dispatch_action for click, set_text, toggle, set_value, set_state, focus, key, split, tabs, context menu, pick, hover/press/ release, the canvas events and shutdown. What iOS has no counterpart for (window resize, menu bar, tray) answers 404 rather than pretending. Two parity fixes on the way: on_click keeps its closure addressable by handle so a driver click on a plain container (a listbox row) fires it, and picker_set_selected fires the change callback as it does on the other backends. The crash-report extraction in the leg's diagnostics now prints the exception, its backtrace and the faulting thread with image names.
The simulator's first spec run passed the button clicks and failed every row-selection case: clear_children, remove_child, set_child and navstack_pop took views out of the tree and left them in the registry, so the driver listed the rows of every rebuild that was gone, found "person 2" in a retired one, and clicked a row that no longer existed. The same slots kept every retired view alive for the life of the process and never gave their closure boxes back. Retired views now leave the registry (aeui_unregister_view_tree, what AppKit's unregister_view_tree and win32's mark_subtree_dead do), and the boxes their helpers hold are released on the next turn of the main queue, since the closure retiring its own widget is on the stack when this runs (#145's lesson). AeuiClosureHolder is the protocol every closure-holding helper adopts so one walk finds them all.
…reach the window handler The simulator run now selects rows by tap and programmatically; the keyboard cases still failed because focus_impl on a row did nothing: UIView answers NO to canBecomeFirstResponder and has no setter, so _listbox_owns_focus never saw a row focused and the arrow keys were ignored. AeuiStackView answers from a flag set_focusable sets, as AppKit's AetherStackView does, and delivers hardware-keyboard presses to aether_ui_window_key_deliver with the desktop backends' key names.
…-leg # Conflicts: # ci.sh
…er says what CI runs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #22 — its acceptance criterion, run on every push: an aether-ui app linked against the UIKit backend and an iOS build of libaether, running on iOS, widgets rendered, taps firing their DSL closures.
The leg (ci.sh Phase 1e2, macOS runner)
ae build --target=aarch64-ios-simulator --emit=staticlib tests/ios/runtime_seed.ae→ the Aether runtime compiled for the simulator (aether #1385's toolchain half, #1654/#1868 upstream).aetherc examples/listbox_demo/listbox_demo.ae→ its portable C, as build.sh emits it.xcrun clang -target arm64-apple-ios17.0-simulatorlinks app +aether_ui_uikit.m+ driver against that archive and the frameworks — Phase 1e's link line with the real runtime wheretests/ios/link_stub.cstood.tests/ios/Info.plist, scene manifest so the backend takes itsUIWindowScenepath),simctl boot/install/launchwithSIMCTL_CHILD_AETHER_UI_TEST_PORT.tests/listbox_demo/spec_listbox_demo.aeruns against it unchanged — 9/9: rows rendered by UIKit, a tap selecting a row through the DSL's closure,on_selectfiring, programmatic select, selection reset on update, a 200-row update driver-visible, Down/Up/Home/End moving the selection.On failure the phase prints whether the process is alive, its unified log, and the crash report's exception, exception backtrace and faulting thread with image names.
What the first runs found, and fixed here
-[__NSArrayM objectAtIndex:]on the first/widgets. UIKit, like GTK4, is not for reading off its thread: the adapter now suppliesrun_on_ui_thread, so every request is serviced on the main queue, and the rest of the table AppKit and Win32 fill (text, visibility, parent, children, rect, enabled, classes, focus, hover/pressed, screenshot, anddispatch_actionfor click, set_text, toggle, set_value, set_state, focus, key, split, tabs, context menu, pick, hover/press/release, the canvas events, shutdown). Window resize, menu bar and tray answer 404: iOS has none.clear_children,remove_child,set_child,navstack_popleft views in the registry: alive for the life of the process, listed by the driver with stale text and parent (the spec found "person 2" in a row of a rebuild that was gone and clicked that), closure boxes never given back.aeui_unregister_view_treeretires them; boxes are released on the next main-queue turn (a closure retiring its own widget is on the stack — win32 gives back the closure boxes a retired widget owned #145's lesson).AeuiClosureHolderis the protocol every closure-holding helper adopts.AeuiStackViewanswerscanBecomeFirstResponderfrom theset_focusableflag (AppKit'sAetherStackViewdoes the same) and delivers hardware-keyboard presses to the window's key handler.picker_set_selectedfires the change callback as on the other backends;on_clickkeeps its closure addressable by handle.README and CHANGELOG updated; the UIKit header says what CI runs.