#include "Platform/Win32/WindowManager/Internal.h" #include "State/EditorContext.h" #include "Platform/Win32/EditorWindow.h" #include #include namespace XCEngine::UI::Editor::App { EditorWindowManager::EditorWindowManager( EditorWindowHostConfig hostConfig, std::filesystem::path repoRoot, EditorContext& editorContext) : m_hostRuntime(std::make_unique( hostConfig, std::move(repoRoot), editorContext)) { m_workspaceCoordinator = std::make_unique(*m_hostRuntime); } EditorWindowManager::~EditorWindowManager() = default; EditorWindow* EditorWindowManager::CreateEditorWindow( UIEditorWorkspaceController workspaceController, const CreateParams& params) { return m_hostRuntime->CreateEditorWindow(std::move(workspaceController), params); } void EditorWindowManager::HandlePendingNativeWindowCreated(HWND hwnd) { m_hostRuntime->HandlePendingNativeWindowCreated(hwnd); } void EditorWindowManager::Shutdown() { m_workspaceCoordinator->EndGlobalTabDragSession(); m_hostRuntime->Shutdown(); } EditorWindow* EditorWindowManager::FindWindow(HWND hwnd) { return m_hostRuntime->FindWindow(hwnd); } const EditorWindow* EditorWindowManager::FindWindow(HWND hwnd) const { return m_hostRuntime->FindWindow(hwnd); } EditorWindow* EditorWindowManager::FindWindow(std::string_view windowId) { return m_hostRuntime->FindWindow(windowId); } const EditorWindow* EditorWindowManager::FindWindow(std::string_view windowId) const { return m_hostRuntime->FindWindow(windowId); } EditorWindow* EditorWindowManager::FindPrimaryWindow() { return m_hostRuntime->FindPrimaryWindow(); } const EditorWindow* EditorWindowManager::FindPrimaryWindow() const { return m_hostRuntime->FindPrimaryWindow(); } bool EditorWindowManager::HasWindows() const { return m_hostRuntime->HasWindows(); } void EditorWindowManager::DestroyClosedWindows() { m_hostRuntime->DestroyClosedWindows(); } void EditorWindowManager::RenderAllWindows() { m_hostRuntime->RenderAllWindows( m_workspaceCoordinator->IsGlobalTabDragActive(), *m_workspaceCoordinator); } bool EditorWindowManager::IsGlobalTabDragActive() const { return m_workspaceCoordinator->IsGlobalTabDragActive(); } bool EditorWindowManager::OwnsActiveGlobalTabDrag(std::string_view windowId) const { return m_workspaceCoordinator->OwnsActiveGlobalTabDrag(windowId); } void EditorWindowManager::EndGlobalTabDragSession() { m_workspaceCoordinator->EndGlobalTabDragSession(); } void EditorWindowManager::HandleDestroyedWindow(HWND hwnd) { m_hostRuntime->HandleDestroyedWindow(hwnd); } void EditorWindowManager::HandleWindowFrameTransferRequests( EditorWindow& sourceWindow, EditorWindowFrameTransferRequests&& transferRequests) { m_workspaceCoordinator->HandleWindowFrameTransferRequests( sourceWindow, std::move(transferRequests)); } bool EditorWindowManager::HandleGlobalTabDragPointerMove(HWND hwnd) { return m_workspaceCoordinator->HandleGlobalTabDragPointerMove(hwnd); } bool EditorWindowManager::HandleGlobalTabDragPointerButtonUp(HWND hwnd) { return m_workspaceCoordinator->HandleGlobalTabDragPointerButtonUp(hwnd); } } // namespace XCEngine::UI::Editor::App namespace XCEngine::UI::Editor::App::Internal { EditorWindowHostRuntime::EditorWindowHostRuntime( EditorWindowHostConfig hostConfig, std::filesystem::path repoRoot, EditorContext& editorContext) : m_hostConfig(hostConfig), m_repoRoot(std::move(repoRoot)), m_editorContext(editorContext) {} EditorWindowHostRuntime::~EditorWindowHostRuntime() = default; void EditorWindowHostRuntime::Shutdown() { for (const std::unique_ptr& 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(); if (GetCapture() == hwnd) { ReleaseCapture(); } window.Shutdown(); if (hwnd != nullptr && IsWindow(hwnd)) { DestroyWindow(hwnd); } window.MarkDestroyed(); } 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; } window->Shutdown(); it = m_windows.erase(it); } } void EditorWindowHostRuntime::RenderAllWindows( bool globalTabDragActive, EditorWindowWorkspaceCoordinator& workspaceCoordinator) { struct WindowFrameTransferBatch { EditorWindow* sourceWindow = nullptr; EditorWindowFrameTransferRequests requests = {}; }; std::vector transferBatches = {}; transferBatches.reserve(m_windows.size()); for (const std::unique_ptr& window : m_windows) { if (window == nullptr || window->GetHwnd() == nullptr) { continue; } EditorWindowFrameTransferRequests transferRequests = window->RenderFrame(m_editorContext, globalTabDragActive); if (!transferRequests.HasPendingRequests()) { continue; } transferBatches.push_back(WindowFrameTransferBatch{ window.get(), std::move(transferRequests), }); } for (WindowFrameTransferBatch& batch : transferBatches) { if (batch.sourceWindow == nullptr || batch.sourceWindow->GetHwnd() == nullptr) { continue; } workspaceCoordinator.HandleWindowFrameTransferRequests( *batch.sourceWindow, std::move(batch.requests)); } } void EditorWindowHostRuntime::HandleDestroyedWindow(HWND hwnd) { if (EditorWindow* window = FindWindow(hwnd); window != nullptr) { window->MarkDestroyed(); if (window->IsPrimary()) { for (const std::unique_ptr& otherWindow : m_windows) { if (otherWindow != nullptr && otherWindow.get() != window && otherWindow->GetHwnd() != nullptr) { PostMessageW(otherWindow->GetHwnd(), WM_CLOSE, 0, 0); } } } } } void EditorWindowHostRuntime::LogRuntimeTrace( std::string_view channel, std::string_view message) const { AppendUIEditorRuntimeTrace(channel, message); } EditorWindowWorkspaceCoordinator::EditorWindowWorkspaceCoordinator( EditorWindowHostRuntime& hostRuntime) : m_hostRuntime(hostRuntime) {} EditorWindowWorkspaceCoordinator::~EditorWindowWorkspaceCoordinator() = default; void EditorWindowWorkspaceCoordinator::HandleWindowFrameTransferRequests( EditorWindow& sourceWindow, EditorWindowFrameTransferRequests&& transferRequests) { if (!m_globalTabDragSession.active && transferRequests.beginGlobalTabDrag.has_value() && transferRequests.beginGlobalTabDrag->IsValid()) { TryStartGlobalTabDrag(sourceWindow, *transferRequests.beginGlobalTabDrag); } if (!m_globalTabDragSession.active && transferRequests.detachPanel.has_value() && transferRequests.detachPanel->IsValid()) { TryProcessDetachRequest(sourceWindow, *transferRequests.detachPanel); } } } // namespace XCEngine::UI::Editor::App::Internal