Phase F: restore the doc-19 bounce (footprint chooser dead-app) + regression spec
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Td4ujboGuAw26jvbDQzehj
This commit is contained in:
parent
22fcb766e7
commit
80199f42f4
11 changed files with 274 additions and 3 deletions
|
|
@ -60,6 +60,7 @@
|
|||
#include <pcbjam_remote_lock.h>
|
||||
#include "collab_common.h"
|
||||
#include "open_gate.h"
|
||||
#include "main_stack_runner.h"
|
||||
#include "collab_presence_core.h"
|
||||
#include "collab_presence_style.h"
|
||||
#include "pcbjam_theme.h"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <wx/app.h>
|
||||
#include <wx/string.h>
|
||||
#include "open_gate.h"
|
||||
#include "main_stack_runner.h"
|
||||
|
||||
using namespace emscripten;
|
||||
using json = nlohmann::json;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "pcbjam_libs_reload.h"
|
||||
#include "open_gate.h"
|
||||
#include "main_stack_runner.h"
|
||||
#include "timer_park.h"
|
||||
#include "fiber_park.h"
|
||||
|
||||
|
|
|
|||
86
wasm/bindings/main_stack_runner.h
Normal file
86
wasm/bindings/main_stack_runner.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Main-stack runner: the KiCad half of wx's nested-loop bounce
|
||||
* (pcbjam docs/features/async/19, 20 D3).
|
||||
*
|
||||
* A quasi-modal's nested event loop parks its whole stack for the dialog's
|
||||
* lifetime. When that stack is a TOOL coroutine's, the park suspends the
|
||||
* fiber's body where the fiber layer cannot see it: the stale-fiber guard
|
||||
* quarantines the fiber, then REFUSES its own resume, and the dialog stops
|
||||
* responding to clicks (only the titlebar x still works, because that path is
|
||||
* ungated). That is the Symbol Properties hang.
|
||||
*
|
||||
* wx detects "this nested loop is about to park on a non-main stack" — it can,
|
||||
* cheaply and exactly, by comparing a frame address against
|
||||
* emscripten_stack_get_base()/end() — but it must not know what a coroutine
|
||||
* is. So it calls this runner, and KiCad's TOOL_MANAGER moves the loop onto
|
||||
* the main stack via its own RunMainStack mechanism, which suspends the
|
||||
* coroutine the legitimate way: a fiber swap the layer records
|
||||
* (swap_suspended = true), so no quarantine, no refused resume.
|
||||
*
|
||||
* This lives in pcbjam's binding layer rather than in KiCad or wx precisely
|
||||
* because it is the only place that may know about both.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <wx/app.h>
|
||||
|
||||
#include <eda_base_frame.h>
|
||||
#include <tool/tool_manager.h>
|
||||
|
||||
#include <wx/wasm/private/mainstack.h>
|
||||
|
||||
namespace pcbjam_main_stack
|
||||
{
|
||||
|
||||
/**
|
||||
* Run aFunc on the main stack if a tool coroutine is currently active.
|
||||
*
|
||||
* Returns 1 when the body has been run (bounced, or run inline because there
|
||||
* was no coroutine to bounce off), 0 when there was nothing to run it with —
|
||||
* no frame or no tool manager — in which case wx parks in place exactly as it
|
||||
* did before this hook existed.
|
||||
*/
|
||||
inline int run_on_main_stack( void ( *aFunc )( void* ), void* aArg )
|
||||
{
|
||||
if( !wxTheApp )
|
||||
return 0;
|
||||
|
||||
auto* frame = dynamic_cast<EDA_BASE_FRAME*>( wxTheApp->GetTopWindow() );
|
||||
|
||||
if( !frame )
|
||||
return 0;
|
||||
|
||||
TOOL_MANAGER* toolMgr = frame->GetToolManager();
|
||||
|
||||
if( !toolMgr )
|
||||
return 0;
|
||||
|
||||
// RunOnMainStackIfActiveTool runs the body inline when no coroutine is
|
||||
// running. Either way the body HAS run, so report it as handled — letting
|
||||
// wx fall through would run the nested loop a second time.
|
||||
bool ran = false;
|
||||
|
||||
toolMgr->RunOnMainStackIfActiveTool(
|
||||
[aFunc, aArg, &ran]()
|
||||
{
|
||||
ran = true;
|
||||
aFunc( aArg );
|
||||
} );
|
||||
|
||||
return ran ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs at static-init time. Only stores a function pointer, so it is safe
|
||||
* before wx exists; every lookup above happens lazily per call, since frames
|
||||
* come and go. Included by more than one binding TU — setting the same pointer
|
||||
* twice is idempotent.
|
||||
*/
|
||||
struct INSTALLER
|
||||
{
|
||||
INSTALLER() { wxWasmSetMainStackRunner( &run_on_main_stack ); }
|
||||
};
|
||||
|
||||
inline INSTALLER g_installer;
|
||||
|
||||
} // namespace pcbjam_main_stack
|
||||
|
|
@ -53,6 +53,7 @@
|
|||
#include "collab_common.h"
|
||||
#include "collab_presence_core.h"
|
||||
#include "open_gate.h"
|
||||
#include "main_stack_runner.h"
|
||||
#include "timer_park.h"
|
||||
#include "fiber_park.h"
|
||||
#include "collab_presence_style.h"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <wx/window.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "open_gate.h"
|
||||
#include "main_stack_runner.h"
|
||||
#include <eda_draw_frame.h>
|
||||
#include <kiid.h>
|
||||
#include <pcbjam_read_only.h>
|
||||
|
|
|
|||
Loading…
Reference in a new issue