refactor(new_editor): introduce win32 window session state

This commit is contained in:
2026-04-23 16:48:09 +08:00
parent d7b099391e
commit fc09b7ad83
8 changed files with 307 additions and 132 deletions

View File

@@ -242,6 +242,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
set(XCUI_EDITOR_APP_PLATFORM_SOURCES
app/Platform/Win32/Windowing/EditorWindow.cpp
app/Platform/Win32/Windowing/EditorFloatingWindowPlacement.cpp
app/Platform/Win32/Windowing/EditorWindowSession.cpp
app/Platform/Win32/Content/EditorUtilityWindowContentController.cpp
app/Platform/Win32/Chrome/EditorWindowChromeController.cpp
app/Platform/Win32/Runtime/EditorWindowFrameDriver.cpp

View File

@@ -3,7 +3,6 @@
#include "Platform/Win32/Windowing/EditorWindow.h"
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
#include "Platform/Win32/Windowing/EditorWindowState.h"
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
#include <XCEditor/Foundation/UIEditorTheme.h>
@@ -233,12 +232,13 @@ bool EditorWindowChromeController::HandleSystemCommand(
EditorContext& editorContext,
bool globalTabDragActive,
WPARAM wParam) {
const HWND hwnd = window.GetHwnd();
switch (wParam & 0xFFF0u) {
case SC_MAXIMIZE:
ToggleMaximizeRestore(window, editorContext, globalTabDragActive);
return true;
case SC_RESTORE:
if (!IsIconic(window.m_state->window.hwnd)) {
if (hwnd != nullptr && !IsIconic(hwnd)) {
ToggleMaximizeRestore(window, editorContext, globalTabDragActive);
return true;
}
@@ -253,7 +253,7 @@ bool EditorWindowChromeController::HandleGetMinMaxInfo(
LPARAM lParam) const {
const ::XCEngine::UI::UISize minimumOuterSize = window.m_runtime->ResolveMinimumOuterSize();
return Host::HandleBorderlessWindowGetMinMaxInfo(
window.m_state->window.hwnd,
window.GetHwnd(),
lParam,
static_cast<int>(minimumOuterSize.width),
static_cast<int>(minimumOuterSize.height));
@@ -264,7 +264,7 @@ LRESULT EditorWindowChromeController::HandleNcCalcSize(
WPARAM wParam,
LPARAM lParam) const {
return Host::HandleBorderlessWindowNcCalcSize(
window.m_state->window.hwnd,
window.GetHwnd(),
wParam,
lParam,
GetWindowDpi());
@@ -283,8 +283,8 @@ bool EditorWindowChromeController::UpdateResizeHover(EditorWindow& window, LPARA
bool EditorWindowChromeController::HandleResizeButtonDown(EditorWindow& window, LPARAM lParam) {
const Host::BorderlessWindowResizeEdge edge = HitTestResizeEdge(window, lParam);
if (edge == Host::BorderlessWindowResizeEdge::None ||
window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (edge == Host::BorderlessWindowResizeEdge::None || hwnd == nullptr) {
return false;
}
@@ -294,7 +294,7 @@ bool EditorWindowChromeController::HandleResizeButtonDown(EditorWindow& window,
}
RECT windowRect = {};
if (!GetWindowRect(window.m_state->window.hwnd, &windowRect)) {
if (!GetWindowRect(hwnd, &windowRect)) {
return false;
}
@@ -319,8 +319,8 @@ bool EditorWindowChromeController::HandleResizePointerMove(
EditorWindow& window,
EditorContext& editorContext,
bool globalTabDragActive) {
if (!IsBorderlessResizeActive() ||
window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (!IsBorderlessResizeActive() || hwnd == nullptr) {
return false;
}
@@ -380,14 +380,14 @@ bool EditorWindowChromeController::HandleResizePointerMove(
const auto setWindowPosBegin = std::chrono::steady_clock::now();
SetWindowPos(
window.m_state->window.hwnd,
hwnd,
nullptr,
targetRect.left,
targetRect.top,
width,
height,
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW);
ValidateRect(window.m_state->window.hwnd, nullptr);
ValidateRect(hwnd, nullptr);
if (IsVerboseResizeTraceEnabled()) {
const auto totalEnd = std::chrono::steady_clock::now();
const auto setWindowPosMs =
@@ -434,12 +434,13 @@ void EditorWindowChromeController::ForceClearResizeState(EditorWindow& window) {
Host::BorderlessWindowResizeEdge EditorWindowChromeController::HitTestResizeEdge(
const EditorWindow& window,
LPARAM lParam) const {
if (window.m_state->window.hwnd == nullptr || IsBorderlessWindowMaximized()) {
const HWND hwnd = window.GetHwnd();
if (hwnd == nullptr || IsBorderlessWindowMaximized()) {
return Host::BorderlessWindowResizeEdge::None;
}
RECT clientRect = {};
if (!GetClientRect(window.m_state->window.hwnd, &clientRect)) {
if (!GetClientRect(hwnd, &clientRect)) {
return Host::BorderlessWindowResizeEdge::None;
}
@@ -482,6 +483,7 @@ bool EditorWindowChromeController::HandleChromeButtonDown(EditorWindow& window,
return false;
}
const HWND hwnd = window.GetHwnd();
const Host::BorderlessWindowChromeHitTarget hitTarget = HitTestChrome(window, lParam);
switch (hitTarget) {
case Host::BorderlessWindowChromeHitTarget::MinimizeButton:
@@ -492,7 +494,7 @@ bool EditorWindowChromeController::HandleChromeButtonDown(EditorWindow& window,
window.InvalidateHostWindow();
return true;
case Host::BorderlessWindowChromeHitTarget::DragRegion:
if (window.m_state->window.hwnd != nullptr) {
if (hwnd != nullptr) {
if (IsBorderlessWindowMaximized()) {
POINT screenPoint = {};
if (GetCursorPos(&screenPoint)) {
@@ -503,7 +505,7 @@ bool EditorWindowChromeController::HandleChromeButtonDown(EditorWindow& window,
}
window.ForceReleasePointerCapture();
SendMessageW(window.m_state->window.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
SendMessageW(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
return true;
case Host::BorderlessWindowChromeHitTarget::None:
@@ -565,8 +567,8 @@ bool EditorWindowChromeController::HandleChromeDragRestorePointerMove(
EditorWindow& window,
EditorContext& editorContext,
bool globalTabDragActive) {
if (!IsBorderlessWindowDragRestoreArmed() ||
window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (!IsBorderlessWindowDragRestoreArmed() || hwnd == nullptr) {
return false;
}
@@ -630,7 +632,7 @@ bool EditorWindowChromeController::HandleChromeDragRestorePointerMove(
SetBorderlessWindowMaximized(false);
ApplyPredictedWindowRectTransition(window, editorContext, globalTabDragActive, targetRect);
ClearChromeDragRestoreState(window);
SendMessageW(window.m_state->window.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
SendMessageW(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
return true;
}
@@ -655,12 +657,13 @@ void EditorWindowChromeController::ClearChromeState(EditorWindow& window) {
Host::BorderlessWindowChromeHitTarget EditorWindowChromeController::HitTestChrome(
const EditorWindow& window,
LPARAM lParam) const {
if (window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (hwnd == nullptr) {
return Host::BorderlessWindowChromeHitTarget::None;
}
RECT clientRect = {};
if (!GetClientRect(window.m_state->window.hwnd, &clientRect)) {
if (!GetClientRect(hwnd, &clientRect)) {
return Host::BorderlessWindowChromeHitTarget::None;
}
@@ -695,7 +698,7 @@ Host::BorderlessWindowChromeLayout EditorWindowChromeController::ResolveChromeLa
bool EditorWindowChromeController::ShouldUseDetachedTitleBarTabStrip(
const EditorWindow& window) const {
const EditorWindowTitleBarBinding* titleBarBinding = window.m_runtime->TryGetTitleBarBinding();
return !window.m_state->window.primary &&
return !window.IsPrimary() &&
titleBarBinding != nullptr &&
titleBarBinding->ShouldUseDetachedTitleBarTabStrip();
}
@@ -718,7 +721,7 @@ void EditorWindowChromeController::AppendChrome(
1.0f);
}
if (!window.m_state->window.primary) {
if (!window.IsPrimary()) {
if (useDetachedTitleBarTabStrip) {
if (window.m_runtime->GetTitleBarLogoIcon().IsValid()) {
drawList.AddImage(
@@ -750,10 +753,11 @@ void EditorWindowChromeController::AppendChrome(
(layout.titleBarRect.height - kBorderlessTitleBarFontSize) * 0.5f -
1.0f)),
[&window]() {
const std::string_view cachedTitleText = window.GetCachedTitleText();
const std::string_view fallbackWindowTitle =
window.m_state->window.titleText.empty()
cachedTitleText.empty()
? std::string_view("XCEngine Editor")
: std::string_view(window.m_state->window.titleText);
: cachedTitleText;
const EditorWindowTitleBarBinding* titleBarBinding =
window.m_runtime->TryGetTitleBarBinding();
return titleBarBinding != nullptr
@@ -775,10 +779,10 @@ void EditorWindowChromeController::AppendChrome(
UIColor(1.0f, 1.0f, 1.0f, 1.0f));
}
const std::string titleText =
window.m_state->window.titleText.empty()
const std::string_view cachedTitleText = window.GetCachedTitleText();
const std::string titleText = cachedTitleText.empty()
? std::string("XCEngine Editor")
: window.m_state->window.titleText;
: std::string(cachedTitleText);
const std::string frameRateText = window.m_runtime->BuildFrameRateText();
drawList.AddText(
UIPoint(
@@ -834,20 +838,20 @@ bool EditorWindowChromeController::QueryCurrentWindowRect(
const EditorWindow& window,
RECT& outRect) const {
outRect = {};
return window.m_state->window.hwnd != nullptr &&
GetWindowRect(window.m_state->window.hwnd, &outRect) != FALSE;
const HWND hwnd = window.GetHwnd();
return hwnd != nullptr && GetWindowRect(hwnd, &outRect) != FALSE;
}
bool EditorWindowChromeController::QueryBorderlessWindowWorkAreaRect(
const EditorWindow& window,
RECT& outRect) const {
outRect = {};
if (window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (hwnd == nullptr) {
return false;
}
const HMONITOR monitor =
MonitorFromWindow(window.m_state->window.hwnd, MONITOR_DEFAULTTONEAREST);
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if (monitor == nullptr) {
return false;
}
@@ -867,7 +871,8 @@ bool EditorWindowChromeController::ApplyPredictedWindowRectTransition(
EditorContext& editorContext,
bool globalTabDragActive,
const RECT& targetRect) {
if (window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (hwnd == nullptr) {
return false;
}
@@ -887,7 +892,7 @@ bool EditorWindowChromeController::ApplyPredictedWindowRectTransition(
MarkPredictedClientPixelSizePresented();
}
SetWindowPos(
window.m_state->window.hwnd,
hwnd,
nullptr,
targetRect.left,
targetRect.top,
@@ -902,7 +907,7 @@ void EditorWindowChromeController::ToggleMaximizeRestore(
EditorWindow& window,
EditorContext& editorContext,
bool globalTabDragActive) {
if (window.m_state->window.hwnd == nullptr) {
if (window.GetHwnd() == nullptr) {
return;
}
@@ -934,19 +939,20 @@ void EditorWindowChromeController::ExecuteChromeAction(
EditorContext& editorContext,
bool globalTabDragActive,
Host::BorderlessWindowChromeHitTarget target) {
if (window.m_state->window.hwnd == nullptr) {
const HWND hwnd = window.GetHwnd();
if (hwnd == nullptr) {
return;
}
switch (target) {
case Host::BorderlessWindowChromeHitTarget::MinimizeButton:
ShowWindow(window.m_state->window.hwnd, SW_MINIMIZE);
ShowWindow(hwnd, SW_MINIMIZE);
break;
case Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
ToggleMaximizeRestore(window, editorContext, globalTabDragActive);
break;
case Host::BorderlessWindowChromeHitTarget::CloseButton:
PostMessageW(window.m_state->window.hwnd, WM_CLOSE, 0, 0);
PostMessageW(hwnd, WM_CLOSE, 0, 0);
break;
case Host::BorderlessWindowChromeHitTarget::DragRegion:
case Host::BorderlessWindowChromeHitTarget::None:

View File

@@ -23,7 +23,7 @@ EditorWindowFrameTransferRequests EditorWindowFrameDriver::DriveFrameInternal(
ValidateRect(hwnd, nullptr);
}
if (requestSkipNextSteadyStateFrame) {
window.m_chromeController->RequestSkipNextSteadyStateFrame();
window.RequestSkipNextSteadyStateFrame();
}
return transferRequests;

View File

@@ -3,10 +3,10 @@
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
#include "Platform/Win32/Content/EditorWindowContentController.h"
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
#include "Platform/Win32/Windowing/EditorWindowSession.h"
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
#include "Platform/Win32/Runtime/EditorWindowFrameOrchestrator.h"
#include "Platform/Win32/Runtime/EditorWindowInputController.h"
#include "Platform/Win32/Windowing/EditorWindowState.h"
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
#include "Composition/EditorContext.h"
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
@@ -79,46 +79,44 @@ EditorWindow::EditorWindow(
std::wstring title,
bool primary,
std::unique_ptr<EditorWindowContentController> contentController)
: m_state(std::make_unique<EditorWindowState>())
: m_session(std::make_unique<EditorWindowSession>(
std::move(windowId),
std::move(title),
primary))
, m_chromeController(std::make_unique<EditorWindowChromeController>())
, m_frameOrchestrator(std::make_unique<EditorWindowFrameOrchestrator>())
, m_inputController(std::make_unique<EditorWindowInputController>())
, m_runtime(std::make_unique<EditorWindowRuntimeController>(
std::move(contentController))) {
m_state->window.windowId = std::move(windowId);
m_state->window.title = std::move(title);
m_state->window.primary = primary;
UpdateCachedTitleText();
}
std::move(contentController))) {}
EditorWindow::~EditorWindow() = default;
std::string_view EditorWindow::GetWindowId() const {
return m_state->window.windowId;
return m_session->GetWindowId();
}
HWND EditorWindow::GetHwnd() const {
return m_state->window.hwnd;
return m_session->GetHwnd();
}
bool EditorWindow::HasHwnd() const {
return m_state->window.hwnd != nullptr;
return m_session->HasHwnd();
}
EditorWindowLifecycleState EditorWindow::GetLifecycleState() const {
return m_state->window.lifecycle;
return m_session->GetLifecycleState();
}
bool EditorWindow::IsPrimary() const {
return m_state->window.primary;
return m_session->IsPrimary();
}
bool EditorWindow::IsClosing() const {
return m_state->window.lifecycle == EditorWindowLifecycleState::Closing;
return m_session->IsClosing();
}
bool EditorWindow::IsDestroyed() const {
return m_state->window.lifecycle == EditorWindowLifecycleState::Destroyed;
return m_session->IsDestroyed();
}
bool EditorWindow::IsRenderReady() const {
@@ -126,7 +124,11 @@ bool EditorWindow::IsRenderReady() const {
}
const std::wstring& EditorWindow::GetTitle() const {
return m_state->window.title;
return m_session->GetTitle();
}
std::string_view EditorWindow::GetCachedTitleText() const {
return m_session->GetCachedTitleText();
}
const UIEditorWorkspaceController* EditorWindow::TryGetWorkspaceController() const {
@@ -143,35 +145,32 @@ const UIEditorWorkspaceController& EditorWindow::GetWorkspaceController() const
}
void EditorWindow::AttachHwnd(HWND hwnd) {
m_state->window.hwnd = hwnd;
m_state->window.lifecycle = EditorWindowLifecycleState::NativeAttached;
m_session->AttachHwnd(hwnd);
}
void EditorWindow::MarkInitializing() {
m_state->window.lifecycle = EditorWindowLifecycleState::Initializing;
m_session->MarkInitializing();
}
void EditorWindow::MarkRunning() {
m_state->window.lifecycle = EditorWindowLifecycleState::Running;
m_session->MarkRunning();
}
void EditorWindow::MarkDestroyed() {
m_state->window.hwnd = nullptr;
m_state->window.lifecycle = EditorWindowLifecycleState::Destroyed;
m_session->MarkDestroyed();
m_inputController->ResetWindowState();
}
void EditorWindow::MarkClosing() {
m_state->window.lifecycle = EditorWindowLifecycleState::Closing;
m_session->MarkClosing();
}
void EditorWindow::SetPrimary(bool primary) {
m_state->window.primary = primary;
m_session->SetPrimary(primary);
}
void EditorWindow::SetTitle(std::wstring title) {
m_state->window.title = std::move(title);
UpdateCachedTitleText();
m_session->SetTitle(std::move(title));
}
void EditorWindow::ReplaceWorkspaceController(UIEditorWorkspaceController workspaceController) {
@@ -181,8 +180,9 @@ void EditorWindow::ReplaceWorkspaceController(UIEditorWorkspaceController worksp
}
void EditorWindow::InvalidateHostWindow() const {
if (m_state->window.hwnd != nullptr && IsWindow(m_state->window.hwnd)) {
InvalidateRect(m_state->window.hwnd, nullptr, FALSE);
if (const HWND hwnd = m_session->GetHwnd();
hwnd != nullptr && IsWindow(hwnd)) {
InvalidateRect(hwnd, nullptr, FALSE);
}
}
@@ -191,14 +191,14 @@ bool EditorWindow::Initialize(
EditorContext& editorContext,
const std::filesystem::path& captureRoot,
bool autoCaptureOnStartup) {
if (m_state->window.hwnd == nullptr) {
if (m_session->GetHwnd() == nullptr) {
LogRuntimeTrace("app", "window initialize skipped: hwnd is null");
return false;
}
Host::RefreshBorderlessWindowDwmDecorations(m_state->window.hwnd);
Host::RefreshBorderlessWindowDwmDecorations(m_session->GetHwnd());
m_chromeController->Reset();
m_chromeController->SetWindowDpi(QueryWindowDpi(m_state->window.hwnd));
m_chromeController->SetWindowDpi(QueryWindowDpi(m_session->GetHwnd()));
m_runtime->SetDpiScale(GetDpiScale());
std::ostringstream dpiTrace = {};
@@ -208,7 +208,7 @@ bool EditorWindow::Initialize(
MarkInitializing();
const bool initialized = m_runtime->Initialize(
m_state->window.hwnd,
m_session->GetHwnd(),
repoRoot,
editorContext,
captureRoot,
@@ -216,7 +216,7 @@ bool EditorWindow::Initialize(
if (initialized) {
MarkRunning();
} else {
m_state->window.lifecycle = EditorWindowLifecycleState::NativeAttached;
m_session->MarkNativeAttached();
}
return initialized;
}
@@ -267,12 +267,13 @@ bool EditorWindow::ApplyWindowResize(UINT width, UINT height) {
bool EditorWindow::QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const {
outWidth = 0u;
outHeight = 0u;
if (m_state->window.hwnd == nullptr || !IsWindow(m_state->window.hwnd)) {
const HWND hwnd = m_session->GetHwnd();
if (hwnd == nullptr || !IsWindow(hwnd)) {
return false;
}
RECT clientRect = {};
if (!GetClientRect(m_state->window.hwnd, &clientRect)) {
if (!GetClientRect(hwnd, &clientRect)) {
return false;
}
@@ -312,8 +313,9 @@ UIPoint EditorWindow::ConvertClientPixelsToDips(LONG x, LONG y) const {
UIPoint EditorWindow::ConvertScreenPixelsToClientDips(const POINT& screenPoint) const {
POINT clientPoint = screenPoint;
if (m_state->window.hwnd != nullptr) {
ScreenToClient(m_state->window.hwnd, &clientPoint);
if (const HWND hwnd = m_session->GetHwnd();
hwnd != nullptr) {
ScreenToClient(hwnd, &clientPoint);
}
const float dpiScale = m_chromeController->GetDpiScale(kBaseDpiScale);
@@ -374,8 +376,9 @@ bool EditorWindow::OnResize(UINT width, UINT height) {
if (!matchedPresentedPrediction) {
m_chromeController->ClearPredictedClientPixelSize();
}
if (m_state->window.hwnd != nullptr) {
Host::RefreshBorderlessWindowDwmDecorations(m_state->window.hwnd);
if (const HWND hwnd = m_session->GetHwnd();
hwnd != nullptr) {
Host::RefreshBorderlessWindowDwmDecorations(hwnd);
}
if (matchedPresentedPrediction) {
@@ -405,11 +408,12 @@ bool EditorWindow::OnExitSizeMove() {
void EditorWindow::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
m_chromeController->SetWindowDpi(dpi == 0u ? kDefaultDpi : dpi);
m_runtime->SetDpiScale(GetDpiScale());
if (m_state->window.hwnd != nullptr) {
if (const HWND hwnd = m_session->GetHwnd();
hwnd != nullptr) {
const LONG windowWidth = suggestedRect.right - suggestedRect.left;
const LONG windowHeight = suggestedRect.bottom - suggestedRect.top;
SetWindowPos(
m_state->window.hwnd,
hwnd,
nullptr,
suggestedRect.left,
suggestedRect.top,
@@ -421,7 +425,7 @@ void EditorWindow::OnDpiChanged(UINT dpi, const RECT& suggestedRect) {
if (QueryCurrentClientPixelSize(clientWidth, clientHeight)) {
ApplyWindowResize(clientWidth, clientHeight);
}
Host::RefreshBorderlessWindowDwmDecorations(m_state->window.hwnd);
Host::RefreshBorderlessWindowDwmDecorations(hwnd);
}
std::ostringstream trace = {};
@@ -435,10 +439,6 @@ bool EditorWindow::IsVerboseRuntimeTraceEnabled() {
return s_enabled;
}
void EditorWindow::UpdateCachedTitleText() {
m_state->window.titleText = WideToUtf8(m_state->window.title);
}
} // namespace XCEngine::UI::Editor::App
namespace XCEngine::UI::Editor::App {
@@ -512,7 +512,7 @@ std::uint8_t ResolveExpectedShellCaptureButtons(
EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_runtime->IsReady() || m_state->window.hwnd == nullptr) {
if (!m_runtime->IsReady() || m_session->GetHwnd() == nullptr) {
return {};
}
@@ -554,49 +554,41 @@ EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
EditorWindowFrameTransferRequests EditorWindow::OnPaintMessage(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_runtime->IsReady() || m_state->window.hwnd == nullptr) {
if (!m_runtime->IsReady() || m_session->GetHwnd() == nullptr) {
return {};
}
PAINTSTRUCT paintStruct = {};
BeginPaint(m_state->window.hwnd, &paintStruct);
BeginPaint(m_session->GetHwnd(), &paintStruct);
const EditorWindowFrameTransferRequests transferRequests =
EditorWindowFrameDriver::DriveImmediateFrame(
*this,
editorContext,
globalTabDragActive);
EndPaint(m_state->window.hwnd, &paintStruct);
EndPaint(m_session->GetHwnd(), &paintStruct);
return transferRequests;
}
void EditorWindow::QueueCompletedImmediateFrame(
EditorWindowFrameTransferRequests transferRequests) {
m_hasQueuedCompletedImmediateFrame = true;
if (transferRequests.beginGlobalTabDrag.has_value()) {
m_queuedImmediateFrameTransferRequests.beginGlobalTabDrag =
std::move(transferRequests.beginGlobalTabDrag);
}
if (transferRequests.detachPanel.has_value()) {
m_queuedImmediateFrameTransferRequests.detachPanel =
std::move(transferRequests.detachPanel);
}
if (transferRequests.openUtilityWindow.has_value()) {
m_queuedImmediateFrameTransferRequests.openUtilityWindow =
std::move(transferRequests.openUtilityWindow);
}
m_session->QueueCompletedImmediateFrame(std::move(transferRequests));
}
bool EditorWindow::HasQueuedCompletedImmediateFrame() const {
return m_hasQueuedCompletedImmediateFrame;
return m_session->HasQueuedCompletedImmediateFrame();
}
EditorWindowFrameTransferRequests
EditorWindow::ConsumeQueuedCompletedImmediateFrameTransferRequests() {
m_hasQueuedCompletedImmediateFrame = false;
EditorWindowFrameTransferRequests transferRequests =
std::move(m_queuedImmediateFrameTransferRequests);
m_queuedImmediateFrameTransferRequests = {};
return transferRequests;
return m_session->ConsumeQueuedCompletedImmediateFrameTransferRequests();
}
void EditorWindow::RequestSkipNextSteadyStateFrame() {
m_chromeController->RequestSkipNextSteadyStateFrame();
}
bool EditorWindow::ConsumeSkipNextSteadyStateFrame() {
return m_chromeController->ConsumeSkipNextSteadyStateFrame();
}
UIRect EditorWindow::ResolveWorkspaceBounds(float clientWidthDips, float clientHeightDips) const {
@@ -634,7 +626,7 @@ EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame(
.bounds = workspaceBounds,
.inputEvents = frameEvents,
.captureStatusText = m_runtime->BuildCaptureStatusText(),
.primary = m_state->window.primary,
.primary = m_session->IsPrimary(),
.globalTabDragActive = globalTabDragActive,
.useDetachedTitleBarTabStrip = useDetachedTitleBarTabStrip,
},
@@ -748,21 +740,22 @@ bool EditorWindow::OwnsPointerCapture(EditorWindowPointerCaptureOwner owner) con
}
void EditorWindow::AcquirePointerCapture(EditorWindowPointerCaptureOwner owner) {
m_inputController->AcquirePointerCapture(m_state->window.hwnd, owner);
m_inputController->AcquirePointerCapture(m_session->GetHwnd(), owner);
}
void EditorWindow::ReleasePointerCapture(EditorWindowPointerCaptureOwner owner) {
m_inputController->ReleasePointerCapture(m_state->window.hwnd, owner);
m_inputController->ReleasePointerCapture(m_session->GetHwnd(), owner);
}
void EditorWindow::ForceReleasePointerCapture() {
m_inputController->ForceReleasePointerCapture(m_state->window.hwnd);
m_inputController->ForceReleasePointerCapture(m_session->GetHwnd());
}
void EditorWindow::TryStartImmediateShellPointerCapture(LPARAM lParam) {
if (m_state->window.hwnd == nullptr ||
!IsWindow(m_state->window.hwnd) ||
GetCapture() == m_state->window.hwnd) {
const HWND hwnd = m_session->GetHwnd();
if (hwnd == nullptr ||
!IsWindow(hwnd) ||
GetCapture() == hwnd) {
return;
}
@@ -794,7 +787,8 @@ void EditorWindow::QueuePointerEvent(
void EditorWindow::QueueSyntheticPointerStateSyncEvent(
const ::XCEngine::UI::UIInputModifiers& modifiers) {
if (m_state->window.hwnd == nullptr || !IsWindow(m_state->window.hwnd)) {
const HWND hwnd = m_session->GetHwnd();
if (hwnd == nullptr || !IsWindow(hwnd)) {
return;
}
@@ -802,7 +796,7 @@ void EditorWindow::QueueSyntheticPointerStateSyncEvent(
if (!GetCursorPos(&screenPoint)) {
return;
}
if (!ScreenToClient(m_state->window.hwnd, &screenPoint)) {
if (!ScreenToClient(hwnd, &screenPoint)) {
return;
}
@@ -813,17 +807,18 @@ void EditorWindow::QueueSyntheticPointerStateSyncEvent(
void EditorWindow::QueuePointerLeaveEvent() {
::XCEngine::UI::UIPoint position = {};
if (m_state->window.hwnd != nullptr) {
if (const HWND hwnd = m_session->GetHwnd();
hwnd != nullptr) {
POINT clientPoint = {};
GetCursorPos(&clientPoint);
ScreenToClient(m_state->window.hwnd, &clientPoint);
ScreenToClient(hwnd, &clientPoint);
position = ConvertClientPixelsToDips(clientPoint.x, clientPoint.y);
}
m_inputController->QueuePointerLeaveEvent(position);
}
void EditorWindow::QueuePointerWheelEvent(short wheelDelta, WPARAM wParam, LPARAM lParam) {
if (m_state->window.hwnd == nullptr) {
if (m_session->GetHwnd() == nullptr) {
return;
}
@@ -831,7 +826,7 @@ void EditorWindow::QueuePointerWheelEvent(short wheelDelta, WPARAM wParam, LPARA
GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam)
};
ScreenToClient(m_state->window.hwnd, &screenPoint);
ScreenToClient(m_session->GetHwnd(), &screenPoint);
m_inputController->QueuePointerWheelEvent(
ConvertClientPixelsToDips(screenPoint.x, screenPoint.y),
@@ -840,7 +835,8 @@ void EditorWindow::QueuePointerWheelEvent(short wheelDelta, WPARAM wParam, LPARA
}
bool EditorWindow::IsPointerInsideClientArea() const {
if (m_state->window.hwnd == nullptr || !IsWindow(m_state->window.hwnd)) {
const HWND hwnd = m_session->GetHwnd();
if (hwnd == nullptr || !IsWindow(hwnd)) {
return false;
}
@@ -849,14 +845,14 @@ bool EditorWindow::IsPointerInsideClientArea() const {
return false;
}
if (!IsScreenPointOverWindow(m_state->window.hwnd, screenPoint)) {
if (!IsScreenPointOverWindow(hwnd, screenPoint)) {
return false;
}
const LPARAM pointParam = MAKELPARAM(
static_cast<SHORT>(screenPoint.x),
static_cast<SHORT>(screenPoint.y));
return SendMessageW(m_state->window.hwnd, WM_NCHITTEST, 0, pointParam) == HTCLIENT;
return SendMessageW(hwnd, WM_NCHITTEST, 0, pointParam) == HTCLIENT;
}
LPCWSTR EditorWindow::ResolveCurrentCursorResource() const {

View File

@@ -5,8 +5,7 @@
#endif
#include "Platform/Win32/Windowing/EditorWindowPointerCapture.h"
#include "Platform/Win32/Windowing/EditorWindowState.h"
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
#include "Platform/Win32/Windowing/EditorWindowSession.h"
#include <windows.h>
@@ -61,7 +60,7 @@ class EditorWindowLifecycleCoordinator;
class EditorWindowMessageDispatcher;
class EditorWindowRuntimeController;
class EditorWindowWorkspaceCoordinator;
struct EditorWindowState;
class EditorWindowSession;
class EditorWindow {
public:
@@ -85,6 +84,7 @@ public:
bool IsClosing() const;
bool IsDestroyed() const;
const std::wstring& GetTitle() const;
std::string_view GetCachedTitleText() const;
const UIEditorWorkspaceController* TryGetWorkspaceController() const;
const UIEditorWorkspaceController& GetWorkspaceController() const;
::XCEngine::UI::UIPoint ConvertScreenPixelsToClientDips(const POINT& screenPoint) const;
@@ -135,6 +135,8 @@ private:
EditorWindowFrameTransferRequests transferRequests);
bool HasQueuedCompletedImmediateFrame() const;
EditorWindowFrameTransferRequests ConsumeQueuedCompletedImmediateFrameTransferRequests();
void RequestSkipNextSteadyStateFrame();
bool ConsumeSkipNextSteadyStateFrame();
bool OnResize(UINT width, UINT height);
void OnEnterSizeMove();
bool OnExitSizeMove();
@@ -177,16 +179,13 @@ private:
float PixelsToDips(float pixels) const;
::XCEngine::UI::UIPoint ConvertClientPixelsToDips(LONG x, LONG y) const;
void ApplyShellRuntimePointerCapture();
void UpdateCachedTitleText();
static bool IsVerboseRuntimeTraceEnabled();
std::unique_ptr<EditorWindowState> m_state = {};
std::unique_ptr<EditorWindowSession> m_session = {};
std::unique_ptr<EditorWindowChromeController> m_chromeController = {};
std::unique_ptr<EditorWindowFrameOrchestrator> m_frameOrchestrator = {};
std::unique_ptr<EditorWindowInputController> m_inputController = {};
std::unique_ptr<EditorWindowRuntimeController> m_runtime = {};
EditorWindowFrameTransferRequests m_queuedImmediateFrameTransferRequests = {};
bool m_hasQueuedCompletedImmediateFrame = false;
};
} // namespace XCEngine::UI::Editor::App

View File

@@ -190,7 +190,7 @@ void EditorWindowHostRuntime::RenderAllWindows(
continue;
}
if (window->m_chromeController->ConsumeSkipNextSteadyStateFrame()) {
if (window->ConsumeSkipNextSteadyStateFrame()) {
workspaceCoordinator.RefreshWindowPresentation(*window);
continue;
}

View File

@@ -0,0 +1,126 @@
#include "Platform/Win32/Windowing/EditorWindowSession.h"
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
#include <utility>
namespace XCEngine::UI::Editor::App {
using namespace EditorWindowSupport;
EditorWindowSession::EditorWindowSession(
std::string windowId,
std::wstring title,
bool primary) {
m_state.window.windowId = std::move(windowId);
m_state.window.title = std::move(title);
m_state.window.primary = primary;
UpdateCachedTitleText();
}
std::string_view EditorWindowSession::GetWindowId() const {
return m_state.window.windowId;
}
HWND EditorWindowSession::GetHwnd() const {
return m_state.window.hwnd;
}
bool EditorWindowSession::HasHwnd() const {
return m_state.window.hwnd != nullptr;
}
EditorWindowLifecycleState EditorWindowSession::GetLifecycleState() const {
return m_state.window.lifecycle;
}
bool EditorWindowSession::IsPrimary() const {
return m_state.window.primary;
}
bool EditorWindowSession::IsClosing() const {
return m_state.window.lifecycle == EditorWindowLifecycleState::Closing;
}
bool EditorWindowSession::IsDestroyed() const {
return m_state.window.lifecycle == EditorWindowLifecycleState::Destroyed;
}
const std::wstring& EditorWindowSession::GetTitle() const {
return m_state.window.title;
}
std::string_view EditorWindowSession::GetCachedTitleText() const {
return m_state.window.titleText;
}
void EditorWindowSession::AttachHwnd(HWND hwnd) {
m_state.window.hwnd = hwnd;
m_state.window.lifecycle = EditorWindowLifecycleState::NativeAttached;
}
void EditorWindowSession::MarkNativeAttached() {
m_state.window.lifecycle = EditorWindowLifecycleState::NativeAttached;
}
void EditorWindowSession::MarkInitializing() {
m_state.window.lifecycle = EditorWindowLifecycleState::Initializing;
}
void EditorWindowSession::MarkRunning() {
m_state.window.lifecycle = EditorWindowLifecycleState::Running;
}
void EditorWindowSession::MarkDestroyed() {
m_state.window.hwnd = nullptr;
m_state.window.lifecycle = EditorWindowLifecycleState::Destroyed;
}
void EditorWindowSession::MarkClosing() {
m_state.window.lifecycle = EditorWindowLifecycleState::Closing;
}
void EditorWindowSession::SetPrimary(bool primary) {
m_state.window.primary = primary;
}
void EditorWindowSession::SetTitle(std::wstring title) {
m_state.window.title = std::move(title);
UpdateCachedTitleText();
}
void EditorWindowSession::QueueCompletedImmediateFrame(
EditorWindowFrameTransferRequests transferRequests) {
m_hasQueuedCompletedImmediateFrame = true;
if (transferRequests.beginGlobalTabDrag.has_value()) {
m_queuedImmediateFrameTransferRequests.beginGlobalTabDrag =
std::move(transferRequests.beginGlobalTabDrag);
}
if (transferRequests.detachPanel.has_value()) {
m_queuedImmediateFrameTransferRequests.detachPanel =
std::move(transferRequests.detachPanel);
}
if (transferRequests.openUtilityWindow.has_value()) {
m_queuedImmediateFrameTransferRequests.openUtilityWindow =
std::move(transferRequests.openUtilityWindow);
}
}
bool EditorWindowSession::HasQueuedCompletedImmediateFrame() const {
return m_hasQueuedCompletedImmediateFrame;
}
EditorWindowFrameTransferRequests
EditorWindowSession::ConsumeQueuedCompletedImmediateFrameTransferRequests() {
m_hasQueuedCompletedImmediateFrame = false;
EditorWindowFrameTransferRequests transferRequests =
std::move(m_queuedImmediateFrameTransferRequests);
m_queuedImmediateFrameTransferRequests = {};
return transferRequests;
}
void EditorWindowSession::UpdateCachedTitleText() {
m_state.window.titleText = WideToUtf8(m_state.window.title);
}
} // namespace XCEngine::UI::Editor::App

View File

@@ -0,0 +1,47 @@
#pragma once
#include "Platform/Win32/Windowing/EditorWindowState.h"
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
#include <string>
#include <string_view>
namespace XCEngine::UI::Editor::App {
class EditorWindowSession final {
public:
EditorWindowSession(std::string windowId, std::wstring title, bool primary);
std::string_view GetWindowId() const;
HWND GetHwnd() const;
bool HasHwnd() const;
EditorWindowLifecycleState GetLifecycleState() const;
bool IsPrimary() const;
bool IsClosing() const;
bool IsDestroyed() const;
const std::wstring& GetTitle() const;
std::string_view GetCachedTitleText() const;
void AttachHwnd(HWND hwnd);
void MarkNativeAttached();
void MarkInitializing();
void MarkRunning();
void MarkDestroyed();
void MarkClosing();
void SetPrimary(bool primary);
void SetTitle(std::wstring title);
void QueueCompletedImmediateFrame(
EditorWindowFrameTransferRequests transferRequests);
bool HasQueuedCompletedImmediateFrame() const;
EditorWindowFrameTransferRequests ConsumeQueuedCompletedImmediateFrameTransferRequests();
private:
void UpdateCachedTitleText();
EditorWindowState m_state = {};
EditorWindowFrameTransferRequests m_queuedImmediateFrameTransferRequests = {};
bool m_hasQueuedCompletedImmediateFrame = false;
};
} // namespace XCEngine::UI::Editor::App