refactor(new_editor): tighten app dependency boundaries

This commit is contained in:
2026-04-19 02:48:41 +08:00
parent 7429f22fb1
commit c59cd83c38
86 changed files with 1754 additions and 1077 deletions

View File

@@ -2,6 +2,7 @@
#include "Bootstrap/EditorResources.h"
#include "Platform/Win32/EditorWindowConstants.h"
#include "Platform/Win32/EditorWindowInternalState.h"
#include "Platform/Win32/EditorWindowPlatformInternal.h"
#include "Platform/Win32/EditorWindowRuntimeInternal.h"
#include "State/EditorContext.h"
@@ -73,122 +74,121 @@ EditorWindow::EditorWindow(
std::wstring title,
bool primary,
UIEditorWorkspaceController workspaceController)
: m_window{
nullptr,
std::move(windowId),
std::move(title),
{},
primary,
false }
, m_composition{ std::move(workspaceController), {} } {
: m_state(std::make_unique<EditorWindowState>()) {
m_state->window.windowId = std::move(windowId);
m_state->window.title = std::move(title);
m_state->window.primary = primary;
m_state->composition.workspaceController = std::move(workspaceController);
UpdateCachedTitleText();
}
EditorWindow::~EditorWindow() = default;
std::string_view EditorWindow::GetWindowId() const {
return m_window.windowId;
return m_state->window.windowId;
}
HWND EditorWindow::GetHwnd() const {
return m_window.hwnd;
return m_state->window.hwnd;
}
bool EditorWindow::HasHwnd() const {
return m_window.hwnd != nullptr;
return m_state->window.hwnd != nullptr;
}
bool EditorWindow::IsPrimary() const {
return m_window.primary;
return m_state->window.primary;
}
bool EditorWindow::IsClosing() const {
return m_window.closing;
return m_state->window.closing;
}
bool EditorWindow::IsRenderReady() const {
return m_render.ready;
return m_state->render.ready;
}
bool EditorWindow::IsTrackingMouseLeave() const {
return m_input.trackingMouseLeave;
return m_state->input.trackingMouseLeave;
}
bool EditorWindow::HasHoveredBorderlessResizeEdge() const {
return m_chrome.runtime.GetHoveredBorderlessResizeEdge() !=
return m_state->chrome.runtime.GetHoveredBorderlessResizeEdge() !=
Host::BorderlessWindowResizeEdge::None;
}
const std::wstring& EditorWindow::GetTitle() const {
return m_window.title;
return m_state->window.title;
}
const UIEditorWorkspaceController& EditorWindow::GetWorkspaceController() const {
return m_composition.workspaceController;
return m_state->composition.workspaceController;
}
UIEditorWorkspaceController& EditorWindow::GetWorkspaceController() {
return m_composition.workspaceController;
return m_state->composition.workspaceController;
}
const EditorShellRuntime& EditorWindow::GetShellRuntime() const {
return m_composition.shellRuntime;
return m_state->composition.shellRuntime;
}
EditorShellRuntime& EditorWindow::GetShellRuntime() {
return m_composition.shellRuntime;
return m_state->composition.shellRuntime;
}
const UIEditorShellInteractionFrame& EditorWindow::GetShellFrame() const {
return m_composition.shellRuntime.GetShellFrame();
return m_state->composition.shellRuntime.GetShellFrame();
}
const UIEditorShellInteractionState& EditorWindow::GetShellInteractionState() const {
return m_composition.shellRuntime.GetShellInteractionState();
return m_state->composition.shellRuntime.GetShellInteractionState();
}
void EditorWindow::SetExternalDockHostDropPreview(
const Widgets::UIEditorDockHostDropPreviewState& preview) {
m_composition.shellRuntime.SetExternalDockHostDropPreview(preview);
m_state->composition.shellRuntime.SetExternalDockHostDropPreview(preview);
}
void EditorWindow::ClearExternalDockHostDropPreview() {
m_composition.shellRuntime.ClearExternalDockHostDropPreview();
m_state->composition.shellRuntime.ClearExternalDockHostDropPreview();
}
void EditorWindow::AttachHwnd(HWND hwnd) {
m_window.hwnd = hwnd;
m_window.closing = false;
m_state->window.hwnd = hwnd;
m_state->window.closing = false;
}
void EditorWindow::MarkDestroyed() {
m_window.hwnd = nullptr;
m_window.closing = false;
m_input.trackingMouseLeave = false;
m_state->window.hwnd = nullptr;
m_state->window.closing = false;
m_state->input.trackingMouseLeave = false;
}
void EditorWindow::MarkClosing() {
m_window.closing = true;
m_state->window.closing = true;
}
void EditorWindow::ClearClosing() {
m_window.closing = false;
m_state->window.closing = false;
}
void EditorWindow::SetTrackingMouseLeave(bool trackingMouseLeave) {
m_input.trackingMouseLeave = trackingMouseLeave;
m_state->input.trackingMouseLeave = trackingMouseLeave;
}
void EditorWindow::SetTitle(std::wstring title) {
m_window.title = std::move(title);
m_state->window.title = std::move(title);
UpdateCachedTitleText();
}
void EditorWindow::ReplaceWorkspaceController(UIEditorWorkspaceController workspaceController) {
m_composition.workspaceController = std::move(workspaceController);
m_state->composition.workspaceController = std::move(workspaceController);
}
void EditorWindow::InvalidateHostWindow() const {
if (m_window.hwnd != nullptr && IsWindow(m_window.hwnd)) {
InvalidateRect(m_window.hwnd, nullptr, FALSE);
if (m_state->window.hwnd != nullptr && IsWindow(m_state->window.hwnd)) {
InvalidateRect(m_state->window.hwnd, nullptr, FALSE);
}
}
@@ -197,71 +197,80 @@ bool EditorWindow::Initialize(
EditorContext& editorContext,
const std::filesystem::path& captureRoot,
bool autoCaptureOnStartup) {
if (m_window.hwnd == nullptr) {
if (m_state->window.hwnd == nullptr) {
LogRuntimeTrace("app", "window initialize skipped: hwnd is null");
return false;
}
Host::RefreshBorderlessWindowDwmDecorations(m_window.hwnd);
m_chrome.runtime.Reset();
m_chrome.runtime.SetWindowDpi(QueryWindowDpi(m_window.hwnd));
m_render.renderer.SetDpiScale(GetDpiScale());
Host::RefreshBorderlessWindowDwmDecorations(m_state->window.hwnd);
m_state->chrome.runtime.Reset();
m_state->chrome.runtime.SetWindowDpi(QueryWindowDpi(m_state->window.hwnd));
m_state->render.renderer.SetDpiScale(GetDpiScale());
std::ostringstream dpiTrace = {};
dpiTrace << "initial dpi=" << m_chrome.runtime.GetWindowDpi()
dpiTrace << "initial dpi=" << m_state->chrome.runtime.GetWindowDpi()
<< " scale=" << GetDpiScale();
LogRuntimeTrace("window", dpiTrace.str());
if (!m_render.renderer.Initialize(m_window.hwnd)) {
if (!m_state->render.renderer.Initialize(m_state->window.hwnd)) {
LogRuntimeTrace("app", "renderer initialization failed");
return false;
}
RECT clientRect = {};
GetClientRect(m_window.hwnd, &clientRect);
GetClientRect(m_state->window.hwnd, &clientRect);
const int clientWidth = (std::max)(clientRect.right - clientRect.left, 1L);
const int clientHeight = (std::max)(clientRect.bottom - clientRect.top, 1L);
if (!m_render.windowRenderer.Initialize(m_window.hwnd, clientWidth, clientHeight)) {
if (!m_state->render.windowRenderer.Initialize(
m_state->window.hwnd,
clientWidth,
clientHeight)) {
LogRuntimeTrace("app", "d3d12 window renderer initialization failed");
m_render.renderer.Shutdown();
m_state->render.renderer.Shutdown();
return false;
}
const Host::D3D12WindowRenderLoopAttachResult attachResult =
m_render.windowRenderLoop.Attach(m_render.renderer, m_render.windowRenderer);
m_state->render.windowRenderLoop.Attach(
m_state->render.renderer,
m_state->render.windowRenderer);
if (!attachResult.interopWarning.empty()) {
LogRuntimeTrace("app", attachResult.interopWarning);
}
editorContext.AttachTextMeasurer(m_render.renderer);
m_composition.shellRuntime.Initialize(repoRoot, m_render.renderer);
m_composition.shellRuntime.AttachViewportWindowRenderer(m_render.windowRenderer);
m_composition.shellRuntime.SetViewportSurfacePresentationEnabled(
editorContext.AttachTextMeasurer(m_state->render.renderer);
m_state->composition.shellRuntime.Initialize(
repoRoot,
m_state->render.renderer,
m_state->render.renderer);
m_state->composition.shellRuntime.AttachViewportWindowRenderer(
m_state->render.windowRenderer);
m_state->composition.shellRuntime.SetViewportSurfacePresentationEnabled(
attachResult.hasViewportSurfacePresentation);
std::string titleBarLogoError = {};
if (!LoadEmbeddedPngTexture(
m_render.renderer,
m_state->render.renderer,
IDR_PNG_LOGO_ICON,
m_render.titleBarLogoIcon,
m_state->render.titleBarLogoIcon,
titleBarLogoError)) {
LogRuntimeTrace("icons", "titlebar logo_icon.png: " + titleBarLogoError);
}
if (!m_composition.shellRuntime.GetBuiltInIconError().empty()) {
LogRuntimeTrace("icons", m_composition.shellRuntime.GetBuiltInIconError());
if (!m_state->composition.shellRuntime.GetBuiltInIconError().empty()) {
LogRuntimeTrace("icons", m_state->composition.shellRuntime.GetBuiltInIconError());
}
LogRuntimeTrace(
"app",
"shell runtime initialized: " +
editorContext.DescribeWorkspaceState(
m_composition.workspaceController,
m_composition.shellRuntime.GetShellInteractionState()));
m_render.ready = true;
m_state->composition.workspaceController,
m_state->composition.shellRuntime.GetShellInteractionState()));
m_state->render.ready = true;
m_render.autoScreenshot.Initialize(captureRoot);
m_state->render.autoScreenshot.Initialize(captureRoot);
if (autoCaptureOnStartup && IsAutoCaptureOnStartupEnabled()) {
m_render.autoScreenshot.RequestCapture("startup");
m_state->render.autoScreenshot.RequestCapture("startup");
editorContext.SetStatus("Capture", "Startup capture requested.");
}
@@ -271,41 +280,42 @@ bool EditorWindow::Initialize(
void EditorWindow::Shutdown() {
ForceReleasePointerCapture();
m_render.ready = false;
m_render.autoScreenshot.Shutdown();
m_composition.shellRuntime.Shutdown();
m_render.renderer.ReleaseTexture(m_render.titleBarLogoIcon);
m_render.windowRenderLoop.Detach();
m_render.windowRenderer.Shutdown();
m_render.renderer.Shutdown();
m_input.pendingEvents.clear();
m_chrome.chromeState = {};
m_chrome.runtime.Reset();
m_state->render.ready = false;
m_state->render.autoScreenshot.Shutdown();
m_state->composition.shellRuntime.Shutdown();
m_state->render.renderer.ReleaseTexture(m_state->render.titleBarLogoIcon);
m_state->render.windowRenderLoop.Detach();
m_state->render.windowRenderer.Shutdown();
m_state->render.renderer.Shutdown();
m_state->input.pendingEvents.clear();
m_state->chrome.chromeState = {};
m_state->chrome.runtime.Reset();
}
void EditorWindow::ResetInteractionState() {
ForceReleasePointerCapture();
m_input.pendingEvents.clear();
m_input.trackingMouseLeave = false;
m_input.modifierTracker.Reset();
m_composition.shellRuntime.ResetInteractionState();
m_chrome.chromeState = {};
m_chrome.runtime.EndBorderlessResize();
m_chrome.runtime.EndBorderlessWindowDragRestore();
m_chrome.runtime.EndInteractiveResize();
m_chrome.runtime.SetHoveredBorderlessResizeEdge(Host::BorderlessWindowResizeEdge::None);
m_chrome.runtime.ClearPredictedClientPixelSize();
m_state->input.pendingEvents.clear();
m_state->input.trackingMouseLeave = false;
m_state->input.modifierTracker.Reset();
m_state->composition.shellRuntime.ResetInteractionState();
m_state->chrome.chromeState = {};
m_state->chrome.runtime.EndBorderlessResize();
m_state->chrome.runtime.EndBorderlessWindowDragRestore();
m_state->chrome.runtime.EndInteractiveResize();
m_state->chrome.runtime.SetHoveredBorderlessResizeEdge(
Host::BorderlessWindowResizeEdge::None);
m_state->chrome.runtime.ClearPredictedClientPixelSize();
}
bool EditorWindow::ApplyWindowResize(UINT width, UINT height) {
if (!m_render.ready || width == 0u || height == 0u) {
if (!m_state->render.ready || width == 0u || height == 0u) {
return false;
}
const Host::D3D12WindowRenderLoopResizeResult resizeResult =
m_render.windowRenderLoop.ApplyResize(width, height);
m_composition.shellRuntime.SetViewportSurfacePresentationEnabled(
m_state->render.windowRenderLoop.ApplyResize(width, height);
m_state->composition.shellRuntime.SetViewportSurfacePresentationEnabled(
resizeResult.hasViewportSurfacePresentation);
if (!resizeResult.windowRendererWarning.empty()) {
@@ -322,12 +332,12 @@ bool EditorWindow::ApplyWindowResize(UINT width, UINT height) {
bool EditorWindow::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const {
outWidth = 0u;
outHeight = 0u;
if (m_window.hwnd == nullptr || !IsWindow(m_window.hwnd)) {
if (m_state->window.hwnd == nullptr || !IsWindow(m_state->window.hwnd)) {
return false;
}
RECT clientRect = {};
if (!GetClientRect(m_window.hwnd, &clientRect)) {
if (!GetClientRect(m_state->window.hwnd, &clientRect)) {
return false;
}
@@ -343,7 +353,7 @@ bool EditorWindow::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight)
}
bool EditorWindow::ResolveRenderClientPixelSize(UINT& outWidth, UINT& outHeight) const {
if (m_chrome.runtime.TryGetPredictedClientPixelSize(outWidth, outHeight)) {
if (m_state->chrome.runtime.TryGetPredictedClientPixelSize(outWidth, outHeight)) {
return true;
}
@@ -351,7 +361,7 @@ bool EditorWindow::ResolveRenderClientPixelSize(UINT& outWidth, UINT& outHeight)
}
float EditorWindow::GetDpiScale() const {
return m_chrome.runtime.GetDpiScale(kBaseDpiScale);
return m_state->chrome.runtime.GetDpiScale(kBaseDpiScale);
}
float EditorWindow::PixelsToDips(float pixels) const {
@@ -367,11 +377,11 @@ UIPoint EditorWindow::ConvertClientPixelsToDips(LONG x, LONG y) const {
UIPoint EditorWindow::ConvertScreenPixelsToClientDips(const POINT& screenPoint) const {
POINT clientPoint = screenPoint;
if (m_window.hwnd != nullptr) {
ScreenToClient(m_window.hwnd, &clientPoint);
if (m_state->window.hwnd != nullptr) {
ScreenToClient(m_state->window.hwnd, &clientPoint);
}
const float dpiScale = m_chrome.runtime.GetDpiScale(kBaseDpiScale);
const float dpiScale = m_state->chrome.runtime.GetDpiScale(kBaseDpiScale);
return UIPoint(
dpiScale > 0.0f
? static_cast<float>(clientPoint.x) / dpiScale
@@ -385,15 +395,17 @@ void EditorWindow::OnResize(UINT width, UINT height) {
bool matchesPredictedClientSize = false;
UINT predictedWidth = 0u;
UINT predictedHeight = 0u;
if (m_chrome.runtime.TryGetPredictedClientPixelSize(predictedWidth, predictedHeight)) {
if (m_state->chrome.runtime.TryGetPredictedClientPixelSize(
predictedWidth,
predictedHeight)) {
matchesPredictedClientSize =
predictedWidth == width &&
predictedHeight == height;
}
m_chrome.runtime.ClearPredictedClientPixelSize();
if (IsBorderlessWindowEnabled() && m_window.hwnd != nullptr) {
Host::RefreshBorderlessWindowDwmDecorations(m_window.hwnd);
m_state->chrome.runtime.ClearPredictedClientPixelSize();
if (IsBorderlessWindowEnabled() && m_state->window.hwnd != nullptr) {
Host::RefreshBorderlessWindowDwmDecorations(m_state->window.hwnd);
}
if (!matchesPredictedClientSize) {
@@ -402,12 +414,12 @@ void EditorWindow::OnResize(UINT width, UINT height) {
}
void EditorWindow::OnEnterSizeMove() {
m_chrome.runtime.BeginInteractiveResize();
m_state->chrome.runtime.BeginInteractiveResize();
}
void EditorWindow::OnExitSizeMove() {
m_chrome.runtime.EndInteractiveResize();
m_chrome.runtime.ClearPredictedClientPixelSize();
m_state->chrome.runtime.EndInteractiveResize();
m_state->chrome.runtime.ClearPredictedClientPixelSize();
UINT width = 0u;
UINT height = 0u;
if (QueryCurrentClientPixelSize(width, height)) {
@@ -416,13 +428,13 @@ void EditorWindow::OnExitSizeMove() {
}
void EditorWindow::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
m_chrome.runtime.SetWindowDpi(dpi == 0u ? kDefaultDpi : dpi);
m_render.renderer.SetDpiScale(GetDpiScale());
if (m_window.hwnd != nullptr) {
m_state->chrome.runtime.SetWindowDpi(dpi == 0u ? kDefaultDpi : dpi);
m_state->render.renderer.SetDpiScale(GetDpiScale());
if (m_state->window.hwnd != nullptr) {
const LONG windowWidth = suggestedRect.right - suggestedRect.left;
const LONG windowHeight = suggestedRect.bottom - suggestedRect.top;
SetWindowPos(
m_window.hwnd,
m_state->window.hwnd,
nullptr,
suggestedRect.left,
suggestedRect.top,
@@ -434,11 +446,11 @@ void EditorWindow::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
if (QueryCurrentClientPixelSize(clientWidth, clientHeight)) {
ApplyWindowResize(clientWidth, clientHeight);
}
Host::RefreshBorderlessWindowDwmDecorations(m_window.hwnd);
Host::RefreshBorderlessWindowDwmDecorations(m_state->window.hwnd);
}
std::ostringstream trace = {};
trace << "dpi changed to " << m_chrome.runtime.GetWindowDpi()
trace << "dpi changed to " << m_state->chrome.runtime.GetWindowDpi()
<< " scale=" << GetDpiScale();
LogRuntimeTrace("window", trace.str());
}
@@ -449,7 +461,7 @@ bool EditorWindow::IsVerboseRuntimeTraceEnabled() {
}
void EditorWindow::UpdateCachedTitleText() {
m_window.titleText = WideToUtf8(m_window.title);
m_state->window.titleText = WideToUtf8(m_state->window.title);
}
} // namespace XCEngine::UI::Editor::App