#include "Windowing/EditorWindowManager.h" #include "Windowing/Content/EditorWindowContentController.h" #include "Windowing/Content/EditorWindowContentFactory.h" #include "Windowing/Coordinator/EditorWindowLifecycleCoordinator.h" #include "Windowing/Coordinator/EditorUtilityWindowCoordinator.h" #include "Windowing/Coordinator/EditorWindowWorkspaceCoordinator.h" #include "Windowing/Runtime/EditorWindowRuntimeController.h" #include #include #include #include namespace XCEngine::UI::Editor::App { EditorWindowManager::EditorWindowManager( EditorContext& editorContext, EditorWindowSystem& windowSystem, EditorWindowHostRuntimeServices& hostRuntime) : m_editorContext(editorContext) , m_hostRuntime(hostRuntime) { m_contentFactory = CreateDefaultEditorWindowContentFactory(windowSystem); m_workspaceCoordinator = std::make_unique( m_editorContext, m_hostRuntime, windowSystem, *m_contentFactory); m_utilityCoordinator = std::make_unique( m_editorContext, m_hostRuntime, *m_contentFactory); m_lifecycleCoordinator = std::make_unique( m_hostRuntime, *m_workspaceCoordinator); m_hostRuntime.BindHostCoordinator(*this); m_workspaceCoordinator->BindLifecycleCoordinator(*m_lifecycleCoordinator); m_utilityCoordinator->BindLifecycleCoordinator(*m_lifecycleCoordinator); } EditorWindowManager::~EditorWindowManager() = default; EditorHostWindow* EditorWindowManager::CreateWorkspaceWindow( const UIEditorWindowWorkspaceState& windowState, const EditorWindowCreateParams& params) { if (m_contentFactory == nullptr) { return nullptr; } if (windowState.windowId.empty()) { return nullptr; } if (!params.windowId.empty() && windowState.windowId != params.windowId) { return nullptr; } EditorHostWindow* const window = m_hostRuntime.CreateHostWindow( std::make_unique( m_editorContext, m_contentFactory->CreateWorkspaceContentController(windowState)), params); if (window != nullptr) { m_workspaceCoordinator->RegisterExistingWindow(*window); } return window; } EditorHostWindow* EditorWindowManager::CreateUtilityWindow( const EditorUtilityWindowDescriptor& descriptor, const EditorWindowCreateParams& params) { if (m_contentFactory == nullptr) { return nullptr; } EditorHostWindow* const window = m_hostRuntime.CreateHostWindow( std::make_unique( m_editorContext, m_contentFactory->CreateUtilityContentController(descriptor)), params); if (window != nullptr) { m_workspaceCoordinator->RegisterExistingWindow(*window); } return window; } void EditorWindowManager::Shutdown() { m_workspaceCoordinator->EndGlobalTabDragSession(); m_lifecycleCoordinator->ShutdownAllWindows(); } bool EditorWindowManager::RequestPrimaryWindowClose() { if (m_lifecycleCoordinator == nullptr) { return false; } for (EditorHostWindow* window : m_hostRuntime.GetWindows()) { if (window == nullptr || !window->IsPrimary()) { continue; } m_lifecycleCoordinator->PostCloseRequest(*window); return true; } return false; } bool EditorWindowManager::HasWindows() const { return !m_hostRuntime.GetWindows().empty(); } void EditorWindowManager::DestroyClosedWindows() { m_lifecycleCoordinator->ReapDestroyedWindows(); } void EditorWindowManager::RenderAllWindows() { struct WindowFrameTransferBatch { EditorHostWindow* sourceWindow = nullptr; EditorWindowFrameTransferRequests requests = {}; }; std::vector transferBatches = {}; const std::vector windows = m_hostRuntime.GetWindows(); transferBatches.reserve(windows.size()); for (EditorHostWindow* window : windows) { if (window == nullptr || !window->HasLiveHostWindow() || window->GetLifecycleState() != EditorWindowLifecycleState::Running) { continue; } if (window->ConsumeSkipNextSteadyStateFrame()) { RefreshWindowPresentation(*window); continue; } EditorWindowFrameTransferRequests transferRequests = DriveWindowFrame(*window); RefreshWindowPresentation(*window); if (!transferRequests.HasPendingRequests()) { continue; } transferBatches.push_back(WindowFrameTransferBatch{ window, std::move(transferRequests), }); } for (WindowFrameTransferBatch& batch : transferBatches) { if (batch.sourceWindow == nullptr || !batch.sourceWindow->HasLiveHostWindow() || batch.sourceWindow->GetLifecycleState() != EditorWindowLifecycleState::Running) { continue; } DispatchWindowFrameTransferRequests( *batch.sourceWindow, batch.requests); } } bool EditorWindowManager::InitializeHostWindow( EditorHostWindow& window, const EditorHostWindowRuntimeInitializationParams& params) { return window.InitializeRuntime(params); } EditorWindowFrameTransferRequests EditorWindowManager::DriveWindowFrame( EditorHostWindow& window) { return DriveWindowFrameInternal(window, false); } EditorWindowFrameTransferRequests EditorWindowManager::DriveImmediateWindowFrame( EditorHostWindow& window) { return DriveWindowFrameInternal(window, true); } EditorWindowFrameTransferRequests EditorWindowManager::DriveWindowFrameInternal( EditorHostWindow& window, bool requestSkipNextSteadyStateFrame) { if (!window.IsRenderReady() || !window.HasLiveHostWindow() || window.GetLifecycleState() != EditorWindowLifecycleState::Running) { return {}; } EditorWindowFrameTransferRequests transferRequests = window.RenderHostFrame(IsGlobalTabDragActive()); window.ValidateHostFrame(); if (requestSkipNextSteadyStateFrame) { window.RequestSkipNextSteadyStateFrame(); } return transferRequests; } bool EditorWindowManager::IsGlobalTabDragActive() const { return m_workspaceCoordinator != nullptr && m_workspaceCoordinator->IsGlobalTabDragActive(); } bool EditorWindowManager::OwnsActiveGlobalTabDrag(std::string_view windowId) const { return m_workspaceCoordinator != nullptr && m_workspaceCoordinator->OwnsActiveGlobalTabDrag(windowId); } bool EditorWindowManager::HandleGlobalTabDragPointerMove(EditorHostWindow& window) { return m_workspaceCoordinator != nullptr && m_workspaceCoordinator->HandleGlobalTabDragPointerMove(window); } bool EditorWindowManager::HandleGlobalTabDragPointerButtonUp(EditorHostWindow& window) { return m_workspaceCoordinator != nullptr && m_workspaceCoordinator->HandleGlobalTabDragPointerButtonUp(window); } void EditorWindowManager::EndGlobalTabDragSession() { if (m_workspaceCoordinator != nullptr) { m_workspaceCoordinator->EndGlobalTabDragSession(); } } void EditorWindowManager::RefreshWindowPresentation(EditorHostWindow& window) { if (m_workspaceCoordinator != nullptr) { m_workspaceCoordinator->RefreshWindowPresentation(window); } } void EditorWindowManager::DispatchWindowFrameTransferRequests( EditorHostWindow& sourceWindow, const EditorWindowFrameTransferRequests& transferRequests) { if (m_workspaceCoordinator != nullptr) { m_workspaceCoordinator->HandleWindowFrameTransferRequests( sourceWindow, transferRequests); } if (m_utilityCoordinator != nullptr) { m_utilityCoordinator->HandleWindowFrameTransferRequests( sourceWindow, transferRequests); } } void EditorWindowManager::ExecuteCloseRequest(EditorHostWindow& window) { if (m_lifecycleCoordinator != nullptr) { m_lifecycleCoordinator->ExecuteCloseRequest(window); } } void EditorWindowManager::HandleNativeWindowDestroyed(EditorHostWindow& window) { if (m_lifecycleCoordinator != nullptr) { m_lifecycleCoordinator->HandleNativeWindowDestroyed(window); } } void EditorWindowManager::AbortUnregisteredWindow(EditorHostWindow& window) { if (m_lifecycleCoordinator != nullptr) { m_lifecycleCoordinator->AbortUnregisteredWindow(window); } } void EditorWindowManager::ReapDestroyedWindows() { if (m_lifecycleCoordinator != nullptr) { m_lifecycleCoordinator->ReapDestroyedWindows(); } } } // namespace XCEngine::UI::Editor::App