From 4a42b757c78a58a9209adc2cef0a9748a0e42b17 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 22 Apr 2026 13:03:28 +0800 Subject: [PATCH] docs(new_editor): plan frame lifecycle runtime refactor --- ...LifecycleRuntimeRefactorPlan_2026-04-22.md | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 docs/plan/NewEditor_FrameLifecycleRuntimeRefactorPlan_2026-04-22.md diff --git a/docs/plan/NewEditor_FrameLifecycleRuntimeRefactorPlan_2026-04-22.md b/docs/plan/NewEditor_FrameLifecycleRuntimeRefactorPlan_2026-04-22.md new file mode 100644 index 00000000..aa0ea29b --- /dev/null +++ b/docs/plan/NewEditor_FrameLifecycleRuntimeRefactorPlan_2026-04-22.md @@ -0,0 +1,251 @@ +# NewEditor Frame/Lifecycle Runtime Refactor Plan + +Date: 2026-04-22 + +## 1. Objective + +This plan targets the highest-priority remaining architecture debt in `new_editor`: + +1. frame execution still has multiple live owners +2. window destruction still has multiple live owners +3. `EditorShellRuntime` is still a per-frame god-object + +The goal is not to split files mechanically. +The goal is to collapse ownership so that: + +1. only one module can drive a frame +2. only one module can finalize window death +3. `EditorShellRuntime` becomes a thin facade over explicit per-frame stages + +## 2. Confirmed Root Issues + +### 2.1 Frame scheduling is not single-owner + +`RenderFrame()` is currently called from: + +- main host render loop +- `WM_PAINT` +- `WM_SIZE` +- `WM_DPICHANGED` +- `WM_EXITSIZEMOVE` +- borderless chrome transition logic + +This means rendering is still driven by both: + +1. the normal frame loop +2. synchronous Win32 message-side side effects + +As long as this remains true, frame timing, transfer request ordering, and present timing +will keep depending on which path happened to trigger first. + +### 2.2 Window lifetime is not single-owner + +`Shutdown()`, `DestroyWindow(...)`, `MarkDestroyed()`, and host erase currently happen from +multiple places in `WindowManager`, host runtime, and workspace coordination. + +This means there is still no single authoritative answer to: + +1. who requests close +2. who observes native window destruction +3. who shuts runtime down +4. who removes the managed window from the host container + +This is the same root class of problem that previously caused sub-window close regressions. + +### 2.3 EditorShellRuntime still owns too many per-frame responsibilities + +`EditorShellRuntime::Update(...)` still performs, in one place: + +1. shell definition build +2. workspace/session sync +3. dock host interaction update +4. viewport request/update +5. hosted panel input routing +6. hosted panel update +7. status/trace/command-focus synchronization + +That makes the runtime difficult to reason about and causes unrelated per-frame concerns to +stay tightly coupled. + +## 3. Target End State + +After this refactor: + +1. only one frame driver can execute `BeginFrame -> UpdateAndAppend -> Present` +2. Win32 message dispatch only records frame requests / dirty reasons, never renders directly +3. borderless chrome logic can request a new frame, but cannot render directly +4. only one lifecycle coordinator can finalize managed window destruction +5. `WorkspaceCoordinator` can request a window-set mutation, but cannot directly destroy windows +6. `EditorShellRuntime` becomes a thin composition facade over smaller stage modules + +## 4. New Modules + +### 4.1 Frame ownership + +Add: + +- `new_editor/app/Platform/Win32/EditorWindowFrameDriver.h` +- `new_editor/app/Platform/Win32/EditorWindowFrameDriver.cpp` +- `new_editor/app/Platform/Win32/EditorWindowFrameRequest.h` + +Responsibilities: + +- own the only live path that executes a frame +- consume frame request reasons / dirty state +- normalize when transfer requests are collected and applied + +### 4.2 Lifecycle ownership + +Add: + +- `new_editor/app/Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h` +- `new_editor/app/Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.cpp` + +Responsibilities: + +- own close request state +- own runtime shutdown sequencing +- own native destroy finalization and managed erase +- own primary-window cascade behavior + +### 4.3 Shell runtime stage split + +Add: + +- `new_editor/app/Composition/EditorShellSessionCoordinator.h` +- `new_editor/app/Composition/EditorShellSessionCoordinator.cpp` +- `new_editor/app/Composition/EditorShellInteractionEngine.h` +- `new_editor/app/Composition/EditorShellInteractionEngine.cpp` +- `new_editor/app/Composition/EditorShellHostedPanelCoordinator.h` +- `new_editor/app/Composition/EditorShellHostedPanelCoordinator.cpp` +- `new_editor/app/Composition/EditorShellDrawComposer.h` +- `new_editor/app/Composition/EditorShellDrawComposer.cpp` + +Responsibilities: + +- `SessionCoordinator`: context/workspace/session/command-focus/status synchronization +- `InteractionEngine`: shell definition, dock host interaction, shell frame/state update +- `HostedPanelCoordinator`: hosted panel input filtering, panel update, panel capture ownership +- `DrawComposer`: shell draw packets, panel draw packets, viewport frame application to draw data + +## 5. Refactor Strategy + +### Phase A. Collapse frame execution to one driver + +Refactor current flow so that: + +1. `EditorWindowHostRuntime` requests frame execution through `EditorWindowFrameDriver` +2. `EditorWindowMessageDispatcher` no longer calls `RenderFrame(...)` directly +3. `EditorWindowChromeController` no longer calls `RenderFrame(...)` directly +4. `EditorWindow` no longer exposes uncontrolled render entrypoints to unrelated callers + +Message-side behavior must become: + +- mark dirty +- enqueue reason +- invalidate host window when needed + +But never: + +- begin a frame +- build draw data +- present directly + +### Phase B. Collapse lifecycle to one owner + +Refactor current flow so that: + +1. `WM_CLOSE` only means `RequestClose` +2. `WM_DESTROY` only reports native death +3. `EditorWindowLifecycleCoordinator` becomes the only place that can: + - call `Shutdown()` + - finalize managed destruction + - erase the managed window from host storage + - cascade close from the primary window +4. `WorkspaceCoordinator` stops duplicating host destroy logic + +### Phase C. Split EditorShellRuntime by stage, not by helper dumping + +Do not split by random utility extraction. +Split by stage ownership: + +1. session sync stage +2. shell interaction stage +3. hosted panel stage +4. draw composition stage + +`EditorShellRuntime` should remain as a thin orchestrating facade that wires these stages +together in a stable order. + +### Phase D. Normalize panel capture ownership + +As part of hosted panel coordination: + +1. stop hardcoding panel capture checks directly in the runtime facade where possible +2. centralize panel capture ownership through one hosted-panel coordination boundary +3. make it explicit which hosted panels participate in pointer-stream ownership decisions + +## 6. File-Level Impact + +### 6.1 Existing files to shrink / re-scope + +- `new_editor/app/Platform/Win32/EditorWindow.cpp` +- `new_editor/app/Platform/Win32/EditorWindow.h` +- `new_editor/app/Platform/Win32/EditorWindowChromeController.cpp` +- `new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp` +- `new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.h` +- `new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp` +- `new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp` +- `new_editor/app/Composition/EditorShellRuntime.cpp` +- `new_editor/app/Composition/EditorShellRuntime.h` + +### 6.2 Build graph + +Update: + +- `new_editor/CMakeLists.txt` + +to register the new frame/lifecycle/runtime stage units. + +## 7. Validation + +### 7.1 Structural validation + +After completion: + +1. direct `RenderFrame(...)` call sites outside the frame driver must be gone +2. duplicate `Shutdown()/DestroyWindow()/MarkDestroyed()/erase` chains must be gone +3. `WorkspaceCoordinator` must no longer perform raw window destruction +4. `EditorShellRuntime` facade must delegate to explicit stage modules + +### 7.2 Runtime validation + +Must validate: + +1. editor starts normally +2. main window continues rendering normally +3. resize / maximize / drag-restore no longer perform direct message-side rendering +4. detached panel windows and tool windows still open/close correctly +5. closing child windows does not close the main window +6. closing the primary window still cascades correctly +7. frame transfer requests still behave correctly during docking / detach workflows + +## 8. Execution Order + +1. introduce frame request model and frame driver +2. remove message-side and chrome-side direct rendering +3. introduce lifecycle coordinator +4. remove duplicate destroy/shutdown ownership from host runtime and workspace coordinator +5. split `EditorShellRuntime` into session/interaction/panel/draw stages +6. rebuild and smoke-test +7. perform structural grep validation + +## 9. Success Criteria + +This refactor is complete only if all of the following are true: + +1. `new_editor` frame execution has a single live owner +2. `new_editor` managed window destruction has a single live owner +3. `EditorShellRuntime` is no longer a monolithic per-frame god-object +4. resize / dpi / chrome transitions no longer trigger direct rendering from message handlers +5. build and smoke validation both pass