refactor(new_editor): centralize window lifecycle ownership
This commit is contained in:
@@ -275,6 +275,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
||||
app/Platform/Win32/EditorWindowRuntimeController.cpp
|
||||
app/Platform/Win32/Win32SystemInteractionHost.cpp
|
||||
app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp
|
||||
app/Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.cpp
|
||||
app/Platform/Win32/WindowManager/EditorWindowManager.cpp
|
||||
app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp
|
||||
app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp
|
||||
|
||||
@@ -66,6 +66,7 @@ class EditorWindowFrameDriver;
|
||||
class EditorWindowFrameOrchestrator;
|
||||
class EditorWindowHostRuntime;
|
||||
class EditorWindowInputController;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
class EditorWindowMessageDispatcher;
|
||||
class EditorWindowRuntimeController;
|
||||
class EditorWindowWorkspaceCoordinator;
|
||||
@@ -100,6 +101,7 @@ private:
|
||||
friend class EditorWindowFrameDriver;
|
||||
friend class EditorWindowHostRuntime;
|
||||
friend class EditorWindowMessageDispatcher;
|
||||
friend class EditorWindowLifecycleCoordinator;
|
||||
friend class EditorWindowWorkspaceCoordinator;
|
||||
|
||||
bool IsRenderReady() const;
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace XCEngine::UI::Editor::App {
|
||||
class EditorContext;
|
||||
class EditorWindow;
|
||||
class EditorWindowHostRuntime;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
class EditorWindowWorkspaceCoordinator;
|
||||
struct EditorWindowPanelTransferRequest;
|
||||
struct EditorWindowFrameTransferRequests;
|
||||
@@ -89,6 +90,7 @@ public:
|
||||
|
||||
private:
|
||||
std::unique_ptr<EditorWindowHostRuntime> m_hostRuntime = {};
|
||||
std::unique_ptr<EditorWindowLifecycleCoordinator> m_lifecycleCoordinator = {};
|
||||
std::unique_ptr<EditorWindowWorkspaceCoordinator> m_workspaceCoordinator = {};
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Composition/EditorContext.h"
|
||||
#include "Platform/Win32/EditorWindow.h"
|
||||
#include "Platform/Win32/EditorWindowFrameDriver.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||
@@ -109,8 +110,7 @@ EditorWindow* EditorWindowHostRuntime::CreateEditorWindow(
|
||||
|
||||
auto failWindowInitialization = [&](std::string_view message) {
|
||||
LogRuntimeTrace("window", std::string(message));
|
||||
DestroyEditorWindow(*rawWindow);
|
||||
eraseRawWindow();
|
||||
m_lifecycleCoordinator->AbortUnregisteredWindow(*rawWindow);
|
||||
return static_cast<EditorWindow*>(nullptr);
|
||||
};
|
||||
|
||||
@@ -150,72 +150,21 @@ EditorWindow* EditorWindowHostRuntime::CreateEditorWindow(
|
||||
return rawWindow;
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::BindLifecycleCoordinator(
|
||||
EditorWindowLifecycleCoordinator& lifecycleCoordinator) {
|
||||
m_lifecycleCoordinator = &lifecycleCoordinator;
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::HandlePendingNativeWindowCreated(HWND hwnd) {
|
||||
if (m_pendingCreateWindow != nullptr && !m_pendingCreateWindow->HasHwnd()) {
|
||||
m_pendingCreateWindow->AttachHwnd(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::Shutdown() {
|
||||
for (const std::unique_ptr<EditorWindow>& window : m_windows) {
|
||||
if (window != nullptr) {
|
||||
DestroyEditorWindow(*window);
|
||||
}
|
||||
}
|
||||
m_windows.clear();
|
||||
m_pendingCreateWindow = nullptr;
|
||||
}
|
||||
|
||||
bool EditorWindowHostRuntime::HasWindows() const {
|
||||
return !m_windows.empty();
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::DestroyEditorWindow(EditorWindow& window) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"DestroyEditorWindow begin windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(hwnd) +
|
||||
" primary=" + (window.IsPrimary() ? "1" : "0") +
|
||||
" closing=" + (window.IsClosing() ? "1" : "0") +
|
||||
" host=" + DescribeHostWindows(m_windows));
|
||||
window.ForceReleasePointerCapture();
|
||||
|
||||
window.Shutdown();
|
||||
if (hwnd != nullptr && IsWindow(hwnd)) {
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
window.MarkDestroyed();
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"DestroyEditorWindow end windowId='" + std::string(window.GetWindowId()) +
|
||||
"' host=" + DescribeHostWindows(m_windows));
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::DestroyClosedWindows() {
|
||||
for (auto it = m_windows.begin(); it != m_windows.end();) {
|
||||
EditorWindow* const window = it->get();
|
||||
if (window == nullptr || window->GetHwnd() != nullptr) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_pendingCreateWindow == window) {
|
||||
m_pendingCreateWindow = nullptr;
|
||||
}
|
||||
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"DestroyClosedWindows reap begin windowId='" + std::string(window->GetWindowId()) +
|
||||
"' hostBefore=" + DescribeHostWindows(m_windows));
|
||||
window->Shutdown();
|
||||
it = m_windows.erase(it);
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"DestroyClosedWindows reap end hostAfter=" + DescribeHostWindows(m_windows));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::RenderAllWindows(
|
||||
bool globalTabDragActive,
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator) {
|
||||
@@ -263,40 +212,6 @@ void EditorWindowHostRuntime::RenderAllWindows(
|
||||
}
|
||||
}
|
||||
|
||||
void EditorWindowHostRuntime::HandleDestroyedWindow(EditorWindow& window, bool destroyedPrimary) {
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"HandleDestroyedWindow begin windowId='" + std::string(window.GetWindowId()) +
|
||||
"' destroyedPrimary=" + (destroyedPrimary ? "1" : "0") +
|
||||
" hostBefore=" + DescribeHostWindows(m_windows));
|
||||
window.MarkDestroyed();
|
||||
if (!destroyedPrimary) {
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"HandleDestroyedWindow end windowId='" + std::string(window.GetWindowId()) +
|
||||
"' no primary cascade hostAfter=" + DescribeHostWindows(m_windows));
|
||||
return;
|
||||
}
|
||||
|
||||
for (const std::unique_ptr<EditorWindow>& otherWindow : m_windows) {
|
||||
if (otherWindow != nullptr &&
|
||||
otherWindow.get() != &window &&
|
||||
otherWindow->GetHwnd() != nullptr &&
|
||||
!otherWindow->IsClosing()) {
|
||||
otherWindow->MarkClosing();
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"HandleDestroyedWindow posting WM_CLOSE to windowId='" +
|
||||
std::string(otherWindow->GetWindowId()) + "'");
|
||||
PostMessageW(otherWindow->GetHwnd(), WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"HandleDestroyedWindow end windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hostAfter=" + DescribeHostWindows(m_windows));
|
||||
}
|
||||
|
||||
EditorWindow* EditorWindowHostRuntime::FindWindow(HWND hwnd) {
|
||||
if (hwnd == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorContext;
|
||||
class EditorWindow;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
class EditorWindowWorkspaceCoordinator;
|
||||
|
||||
class EditorWindowHostRuntime final {
|
||||
@@ -26,8 +27,8 @@ public:
|
||||
EditorWindow* CreateEditorWindow(
|
||||
UIEditorWorkspaceController workspaceController,
|
||||
const CreateParams& params);
|
||||
void BindLifecycleCoordinator(EditorWindowLifecycleCoordinator& lifecycleCoordinator);
|
||||
void HandlePendingNativeWindowCreated(HWND hwnd);
|
||||
void Shutdown();
|
||||
|
||||
EditorWindow* FindWindow(HWND hwnd);
|
||||
const EditorWindow* FindWindow(HWND hwnd) const;
|
||||
@@ -37,11 +38,9 @@ public:
|
||||
const EditorWindow* FindPrimaryWindow() const;
|
||||
|
||||
bool HasWindows() const;
|
||||
void DestroyClosedWindows();
|
||||
void RenderAllWindows(
|
||||
bool globalTabDragActive,
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator);
|
||||
void HandleDestroyedWindow(EditorWindow& window, bool destroyedPrimary);
|
||||
|
||||
EditorContext& GetEditorContext() {
|
||||
return m_editorContext;
|
||||
@@ -70,13 +69,14 @@ public:
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
||||
|
||||
private:
|
||||
void DestroyEditorWindow(EditorWindow& window);
|
||||
friend class EditorWindowLifecycleCoordinator;
|
||||
|
||||
EditorWindowHostConfig m_hostConfig = {};
|
||||
std::filesystem::path m_repoRoot = {};
|
||||
EditorContext& m_editorContext;
|
||||
std::vector<std::unique_ptr<EditorWindow>> m_windows = {};
|
||||
EditorWindow* m_pendingCreateWindow = nullptr;
|
||||
EditorWindowLifecycleCoordinator* m_lifecycleCoordinator = nullptr;
|
||||
};
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
#include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h"
|
||||
|
||||
#include "Platform/Win32/EditorWindow.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string DescribeHwnd(HWND hwnd) {
|
||||
std::ostringstream stream = {};
|
||||
stream << "0x" << std::hex << std::uppercase
|
||||
<< reinterpret_cast<std::uintptr_t>(hwnd);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string DescribeHostWindows(
|
||||
const std::vector<std::unique_ptr<EditorWindow>>& windows) {
|
||||
std::ostringstream stream = {};
|
||||
stream << "count=" << windows.size() << " [";
|
||||
bool first = true;
|
||||
for (const std::unique_ptr<EditorWindow>& window : windows) {
|
||||
if (!first) {
|
||||
stream << ", ";
|
||||
}
|
||||
first = false;
|
||||
if (window == nullptr) {
|
||||
stream << "<null>";
|
||||
continue;
|
||||
}
|
||||
|
||||
stream << window->GetWindowId()
|
||||
<< "{hwnd=" << DescribeHwnd(window->GetHwnd())
|
||||
<< ",primary=" << (window->IsPrimary() ? '1' : '0')
|
||||
<< ",closing=" << (window->IsClosing() ? '1' : '0')
|
||||
<< '}';
|
||||
}
|
||||
stream << ']';
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
EditorWindowLifecycleCoordinator::EditorWindowLifecycleCoordinator(
|
||||
EditorWindowHostRuntime& hostRuntime,
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator)
|
||||
: m_hostRuntime(hostRuntime),
|
||||
m_workspaceCoordinator(workspaceCoordinator) {}
|
||||
|
||||
EditorWindowLifecycleCoordinator::~EditorWindowLifecycleCoordinator() = default;
|
||||
|
||||
void EditorWindowLifecycleCoordinator::PostCloseRequest(EditorWindow& window) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (!window.IsClosing()) {
|
||||
window.MarkClosing();
|
||||
}
|
||||
|
||||
if (hwnd == nullptr || !IsWindow(hwnd)) {
|
||||
ShutdownRuntimeIfNeeded(window);
|
||||
window.MarkDestroyed();
|
||||
return;
|
||||
}
|
||||
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"PostCloseRequest windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(hwnd) +
|
||||
" primary=" + (window.IsPrimary() ? "1" : "0") +
|
||||
" host=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
PostMessageW(hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::ExecuteCloseRequest(EditorWindow& window) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"ExecuteCloseRequest begin windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(hwnd) +
|
||||
" primary=" + (window.IsPrimary() ? "1" : "0") +
|
||||
" closingBefore=" + (window.IsClosing() ? "1" : "0") +
|
||||
" workspace=" + m_workspaceCoordinator.DescribeWindowSet() +
|
||||
" host=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
|
||||
if (!window.IsClosing()) {
|
||||
window.MarkClosing();
|
||||
}
|
||||
|
||||
ShutdownRuntimeIfNeeded(window);
|
||||
|
||||
if (hwnd != nullptr && IsWindow(hwnd)) {
|
||||
DestroyWindow(hwnd);
|
||||
} else {
|
||||
window.MarkDestroyed();
|
||||
}
|
||||
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"ExecuteCloseRequest end windowId='" + std::string(window.GetWindowId()) +
|
||||
"' host=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::HandleNativeWindowDestroyed(EditorWindow& window) {
|
||||
const bool destroyedPrimary =
|
||||
m_workspaceCoordinator.IsPrimaryWindowId(window.GetWindowId());
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"HandleNativeWindowDestroyed begin windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(window.GetHwnd()) +
|
||||
" destroyedPrimary=" + (destroyedPrimary ? "1" : "0") +
|
||||
" localPrimary=" + (window.IsPrimary() ? "1" : "0") +
|
||||
" workspaceBefore=" + m_workspaceCoordinator.DescribeWindowSet() +
|
||||
" hostBefore=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
|
||||
if (m_workspaceCoordinator.OwnsActiveGlobalTabDrag(window.GetWindowId())) {
|
||||
m_workspaceCoordinator.EndGlobalTabDragSession();
|
||||
}
|
||||
|
||||
ShutdownRuntimeIfNeeded(window);
|
||||
m_workspaceCoordinator.RemoveWindowProjection(window.GetWindowId(), destroyedPrimary);
|
||||
window.MarkDestroyed();
|
||||
|
||||
if (destroyedPrimary) {
|
||||
std::vector<EditorWindow*> closeTargets = {};
|
||||
closeTargets.reserve(m_hostRuntime.GetWindows().size());
|
||||
for (const std::unique_ptr<EditorWindow>& otherWindow : m_hostRuntime.GetWindows()) {
|
||||
if (otherWindow == nullptr ||
|
||||
otherWindow.get() == &window ||
|
||||
otherWindow->GetHwnd() == nullptr ||
|
||||
otherWindow->IsClosing()) {
|
||||
continue;
|
||||
}
|
||||
closeTargets.push_back(otherWindow.get());
|
||||
}
|
||||
|
||||
for (EditorWindow* closeTarget : closeTargets) {
|
||||
if (closeTarget != nullptr) {
|
||||
PostCloseRequest(*closeTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"HandleNativeWindowDestroyed end windowId='" + std::string(window.GetWindowId()) +
|
||||
"' workspaceAfter=" + m_workspaceCoordinator.DescribeWindowSet() +
|
||||
" hostAfter=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::AbortUnregisteredWindow(EditorWindow& window) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"AbortUnregisteredWindow begin windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(hwnd) +
|
||||
" hostBefore=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
|
||||
if (!window.IsClosing()) {
|
||||
window.MarkClosing();
|
||||
}
|
||||
|
||||
ShutdownRuntimeIfNeeded(window);
|
||||
window.MarkDestroyed();
|
||||
if (hwnd != nullptr && IsWindow(hwnd)) {
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
EraseWindow(window);
|
||||
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"AbortUnregisteredWindow end windowId='" + std::string(window.GetWindowId()) +
|
||||
"' hostAfter=" + DescribeHostWindows(m_hostRuntime.GetWindows()));
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::ShutdownAllWindows() {
|
||||
std::vector<EditorWindow*> closeTargets = {};
|
||||
closeTargets.reserve(m_hostRuntime.GetWindows().size());
|
||||
for (const std::unique_ptr<EditorWindow>& window : m_hostRuntime.GetWindows()) {
|
||||
if (window != nullptr) {
|
||||
closeTargets.push_back(window.get());
|
||||
}
|
||||
}
|
||||
|
||||
for (EditorWindow* closeTarget : closeTargets) {
|
||||
if (closeTarget != nullptr) {
|
||||
ExecuteCloseRequest(*closeTarget);
|
||||
}
|
||||
}
|
||||
|
||||
ReapDestroyedWindows();
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::ReapDestroyedWindows() {
|
||||
auto& windows = m_hostRuntime.GetWindows();
|
||||
for (auto it = windows.begin(); it != windows.end();) {
|
||||
EditorWindow* const window = it->get();
|
||||
if (window == nullptr || window->GetHwnd() != nullptr) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_hostRuntime.m_pendingCreateWindow == window) {
|
||||
m_hostRuntime.m_pendingCreateWindow = nullptr;
|
||||
}
|
||||
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"ReapDestroyedWindows erase windowId='" + std::string(window->GetWindowId()) +
|
||||
"' hostBefore=" + DescribeHostWindows(windows));
|
||||
it = windows.erase(it);
|
||||
LogRuntimeTrace(
|
||||
"window-close",
|
||||
"ReapDestroyedWindows erase end hostAfter=" + DescribeHostWindows(windows));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::ShutdownRuntimeIfNeeded(EditorWindow& window) {
|
||||
if (window.IsRenderReady()) {
|
||||
window.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::EraseWindow(EditorWindow& window) {
|
||||
auto& windows = m_hostRuntime.GetWindows();
|
||||
const auto it = std::find_if(
|
||||
windows.begin(),
|
||||
windows.end(),
|
||||
[&window](const std::unique_ptr<EditorWindow>& candidate) {
|
||||
return candidate.get() == &window;
|
||||
});
|
||||
if (it == windows.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_hostRuntime.m_pendingCreateWindow == &window) {
|
||||
m_hostRuntime.m_pendingCreateWindow = nullptr;
|
||||
}
|
||||
|
||||
windows.erase(it);
|
||||
}
|
||||
|
||||
void EditorWindowLifecycleCoordinator::LogRuntimeTrace(
|
||||
std::string_view channel,
|
||||
std::string_view message) const {
|
||||
m_hostRuntime.LogRuntimeTrace(channel, message);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorWindow;
|
||||
class EditorWindowHostRuntime;
|
||||
class EditorWindowWorkspaceCoordinator;
|
||||
|
||||
class EditorWindowLifecycleCoordinator final {
|
||||
public:
|
||||
EditorWindowLifecycleCoordinator(
|
||||
EditorWindowHostRuntime& hostRuntime,
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator);
|
||||
~EditorWindowLifecycleCoordinator();
|
||||
|
||||
void PostCloseRequest(EditorWindow& window);
|
||||
void ExecuteCloseRequest(EditorWindow& window);
|
||||
void HandleNativeWindowDestroyed(EditorWindow& window);
|
||||
void AbortUnregisteredWindow(EditorWindow& window);
|
||||
void ShutdownAllWindows();
|
||||
void ReapDestroyedWindows();
|
||||
|
||||
private:
|
||||
void ShutdownRuntimeIfNeeded(EditorWindow& window);
|
||||
void EraseWindow(EditorWindow& window);
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
||||
|
||||
EditorWindowHostRuntime& m_hostRuntime;
|
||||
EditorWindowWorkspaceCoordinator& m_workspaceCoordinator;
|
||||
};
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Platform/Win32/EditorWindow.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowMessageDispatcher.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h"
|
||||
|
||||
@@ -19,6 +20,11 @@ EditorWindowManager::EditorWindowManager(
|
||||
editorContext)) {
|
||||
m_workspaceCoordinator =
|
||||
std::make_unique<EditorWindowWorkspaceCoordinator>(*m_hostRuntime);
|
||||
m_lifecycleCoordinator = std::make_unique<EditorWindowLifecycleCoordinator>(
|
||||
*m_hostRuntime,
|
||||
*m_workspaceCoordinator);
|
||||
m_hostRuntime->BindLifecycleCoordinator(*m_lifecycleCoordinator);
|
||||
m_workspaceCoordinator->BindLifecycleCoordinator(*m_lifecycleCoordinator);
|
||||
}
|
||||
|
||||
EditorWindowManager::~EditorWindowManager() = default;
|
||||
@@ -40,7 +46,7 @@ void EditorWindowManager::HandlePendingNativeWindowCreated(HWND hwnd) {
|
||||
|
||||
void EditorWindowManager::Shutdown() {
|
||||
m_workspaceCoordinator->EndGlobalTabDragSession();
|
||||
m_hostRuntime->Shutdown();
|
||||
m_lifecycleCoordinator->ShutdownAllWindows();
|
||||
}
|
||||
|
||||
bool EditorWindowManager::TryDispatchWindowMessage(
|
||||
@@ -61,6 +67,7 @@ bool EditorWindowManager::TryDispatchWindowMessage(
|
||||
return EditorWindowMessageDispatcher::TryDispatch(
|
||||
hwnd,
|
||||
*m_hostRuntime,
|
||||
*m_lifecycleCoordinator,
|
||||
*m_workspaceCoordinator,
|
||||
*window,
|
||||
message,
|
||||
@@ -98,7 +105,7 @@ bool EditorWindowManager::HasWindows() const {
|
||||
}
|
||||
|
||||
void EditorWindowManager::DestroyClosedWindows() {
|
||||
m_hostRuntime->DestroyClosedWindows();
|
||||
m_lifecycleCoordinator->ReapDestroyedWindows();
|
||||
}
|
||||
|
||||
void EditorWindowManager::RenderAllWindows() {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Platform/Win32/EditorWindow.h"
|
||||
#include "Platform/Win32/EditorWindowPointerCapture.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h"
|
||||
|
||||
#include <cstdint>
|
||||
@@ -55,6 +56,7 @@ std::string DescribeHostWindows(const EditorWindowHostRuntime& hostRuntime) {
|
||||
struct EditorWindowMessageDispatcher::DispatchContext {
|
||||
HWND hwnd = nullptr;
|
||||
EditorWindowHostRuntime& hostRuntime;
|
||||
EditorWindowLifecycleCoordinator& lifecycleCoordinator;
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator;
|
||||
EditorWindow& window;
|
||||
};
|
||||
@@ -403,18 +405,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowLifecycleMessage(
|
||||
outResult = 0;
|
||||
return true;
|
||||
case WM_CLOSE:
|
||||
context.hostRuntime.LogRuntimeTrace(
|
||||
"window-close",
|
||||
"WM_CLOSE windowId='" + std::string(context.window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(context.hwnd) +
|
||||
" localPrimary=" + (context.window.IsPrimary() ? "1" : "0") +
|
||||
" closingBefore=" + (context.window.IsClosing() ? "1" : "0") +
|
||||
" workspace=" + context.workspaceCoordinator.DescribeWindowSet() +
|
||||
" host=" + DescribeHostWindows(context.hostRuntime));
|
||||
if (!context.window.IsClosing()) {
|
||||
context.window.MarkClosing();
|
||||
}
|
||||
DestroyWindow(context.hwnd);
|
||||
context.lifecycleCoordinator.ExecuteCloseRequest(context.window);
|
||||
outResult = 0;
|
||||
return true;
|
||||
case WM_PAINT:
|
||||
@@ -425,30 +416,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowLifecycleMessage(
|
||||
outResult = 1;
|
||||
return true;
|
||||
case WM_DESTROY:
|
||||
if (context.workspaceCoordinator.OwnsActiveGlobalTabDrag(context.window.GetWindowId())) {
|
||||
context.workspaceCoordinator.EndGlobalTabDragSession();
|
||||
}
|
||||
{
|
||||
const bool destroyedPrimary =
|
||||
context.workspaceCoordinator.IsPrimaryWindowId(context.window.GetWindowId());
|
||||
context.hostRuntime.LogRuntimeTrace(
|
||||
"window-close",
|
||||
"WM_DESTROY begin windowId='" + std::string(context.window.GetWindowId()) +
|
||||
"' hwnd=" + DescribeHwnd(context.hwnd) +
|
||||
" destroyedPrimary=" + (destroyedPrimary ? "1" : "0") +
|
||||
" localPrimary=" + (context.window.IsPrimary() ? "1" : "0") +
|
||||
" workspaceBefore=" + context.workspaceCoordinator.DescribeWindowSet() +
|
||||
" hostBefore=" + DescribeHostWindows(context.hostRuntime));
|
||||
context.workspaceCoordinator.HandleWindowDestroyed(
|
||||
context.window.GetWindowId(),
|
||||
destroyedPrimary);
|
||||
context.hostRuntime.HandleDestroyedWindow(context.window, destroyedPrimary);
|
||||
context.hostRuntime.LogRuntimeTrace(
|
||||
"window-close",
|
||||
"WM_DESTROY end windowId='" + std::string(context.window.GetWindowId()) +
|
||||
"' workspaceAfter=" + context.workspaceCoordinator.DescribeWindowSet() +
|
||||
" hostAfter=" + DescribeHostWindows(context.hostRuntime));
|
||||
}
|
||||
context.lifecycleCoordinator.HandleNativeWindowDestroyed(context.window);
|
||||
outResult = 0;
|
||||
return true;
|
||||
default:
|
||||
@@ -519,6 +487,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowChromeMessage(
|
||||
bool EditorWindowMessageDispatcher::TryDispatch(
|
||||
HWND hwnd,
|
||||
EditorWindowHostRuntime& hostRuntime,
|
||||
EditorWindowLifecycleCoordinator& lifecycleCoordinator,
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator,
|
||||
EditorWindow& window,
|
||||
UINT message,
|
||||
@@ -528,6 +497,7 @@ bool EditorWindowMessageDispatcher::TryDispatch(
|
||||
const DispatchContext context = {
|
||||
.hwnd = hwnd,
|
||||
.hostRuntime = hostRuntime,
|
||||
.lifecycleCoordinator = lifecycleCoordinator,
|
||||
.workspaceCoordinator = workspaceCoordinator,
|
||||
.window = window,
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ class EditorWindow;
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorWindowHostRuntime;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
class EditorWindowWorkspaceCoordinator;
|
||||
|
||||
class EditorWindowMessageDispatcher final {
|
||||
@@ -20,6 +21,7 @@ public:
|
||||
static bool TryDispatch(
|
||||
HWND hwnd,
|
||||
EditorWindowHostRuntime& hostRuntime,
|
||||
EditorWindowLifecycleCoordinator& lifecycleCoordinator,
|
||||
EditorWindowWorkspaceCoordinator& workspaceCoordinator,
|
||||
EditorWindow& window,
|
||||
UINT message,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Composition/EditorContext.h"
|
||||
#include "Platform/Win32/EditorWindow.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h"
|
||||
|
||||
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
|
||||
#include <XCEditor/Workspace/UIEditorWindowWorkspaceController.h>
|
||||
@@ -87,6 +88,11 @@ EditorWindowWorkspaceCoordinator::EditorWindowWorkspaceCoordinator(
|
||||
|
||||
EditorWindowWorkspaceCoordinator::~EditorWindowWorkspaceCoordinator() = default;
|
||||
|
||||
void EditorWindowWorkspaceCoordinator::BindLifecycleCoordinator(
|
||||
EditorWindowLifecycleCoordinator& lifecycleCoordinator) {
|
||||
m_lifecycleCoordinator = &lifecycleCoordinator;
|
||||
}
|
||||
|
||||
void EditorWindowWorkspaceCoordinator::RegisterExistingWindow(EditorWindow& window) {
|
||||
std::string error = {};
|
||||
if (!m_workspaceStore.RegisterWindowProjection(
|
||||
@@ -137,7 +143,7 @@ std::string EditorWindowWorkspaceCoordinator::DescribeWindowSet() const {
|
||||
return DescribeWindowSetState(m_workspaceStore.GetWindowSet());
|
||||
}
|
||||
|
||||
void EditorWindowWorkspaceCoordinator::HandleWindowDestroyed(
|
||||
void EditorWindowWorkspaceCoordinator::RemoveWindowProjection(
|
||||
std::string_view windowId,
|
||||
bool primary) {
|
||||
LogRuntimeTrace(
|
||||
@@ -249,27 +255,12 @@ bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet(
|
||||
};
|
||||
|
||||
const auto destroyAndEraseWindowById = [this](std::string_view windowId) {
|
||||
auto& windows = m_hostRuntime.GetWindows();
|
||||
const auto it = std::find_if(
|
||||
windows.begin(),
|
||||
windows.end(),
|
||||
[windowId](const std::unique_ptr<EditorWindow>& candidate) {
|
||||
return candidate != nullptr && candidate->GetWindowId() == windowId;
|
||||
});
|
||||
if (it == windows.end() || *it == nullptr) {
|
||||
EditorWindow* const window = m_hostRuntime.FindWindow(windowId);
|
||||
if (window == nullptr || m_lifecycleCoordinator == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EditorWindow& window = *it->get();
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
window.ForceReleasePointerCapture();
|
||||
|
||||
window.Shutdown();
|
||||
if (hwnd != nullptr && IsWindow(hwnd)) {
|
||||
DestroyWindow(hwnd);
|
||||
}
|
||||
window.MarkDestroyed();
|
||||
windows.erase(it);
|
||||
m_lifecycleCoordinator->AbortUnregisteredWindow(*window);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -357,8 +348,9 @@ bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet(
|
||||
windowIdsInSet.end(),
|
||||
window->GetWindowId()) != windowIdsInSet.end();
|
||||
if (!existsInWindowSet) {
|
||||
window->MarkClosing();
|
||||
PostMessageW(window->GetHwnd(), WM_CLOSE, 0, 0);
|
||||
if (m_lifecycleCoordinator != nullptr) {
|
||||
m_lifecycleCoordinator->PostCloseRequest(*window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,17 +16,19 @@ namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class EditorWindow;
|
||||
class EditorWindowHostRuntime;
|
||||
class EditorWindowLifecycleCoordinator;
|
||||
|
||||
class EditorWindowWorkspaceCoordinator final {
|
||||
public:
|
||||
explicit EditorWindowWorkspaceCoordinator(EditorWindowHostRuntime& hostRuntime);
|
||||
~EditorWindowWorkspaceCoordinator();
|
||||
|
||||
void BindLifecycleCoordinator(EditorWindowLifecycleCoordinator& lifecycleCoordinator);
|
||||
void RegisterExistingWindow(EditorWindow& window);
|
||||
void CommitWindowProjection(EditorWindow& window);
|
||||
bool IsPrimaryWindowId(std::string_view windowId) const;
|
||||
std::string DescribeWindowSet() const;
|
||||
void HandleWindowDestroyed(std::string_view windowId, bool primary);
|
||||
void RemoveWindowProjection(std::string_view windowId, bool primary);
|
||||
|
||||
bool IsGlobalTabDragActive() const;
|
||||
bool OwnsActiveGlobalTabDrag(std::string_view windowId) const;
|
||||
@@ -103,6 +105,7 @@ private:
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
||||
|
||||
EditorWindowHostRuntime& m_hostRuntime;
|
||||
EditorWindowLifecycleCoordinator* m_lifecycleCoordinator = nullptr;
|
||||
EditorWindowWorkspaceStore m_workspaceStore;
|
||||
GlobalTabDragSession m_globalTabDragSession = {};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user