The runtime is JSPI-only; this removes everything that still pretended otherwise. Three exhaustive sweeps (C++/JS+build+CI/tests+docs) drove the inventory; every deletion verified by grep closure + full gates. Broken-right-now fixes: - deploy-staging.yml passed the retired opt_level input — the workflow could not even start. Removed. - env.sh carried dead exports with a live -sASYNCIFY=1 inside (WASM_LDFLAGS/PTHREAD_LDFLAGS, zero consumers). Removed; the WASM_LEGACY_EXCEPTIONS rationale rewritten to the real reason. - docker/build.sh exported PCBJAM_ASYNC_BACKEND (read nowhere). Gone. Dead weight removed: - binaryen submodule (nothing builds or invokes it), wasm-opt-bench workflow + scripts/bench/, get-wasm-opt.sh, diagnostics.js (242 lines of Asyncify-API-only code), the KICAD_PIPELINE background-postprocess scaffolding (existed to parallelize the deleted wasm-opt phase; the postprocess is a seconds-long node script and now runs inline), build-monitor's dead asyncify rows, sched-context orphan build output, dead .gitignore entries, the .jspi-assets spike dir (the two wf-result research JSONs moved to docs/features/async/migration-evidence/). - bindings: fiber_park.h + its 12 embind registrations (broken-if- called under JSPI), the kicadOpenFileStart/OPEN_JOB starter route, main_stack_runner.h + 5 includes, the always-null context-sleep weak hook in nanosleep_yield.c. - shim: the backend field (installed-flag idempotency instead), noteContextWait (dead both sides), the __wxAsyncifyDump alias (+ the WasmTool fallback and string-dump normalize branch). - web: the emscripten-6-ignored mainScriptUrlOrBlob option in boot.ts (gerber-demo keeps it: it loads the deployed CDN release, which predates emscripten 6 — noted inline). Conditionals: all 'backend === jspi' checks reduced to scheduler- presence checks; races_quiescent re-keyed from Asyncify.state (vacuous) to real backlog quiescence (resumeReady/mutatorQueue — NOT _windowLive, which is the probing activation's own window by definition). Renames (identifiers only, no file renames): ASYNC_LINK_FLAGS→ JSPI_LINK_FLAGS and Makefile ASYNC_LDFLAGS→JSPI_LDFLAGS, kicadCollabFiberBusy→kicadCollabBusy (embind + web + tests), collab_common.h fiber*→apply*/coroutine naming, asyncifySignatures→ wasmTrapSignatures (lists byte-identical). Tests: the two remaining vacuous [wx-asyncify]/fiber-resume-refused asserts re-keyed to live JSPI beacons; eeschema-load's failure message no longer sends the developer to a deleted script; wait-beacons' dead families/parser deleted; lane-0 legacy-glue guards removed (lane 0 is unconstructible); the embind test.fail re-gated with the JSPI reason (plain embind invokers cannot suspend — verified still failing); lint-determinism now scans tests/jspi (166 files clean); eeschema-collab local-move gated to chromium (~50% flaky on FF even solo; pcbnew twin covers both engines). Docs: DEBUG.md rewritten as the JSPI debugging guide; build.md describes the single-phase build; docs/features/async/README.md banner-marked historical and repointed at the NEW 23-jspi-runtime.md (current architecture: export census, turnstile, libcontext ownership + refusal contract, embind call shapes, the em-pthread service-wrapper trick, exception policy, known gaps). Gates on the cleaned tree: test:e2e 725 passed / 0 failed (after the quiescence-probe fix; the 3 other reds were verified contention flakes solo-green or the documented FF gate), web 76/0, jspi 18/18 both engines, vitest 295/295 + 17/17, all lints green, live-app census clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
130 lines
5.4 KiB
C++
130 lines
5.4 KiB
C++
/*
|
|
* Live color-theme switch (comments-ux 0002 F4): kicadSetColorTheme(name)
|
|
* re-points the frame's app settings `color_theme` and drives the frame's own
|
|
* CommonSettingsChanged — the exact path the desktop Preferences dialog uses
|
|
* to hot-apply a theme (SCH_BASE_FRAME / PCB_BASE_FRAME reload COLOR_SETTINGS
|
|
* into the painter, recache the view, refresh). SETTINGS_MANAGER resolves
|
|
* colors/<name>.json from the MEMFS config dir on demand, so the JSON only
|
|
* has to exist (standalone boot seeding writes it — web/standalone
|
|
* src/wasm/boot.ts). The changed app settings are saved back to MEMFS so a
|
|
* same-session relaunch (warm pool) comes up already themed.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
#include <eda_draw_frame.h>
|
|
#include <pgm_base.h>
|
|
#include <settings/app_settings.h>
|
|
#include <settings/settings_manager.h>
|
|
#include <string>
|
|
#include <wx/event.h>
|
|
#include <wx/window.h>
|
|
|
|
#include "collab_common.h"
|
|
|
|
// wx wasm port chrome appearance (wxwidgets src/wasm/settings.cpp): the
|
|
// system-colour table every widget paints from.
|
|
extern "C" void wxWasmSetDarkAppearance( bool dark );
|
|
extern "C" bool wxWasmGetDarkAppearance();
|
|
|
|
namespace pcbjam_theme {
|
|
|
|
/** Merged-image hook (installed by kicad_editor_embind.cpp): re-assert the
|
|
* canvas-only chrome state after a theme apply. CommonSettingsChanged
|
|
* recreates the menubar (CallAfter-deferred, eda_base_frame.cpp) and the
|
|
* toolbars, and they come back SHOWN — without this, a theme apply
|
|
* resurrects the chrome kicadSetChrome(false) hid (read-only viewer /
|
|
* mobile canvas-only). Inline variable: the dispatcher TU re-declares the
|
|
* identical definition instead of including this (deliberately
|
|
* header-light) — keep the two in sync. Null in the standalone bundles,
|
|
* which have no chrome API. */
|
|
inline void ( *g_afterThemeApplied )() = nullptr;
|
|
|
|
/** Set the chrome appearance FLAG only — no widget traffic, no coroutine. Safe
|
|
* from the browser main thread at any point (it writes one bool in shared
|
|
* wasm memory); the embedder calls it at onRuntimeInitialized, BEFORE main()
|
|
* spawns on the KiCad pthread, so the first widget paint is already themed.
|
|
* (Module.ENV proved unreliable for this: the pthread builds its environ
|
|
* from its own worker's ENV, not the main runtime's.) */
|
|
inline void setDarkChromeFlag( bool aDark )
|
|
{
|
|
wxWasmSetDarkAppearance( aDark );
|
|
}
|
|
|
|
/** Flip the wx CHROME (panels/toolbars/dialogs — the system-colour table) and
|
|
* broadcast the change so every live window repaints:
|
|
* wxWindowBase::OnSysColourChanged recurses to children, and
|
|
* EDA_BASE_FRAME's handler additionally re-themes icons and rebuilds
|
|
* toolbars/menubar. No-op when the appearance didn't change (the merged
|
|
* image calls the theme entry once per editor). No DOM probing here — this
|
|
* runs on the KiCad pthread, which has no `document`. */
|
|
inline void syncChromeAppearance( bool aDark )
|
|
{
|
|
if( aDark == wxWasmGetDarkAppearance() )
|
|
return;
|
|
|
|
wxWasmSetDarkAppearance( aDark );
|
|
|
|
for( wxWindowList::const_iterator it = wxTopLevelWindows.begin();
|
|
it != wxTopLevelWindows.end(); ++it )
|
|
{
|
|
wxWindow* tlw = *it;
|
|
wxSysColourChangedEvent evt;
|
|
evt.SetEventObject( tlw );
|
|
tlw->GetEventHandler()->ProcessEvent( evt );
|
|
tlw->Refresh();
|
|
}
|
|
}
|
|
|
|
/** Apply `aTheme` ("pcbjam-dark", "_builtin_default", …) to one frame. Runs
|
|
* on the apply coroutine: CommonSettingsChanged reaches tool/view internals
|
|
* that must not run from a bare JS callback. Null frame no-ops (the merged
|
|
* dispatcher calls every editor, open or not). */
|
|
inline void setColorTheme( EDA_DRAW_FRAME* aFrame, const std::string& aTheme )
|
|
{
|
|
if( !aFrame )
|
|
return;
|
|
|
|
pcbjam_collab::runOnCoroutine( aFrame, [aFrame, aTheme]() {
|
|
// The shell only ever sends our dark theme name or the builtin
|
|
// default, so the chrome appearance rides on that distinction.
|
|
const bool dark = aTheme != "_builtin_default";
|
|
const wxString theme = wxString::FromUTF8( aTheme.c_str() );
|
|
APP_SETTINGS_BASE* cfg = aFrame->config();
|
|
|
|
// The shell re-sends its theme on EVERY boot (a warm relaunch can
|
|
// have stale MEMFS settings from a HomePage theme switch) — skip the
|
|
// apply when nothing changes: CommonSettingsChanged below is not
|
|
// free, it rebuilds the menubar and toolbars.
|
|
if( cfg && cfg->m_ColorTheme == theme && dark == wxWasmGetDarkAppearance() )
|
|
return;
|
|
|
|
if( cfg )
|
|
{
|
|
cfg->m_ColorTheme = theme;
|
|
// Persist now — wasm sessions never exit cleanly, so the normal
|
|
// save-on-close path would lose the choice.
|
|
Pgm().GetSettingsManager().Save( cfg );
|
|
}
|
|
|
|
// wx chrome first (panels/toolbars), then the GAL canvas colors.
|
|
syncChromeAppearance( dark );
|
|
|
|
// 0 flags: no env/text vars changed; the frame's override chain still
|
|
// unconditionally reloads colors and recaches the view.
|
|
aFrame->CommonSettingsChanged( 0 );
|
|
|
|
// Queued from INSIDE the coroutine body, AFTER CommonSettingsChanged: the
|
|
// menubar rebuild it triggers is itself a CallAfter on this same
|
|
// handler, so FIFO puts the re-assert behind the rebuilt (shown)
|
|
// menubar.
|
|
if( void ( *hook )() = g_afterThemeApplied )
|
|
aFrame->CallAfter( hook );
|
|
} );
|
|
}
|
|
|
|
} // namespace pcbjam_theme
|
|
|
|
#endif // __EMSCRIPTEN__
|