Skip to content

applets-frontend (batch 2026-10-27-b6): AppKit UI for the library applets

The portable applets (controller 0xc, error 0xe, player select 0x10, web 0x13/0x17, album 0x15) had no UI: they always confirmed, logged or left at once. They now show real sheets in window mode; headless runs keep their scripted answers.

What changed

  • frontend/src/applet_sheets.m (macOS only, new): napple_frontend_sheet_controller / _player_select / _error / _web / _image (declared in napple_frontend.h). Each blocks the guest thread until the user answers. Alerts (controller, player select, error) use NSAlert in a modal loop; the web (WKWebView, http(s) and file:// offline documents, back / forward / address / Done) and album (image, Select / Next / Close album) sheets are plain windows finished by a semaphore: a modal loop does not service the dispatch queues WebKit needs (the page never committed under runModalForWindow). file:// pages may read the title's HTML root (applet_web_html_root()).
  • Hooks (portable, runtime/src/services): applet_set_controller_ui / applet_controller_ask, applet_set_player_select_ui / applet_player_select_ask (applet_lib_core), applet_ui_album_selecting (is the album in select mode), album hook answer -1 closes the album (album_run stops walking), applet_web_html_root. runtime/src/app.m registers all five sheets with the existing applet_set_error_hook, applet_ui_set_open_web, applet_ui_set_show_image once the window exists (register_applet_sheets, not in headless runs, not on iOS).
  • Scripted answers, checked before any sheet or hook so e2e can drive them: NAPPLE_CONTROLLER_SUPPORT (cancel / strict, existing), NAPPLE_PLAYER_SELECT (<index> / cancel, existing), new NAPPLE_WEB_ANSWER (back | closed | requested | error | <exit reason number>, leaves on the page it opened), new NAPPLE_ALBUM_PICK (<index> | first | next | none), existing NAPPLE_SWKBD_ANSWER.
  • The controller sheet shows what the game asked (min..max, single mode), the connected pads (frontend_connected_pads) and a players popup; cancel reports 0 players, selected id 0xffffffff, result 2. The player select sheet lists applet_profiles() (the account service's lister when one is registered, else the one local user) and cancels with result 2. The error sheet shows the error code and description.
  • The software keyboard already runs for real in window mode (the text bar, frontend_text_input); nothing changed there.
  • Test aids: NAPPLE_SHEET_AUTO=<action>[:ms] presses a sheet's button by itself (confirm / cancel / next / leave), NAPPLE_SHEET_SHOT=<dir> writes <sheet>.png of the sheet window with screencapture (works in the sandboxed shell). make -C frontend test-sheets runs all five sheets that way (12 checks, opens real windows for about 10 s); screenshots in docs/screenshots/applets-frontend/.

Verified here (Mac, audio off)

  • make -C frontend test (77 + 13 checks), make -C frontend test-sheets (12 checks, every sheet answered and its answer asserted, screenshots written), make -C runtime test test-services test-host all green; new checks in test_svc_applet_libs (sheet answers, cancel, scripted-over-sheet, error hook), test_svc_applet_album (script values, leave, selecting flag), test_svc_applet_web (script values, html root getter).
  • Not verified: a sheet raised by a running title (none of the four reference titles opens these applets in the e2e path); the sheets' behaviour over a fullscreen game window; gamepad navigation of the sheets (mouse / keyboard only).

Files

frontend/src/applet_sheets.m, frontend/include/napple_frontend.h, frontend/Makefile (WebKit link, test-sheets), frontend/tests/test_sheets.m, runtime/src/app.m, runtime/src/services/{applet.c, applet_lib_core., applet_ui.h, applet_web_core., applet_album_core.c}, three runtime tests.