new_editor: filter closing windows from interaction

This commit is contained in:
2026-04-17 22:35:16 +08:00
parent ba8437d919
commit bf9a906464
3 changed files with 49 additions and 13 deletions

View File

@@ -57,6 +57,7 @@
- 已补 live window-set 构造时对 destroyed/no-`HWND` 窗口的过滤,避免 `primary/activeWindowId` 指向不存在的运行时窗口
- 已补 window-sync 失败时的已有窗口/新建窗口回滚,避免同步中途失败留下半更新窗口集
- 已补 closing-window 过滤,避免已发出 `WM_CLOSE` 但尚未销毁的 detached window 继续参与 live window-set 与命中测试
- 已补 closing-window 对 render/transfer/global-tab-drag 的排除,并在主窗口级联关闭 detached windows 前先标记 `closing`
9. integration 测试构建模板已继续收口:
- 已把 `tests/UI/Editor/integration` 叶子目标收敛到 shared helper
@@ -556,6 +557,7 @@
- 已完成 detached window 起始 global-tab-drag 的源请求校验
- 已完成 live window-set 对 destroyed/no-`HWND` 窗口的 primary/active 过滤
- 已完成 window-sync 失败回滚与 closing-window 过滤
- 已完成 closing-window 在 render/transfer/global-tab-drag 路径上的排除
- `transfer/session/state` 主链路已基本收口,剩余更多属于后续演进项而非当前主线阻塞
### 涉及范围

View File

@@ -276,7 +276,9 @@ void EditorWindowHostRuntime::RenderAllWindows(
transferBatches.reserve(m_windows.size());
for (const std::unique_ptr<EditorWindow>& window : m_windows) {
if (window == nullptr || window->GetHwnd() == nullptr) {
if (window == nullptr ||
window->GetHwnd() == nullptr ||
window->IsClosing()) {
continue;
}
@@ -293,7 +295,9 @@ void EditorWindowHostRuntime::RenderAllWindows(
}
for (WindowFrameTransferBatch& batch : transferBatches) {
if (batch.sourceWindow == nullptr || batch.sourceWindow->GetHwnd() == nullptr) {
if (batch.sourceWindow == nullptr ||
batch.sourceWindow->GetHwnd() == nullptr ||
batch.sourceWindow->IsClosing()) {
continue;
}
@@ -310,7 +314,9 @@ void EditorWindowHostRuntime::HandleDestroyedWindow(HWND hwnd) {
for (const std::unique_ptr<EditorWindow>& otherWindow : m_windows) {
if (otherWindow != nullptr &&
otherWindow.get() != window &&
otherWindow->GetHwnd() != nullptr) {
otherWindow->GetHwnd() != nullptr &&
!otherWindow->IsClosing()) {
otherWindow->MarkClosing();
PostMessageW(otherWindow->GetHwnd(), WM_CLOSE, 0, 0);
}
}

View File

@@ -68,6 +68,12 @@ bool CanStartGlobalTabDragFromWindow(
extractedPanel);
}
bool IsLiveInteractiveWindow(const EditorWindow* window) {
return window != nullptr &&
window->GetHwnd() != nullptr &&
!window->IsClosing();
}
std::size_t ResolveDropInsertionIndex(
const Widgets::UIEditorDockHostTabStackLayout& tabStack,
const UIPoint& point) {
@@ -240,7 +246,7 @@ void EditorWindowWorkspaceCoordinator::UpdateGlobalTabDragOwnerWindowPosition()
}
EditorWindow* ownerWindow = m_hostRuntime.FindWindow(m_globalTabDragSession.panelWindowId);
if (ownerWindow == nullptr || ownerWindow->GetHwnd() == nullptr) {
if (!IsLiveInteractiveWindow(ownerWindow)) {
return;
}
@@ -273,7 +279,7 @@ void EditorWindowWorkspaceCoordinator::ClearGlobalTabDragDropPreview() {
}
if (EditorWindow* previewWindow = m_hostRuntime.FindWindow(m_globalTabDragSession.previewWindowId);
previewWindow != nullptr) {
IsLiveInteractiveWindow(previewWindow)) {
previewWindow->ClearExternalDockHostDropPreview();
previewWindow->InvalidateHostWindow();
}
@@ -288,7 +294,7 @@ void EditorWindowWorkspaceCoordinator::UpdateGlobalTabDragDropPreview() {
EditorWindow* targetWindow = FindTopmostWindowAtScreenPoint(
m_globalTabDragSession.screenPoint,
m_globalTabDragSession.panelWindowId);
if (targetWindow == nullptr || targetWindow->GetHwnd() == nullptr) {
if (!IsLiveInteractiveWindow(targetWindow)) {
ClearGlobalTabDragDropPreview();
return;
}
@@ -333,7 +339,9 @@ void EditorWindowWorkspaceCoordinator::EndGlobalTabDragSession() {
if (GetCapture() == ownerWindow->GetHwnd()) {
ReleaseCapture();
}
ownerWindow->ResetInteractionState();
if (!ownerWindow->IsClosing()) {
ownerWindow->ResetInteractionState();
}
}
m_globalTabDragSession = {};
@@ -345,7 +353,11 @@ bool EditorWindowWorkspaceCoordinator::HandleGlobalTabDragPointerMove(HWND hwnd)
}
const EditorWindow* ownerWindow = m_hostRuntime.FindWindow(m_globalTabDragSession.panelWindowId);
if (ownerWindow == nullptr || ownerWindow->GetHwnd() != hwnd) {
if (!IsLiveInteractiveWindow(ownerWindow)) {
EndGlobalTabDragSession();
return false;
}
if (ownerWindow->GetHwnd() != hwnd) {
return false;
}
@@ -364,7 +376,11 @@ bool EditorWindowWorkspaceCoordinator::HandleGlobalTabDragPointerButtonUp(HWND h
}
const EditorWindow* ownerWindow = m_hostRuntime.FindWindow(m_globalTabDragSession.panelWindowId);
if (ownerWindow == nullptr || ownerWindow->GetHwnd() != hwnd) {
if (!IsLiveInteractiveWindow(ownerWindow)) {
EndGlobalTabDragSession();
return false;
}
if (ownerWindow->GetHwnd() != hwnd) {
return false;
}
@@ -377,7 +393,7 @@ bool EditorWindowWorkspaceCoordinator::HandleGlobalTabDragPointerButtonUp(HWND h
EndGlobalTabDragSession();
EditorWindow* targetWindow = FindTopmostWindowAtScreenPoint(screenPoint, panelWindowId);
if (targetWindow == nullptr || targetWindow->GetHwnd() == nullptr) {
if (!IsLiveInteractiveWindow(targetWindow)) {
return true;
}
@@ -423,7 +439,8 @@ bool EditorWindowWorkspaceCoordinator::HandleGlobalTabDragPointerButtonUp(HWND h
if (EditorWindow* updatedTargetWindow = m_hostRuntime.FindWindow(targetWindow->GetWindowId());
updatedTargetWindow != nullptr &&
updatedTargetWindow->GetHwnd() != nullptr) {
updatedTargetWindow->GetHwnd() != nullptr &&
!updatedTargetWindow->IsClosing()) {
SetForegroundWindow(updatedTargetWindow->GetHwnd());
}
LogRuntimeTrace(
@@ -436,6 +453,11 @@ bool EditorWindowWorkspaceCoordinator::HandleGlobalTabDragPointerButtonUp(HWND h
bool EditorWindowWorkspaceCoordinator::TryStartGlobalTabDrag(
EditorWindow& sourceWindow,
const EditorWindowPanelTransferRequest& request) {
if (sourceWindow.IsClosing()) {
LogRuntimeTrace("drag", "failed to start global tab drag: source window is closing");
return false;
}
POINT dragHotspot = BuildFallbackGlobalTabDragHotspot();
TryResolveGlobalTabDragHotspot(
sourceWindow,
@@ -468,7 +490,7 @@ bool EditorWindowWorkspaceCoordinator::TryStartGlobalTabDrag(
}
EditorWindow* detachedWindow = m_hostRuntime.FindWindow(result.targetWindowId);
if (detachedWindow == nullptr || detachedWindow->GetHwnd() == nullptr) {
if (!IsLiveInteractiveWindow(detachedWindow)) {
LogRuntimeTrace("drag", "detached drag window was not created.");
return false;
}
@@ -518,6 +540,11 @@ bool EditorWindowWorkspaceCoordinator::TryStartGlobalTabDrag(
bool EditorWindowWorkspaceCoordinator::TryProcessDetachRequest(
EditorWindow& sourceWindow,
const EditorWindowPanelTransferRequest& request) {
if (sourceWindow.IsClosing()) {
LogRuntimeTrace("detach", "detach request rejected: source window is closing");
return false;
}
const std::string sourceWindowId(sourceWindow.GetWindowId());
UIEditorWindowWorkspaceController windowWorkspaceController =
BuildLiveWindowWorkspaceController(sourceWindowId);
@@ -541,7 +568,8 @@ bool EditorWindowWorkspaceCoordinator::TryProcessDetachRequest(
if (EditorWindow* detachedWindow = m_hostRuntime.FindWindow(result.targetWindowId);
detachedWindow != nullptr &&
detachedWindow->GetHwnd() != nullptr) {
detachedWindow->GetHwnd() != nullptr &&
!detachedWindow->IsClosing()) {
SetForegroundWindow(detachedWindow->GetHwnd());
}