587 lines
20 KiB
C++
587 lines
20 KiB
C++
#include "Platform/Win32/Windowing/EditorWindowMessageDispatcher.h"
|
|
|
|
#include "Platform/Win32/Chrome/BorderlessWindowChrome.h"
|
|
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
|
#include "Platform/Win32/Runtime/EditorWindowInputController.h"
|
|
#include "Platform/Win32/Windowing/EditorWindow.h"
|
|
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
|
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
|
#include "Platform/Win32/Windowing/EditorWindowPointerCapture.h"
|
|
#include "Platform/Win32/Windowing/EditorWindowHostRuntime.h"
|
|
#include "Platform/Win32/Windowing/EditorWindowLifecycleCoordinator.h"
|
|
#include "Platform/Win32/Windowing/EditorUtilityWindowCoordinator.h"
|
|
#include "Platform/Win32/Windowing/EditorWindowWorkspaceCoordinator.h"
|
|
|
|
#include <cstdint>
|
|
#include <sstream>
|
|
#include <utility>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
namespace {
|
|
|
|
constexpr UINT kMessageNcUaDrawCaption = 0x00AEu;
|
|
constexpr UINT kMessageNcUaDrawFrame = 0x00AFu;
|
|
|
|
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 EditorWindowHostRuntime& hostRuntime) {
|
|
std::ostringstream stream = {};
|
|
const auto& windows = hostRuntime.GetWindows();
|
|
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')
|
|
<< ",state=" << GetEditorWindowLifecycleStateName(window->GetLifecycleState())
|
|
<< '}';
|
|
}
|
|
stream << ']';
|
|
return stream.str();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
struct EditorWindowMessageDispatcher::DispatchContext {
|
|
HWND hwnd = nullptr;
|
|
EditorWindowHostRuntime& hostRuntime;
|
|
EditorWindowLifecycleCoordinator& lifecycleCoordinator;
|
|
EditorUtilityWindowCoordinator& utilityCoordinator;
|
|
EditorWindowWorkspaceCoordinator& workspaceCoordinator;
|
|
EditorWindow& window;
|
|
};
|
|
|
|
void EditorWindowMessageDispatcher::DispatchWindowFrameTransferRequests(
|
|
const DispatchContext& context,
|
|
const EditorWindowFrameTransferRequests& transferRequests) {
|
|
context.workspaceCoordinator.HandleWindowFrameTransferRequests(
|
|
context.window,
|
|
transferRequests);
|
|
context.utilityCoordinator.HandleWindowFrameTransferRequests(
|
|
context.window,
|
|
transferRequests);
|
|
}
|
|
|
|
void EditorWindowMessageDispatcher::FinalizeImmediateFrame(
|
|
const DispatchContext& context,
|
|
const EditorWindowFrameTransferRequests& transferRequests) {
|
|
context.workspaceCoordinator.RefreshWindowPresentation(context.window);
|
|
if (!transferRequests.HasPendingRequests()) {
|
|
return;
|
|
}
|
|
|
|
DispatchWindowFrameTransferRequests(context, transferRequests);
|
|
}
|
|
|
|
void EditorWindowMessageDispatcher::FlushQueuedCompletedImmediateFrame(
|
|
const DispatchContext& context) {
|
|
if (!context.window.HasQueuedCompletedImmediateFrame()) {
|
|
return;
|
|
}
|
|
|
|
FinalizeImmediateFrame(
|
|
context,
|
|
context.window.ConsumeQueuedCompletedImmediateFrameTransferRequests());
|
|
}
|
|
|
|
void EditorWindowMessageDispatcher::RenderAndHandleWindowFrame(const DispatchContext& context) {
|
|
FinalizeImmediateFrame(
|
|
context,
|
|
EditorWindowFrameDriver::DriveImmediateFrame(
|
|
context.window,
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive()));
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::EnsureTrackingMouseLeave(const DispatchContext& context) {
|
|
if (context.window.m_inputController->IsTrackingMouseLeave()) {
|
|
return true;
|
|
}
|
|
|
|
TRACKMOUSEEVENT trackMouseEvent = {};
|
|
trackMouseEvent.cbSize = sizeof(trackMouseEvent);
|
|
trackMouseEvent.dwFlags = TME_LEAVE;
|
|
trackMouseEvent.hwndTrack = context.hwnd;
|
|
if (!TrackMouseEvent(&trackMouseEvent)) {
|
|
return false;
|
|
}
|
|
|
|
context.window.m_inputController->SetTrackingMouseLeave(true);
|
|
return true;
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::TryHandleChromeHoverConsumption(
|
|
const DispatchContext& context,
|
|
LPARAM lParam,
|
|
LRESULT& outResult) {
|
|
EditorWindowInputController& inputController = *context.window.m_inputController;
|
|
EditorWindowChromeController& chromeController = *context.window.m_chromeController;
|
|
const EditorWindowInputFeedbackBinding* inputFeedbackBinding =
|
|
context.window.m_runtime->TryGetInputFeedbackBinding();
|
|
|
|
if (!CanConsumeEditorWindowChromeHover(
|
|
inputController.GetPointerCaptureOwner(),
|
|
inputFeedbackBinding != nullptr &&
|
|
inputFeedbackBinding->HasShellInteractiveCapture(),
|
|
inputFeedbackBinding != nullptr &&
|
|
inputFeedbackBinding->HasHostedContentCapture())) {
|
|
return false;
|
|
}
|
|
|
|
const bool resizeHoverChanged = chromeController.UpdateResizeHover(context.window, lParam);
|
|
if (chromeController.UpdateChromeHover(context.window, lParam)) {
|
|
context.window.InvalidateHostWindow();
|
|
}
|
|
if (resizeHoverChanged) {
|
|
context.window.InvalidateHostWindow();
|
|
}
|
|
|
|
EnsureTrackingMouseLeave(context);
|
|
if (chromeController.GetHoveredBorderlessResizeEdge() !=
|
|
Host::BorderlessWindowResizeEdge::None) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
|
|
const Host::BorderlessWindowChromeHitTarget chromeHitTarget =
|
|
chromeController.HitTestChrome(context.window, lParam);
|
|
if (chromeHitTarget == Host::BorderlessWindowChromeHitTarget::PinButton ||
|
|
chromeHitTarget == Host::BorderlessWindowChromeHitTarget::MinimizeButton ||
|
|
chromeHitTarget == Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton ||
|
|
chromeHitTarget == Host::BorderlessWindowChromeHitTarget::CloseButton) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::TryDispatchWindowPointerMessage(
|
|
const DispatchContext& context,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LRESULT& outResult) {
|
|
EditorWindowInputController& inputController = *context.window.m_inputController;
|
|
EditorWindowChromeController& chromeController = *context.window.m_chromeController;
|
|
|
|
switch (message) {
|
|
case WM_MOUSEMOVE:
|
|
if (CanRouteEditorWindowGlobalTabDragPointerMessages(
|
|
inputController.GetPointerCaptureOwner(),
|
|
context.workspaceCoordinator.OwnsActiveGlobalTabDrag(context.window.GetWindowId())) &&
|
|
context.workspaceCoordinator.HandleGlobalTabDragPointerMove(context.hwnd)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (CanRouteEditorWindowBorderlessResizePointerMessages(
|
|
inputController.GetPointerCaptureOwner()) &&
|
|
chromeController.HandleResizePointerMove(
|
|
context.window,
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive())) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (CanRouteEditorWindowBorderlessChromePointerMessages(
|
|
inputController.GetPointerCaptureOwner()) &&
|
|
chromeController.HandleChromeDragRestorePointerMove(
|
|
context.window,
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive())) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (TryHandleChromeHoverConsumption(context, lParam, outResult)) {
|
|
return true;
|
|
}
|
|
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerMove,
|
|
::XCEngine::UI::UIPointerButton::None,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_MOUSELEAVE:
|
|
inputController.SetTrackingMouseLeave(false);
|
|
chromeController.ClearResizeState(context.window);
|
|
chromeController.ClearChromeDragRestoreState(context.window);
|
|
chromeController.ClearChromeState(context.window);
|
|
context.window.QueuePointerLeaveEvent();
|
|
outResult = 0;
|
|
return true;
|
|
case WM_LBUTTONDOWN:
|
|
if (context.workspaceCoordinator.OwnsActiveGlobalTabDrag(context.window.GetWindowId())) {
|
|
context.workspaceCoordinator.EndGlobalTabDragSession();
|
|
}
|
|
if (chromeController.HandleResizeButtonDown(context.window, lParam)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (chromeController.HandleChromeButtonDown(context.window, lParam)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
SetFocus(context.hwnd);
|
|
context.window.TryStartImmediateShellPointerCapture(lParam);
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonDown,
|
|
::XCEngine::UI::UIPointerButton::Left,
|
|
wParam,
|
|
lParam,
|
|
true);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_RBUTTONDOWN:
|
|
SetFocus(context.hwnd);
|
|
context.window.TryStartImmediateShellPointerCapture(lParam);
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonDown,
|
|
::XCEngine::UI::UIPointerButton::Right,
|
|
wParam,
|
|
lParam,
|
|
true);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_MBUTTONDOWN:
|
|
SetFocus(context.hwnd);
|
|
context.window.TryStartImmediateShellPointerCapture(lParam);
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonDown,
|
|
::XCEngine::UI::UIPointerButton::Middle,
|
|
wParam,
|
|
lParam,
|
|
true);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_LBUTTONUP:
|
|
if (CanRouteEditorWindowGlobalTabDragPointerMessages(
|
|
inputController.GetPointerCaptureOwner(),
|
|
context.workspaceCoordinator.OwnsActiveGlobalTabDrag(context.window.GetWindowId())) &&
|
|
context.workspaceCoordinator.HandleGlobalTabDragPointerButtonUp(context.hwnd)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (CanRouteEditorWindowBorderlessResizePointerMessages(
|
|
inputController.GetPointerCaptureOwner()) &&
|
|
chromeController.HandleResizeButtonUp(context.window)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (CanRouteEditorWindowBorderlessChromePointerMessages(
|
|
inputController.GetPointerCaptureOwner()) &&
|
|
chromeController.HandleChromeButtonUp(
|
|
context.window,
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive(),
|
|
lParam)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonUp,
|
|
::XCEngine::UI::UIPointerButton::Left,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_RBUTTONUP:
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonUp,
|
|
::XCEngine::UI::UIPointerButton::Right,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_MBUTTONUP:
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonUp,
|
|
::XCEngine::UI::UIPointerButton::Middle,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_LBUTTONDBLCLK:
|
|
if (chromeController.HandleChromeDoubleClick(
|
|
context.window,
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive(),
|
|
lParam)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
SetFocus(context.hwnd);
|
|
context.window.TryStartImmediateShellPointerCapture(lParam);
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonDown,
|
|
::XCEngine::UI::UIPointerButton::Left,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_RBUTTONDBLCLK:
|
|
SetFocus(context.hwnd);
|
|
context.window.TryStartImmediateShellPointerCapture(lParam);
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonDown,
|
|
::XCEngine::UI::UIPointerButton::Right,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_MBUTTONDBLCLK:
|
|
SetFocus(context.hwnd);
|
|
context.window.TryStartImmediateShellPointerCapture(lParam);
|
|
context.window.QueuePointerEvent(
|
|
::XCEngine::UI::UIInputEventType::PointerButtonDown,
|
|
::XCEngine::UI::UIPointerButton::Middle,
|
|
wParam,
|
|
lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_MOUSEWHEEL:
|
|
context.window.QueuePointerWheelEvent(GET_WHEEL_DELTA_WPARAM(wParam), wParam, lParam);
|
|
outResult = 0;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::TryDispatchWindowInputMessage(
|
|
const DispatchContext& context,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LRESULT& outResult) {
|
|
EditorWindowInputController& inputController = *context.window.m_inputController;
|
|
EditorWindowChromeController& chromeController = *context.window.m_chromeController;
|
|
|
|
if (TryDispatchWindowPointerMessage(context, message, wParam, lParam, outResult)) {
|
|
return true;
|
|
}
|
|
|
|
switch (message) {
|
|
case WM_SETFOCUS:
|
|
inputController.SyncInputModifiersFromSystemState();
|
|
inputController.QueueWindowFocusEvent(::XCEngine::UI::UIInputEventType::FocusGained);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_KILLFOCUS:
|
|
inputController.ResetInputModifiers();
|
|
inputController.QueueWindowFocusEvent(::XCEngine::UI::UIInputEventType::FocusLost);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_CAPTURECHANGED:
|
|
if (reinterpret_cast<HWND>(lParam) != context.hwnd) {
|
|
inputController.ClearPointerCaptureOwner();
|
|
}
|
|
if (context.workspaceCoordinator.OwnsActiveGlobalTabDrag(context.window.GetWindowId()) &&
|
|
reinterpret_cast<HWND>(lParam) != context.hwnd) {
|
|
context.workspaceCoordinator.EndGlobalTabDragSession();
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (reinterpret_cast<HWND>(lParam) != context.hwnd &&
|
|
context.window.HasInteractiveCaptureState()) {
|
|
inputController.QueueWindowFocusEvent(::XCEngine::UI::UIInputEventType::FocusLost);
|
|
chromeController.ForceClearResizeState(context.window);
|
|
chromeController.ClearChromeDragRestoreState(context.window);
|
|
chromeController.ClearChromeState(context.window);
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
if (reinterpret_cast<HWND>(lParam) != context.hwnd) {
|
|
chromeController.ForceClearResizeState(context.window);
|
|
chromeController.ClearChromeDragRestoreState(context.window);
|
|
chromeController.ClearChromeState(context.window);
|
|
}
|
|
return false;
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
if (wParam == VK_F12) {
|
|
context.window.m_runtime->RequestManualScreenshot("manual_f12");
|
|
}
|
|
inputController.QueueKeyEvent(::XCEngine::UI::UIInputEventType::KeyDown, wParam, lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_KEYUP:
|
|
case WM_SYSKEYUP:
|
|
inputController.QueueKeyEvent(::XCEngine::UI::UIInputEventType::KeyUp, wParam, lParam);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_CHAR:
|
|
inputController.QueueCharacterEvent(wParam);
|
|
outResult = 0;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::TryDispatchWindowLifecycleMessage(
|
|
const DispatchContext& context,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LRESULT& outResult) {
|
|
switch (message) {
|
|
case WM_DPICHANGED:
|
|
if (lParam == 0) {
|
|
return false;
|
|
}
|
|
context.window.OnDpiChanged(
|
|
static_cast<UINT>(LOWORD(wParam)),
|
|
*reinterpret_cast<const RECT*>(lParam));
|
|
RenderAndHandleWindowFrame(context);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_ENTERSIZEMOVE:
|
|
context.window.OnEnterSizeMove();
|
|
outResult = 0;
|
|
return true;
|
|
case WM_EXITSIZEMOVE:
|
|
if (context.window.OnExitSizeMove()) {
|
|
RenderAndHandleWindowFrame(context);
|
|
}
|
|
outResult = 0;
|
|
return true;
|
|
case WM_SIZE:
|
|
if (wParam != SIZE_MINIMIZED) {
|
|
const bool requiresImmediateFrame = context.window.OnResize(
|
|
static_cast<UINT>(LOWORD(lParam)),
|
|
static_cast<UINT>(HIWORD(lParam)));
|
|
if (requiresImmediateFrame) {
|
|
RenderAndHandleWindowFrame(context);
|
|
}
|
|
}
|
|
outResult = 0;
|
|
return true;
|
|
case WM_CLOSE:
|
|
context.lifecycleCoordinator.ExecuteCloseRequest(context.window);
|
|
outResult = 0;
|
|
return true;
|
|
case WM_PAINT:
|
|
FinalizeImmediateFrame(
|
|
context,
|
|
context.window.OnPaintMessage(
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive()));
|
|
outResult = 0;
|
|
return true;
|
|
case WM_ERASEBKGND:
|
|
outResult = 1;
|
|
return true;
|
|
case WM_DESTROY:
|
|
context.lifecycleCoordinator.HandleNativeWindowDestroyed(context.window);
|
|
outResult = 0;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::TryDispatchWindowChromeMessage(
|
|
const DispatchContext& context,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LRESULT& outResult) {
|
|
EditorWindowChromeController& chromeController = *context.window.m_chromeController;
|
|
|
|
switch (message) {
|
|
case WM_GETMINMAXINFO:
|
|
if (chromeController.HandleGetMinMaxInfo(context.window, lParam)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case WM_NCCALCSIZE:
|
|
outResult = chromeController.HandleNcCalcSize(context.window, wParam, lParam);
|
|
return true;
|
|
case WM_NCACTIVATE:
|
|
outResult = TRUE;
|
|
return true;
|
|
case WM_NCHITTEST:
|
|
outResult = HTCLIENT;
|
|
return true;
|
|
case WM_NCPAINT:
|
|
case kMessageNcUaDrawCaption:
|
|
case kMessageNcUaDrawFrame:
|
|
outResult = 0;
|
|
return true;
|
|
case WM_SYSCOMMAND:
|
|
if (chromeController.HandleSystemCommand(
|
|
context.window,
|
|
context.hostRuntime.GetEditorContext(),
|
|
context.workspaceCoordinator.IsGlobalTabDragActive(),
|
|
wParam)) {
|
|
outResult = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
case WM_SETCURSOR:
|
|
if (LOWORD(lParam) == HTCLIENT && context.window.ApplyCurrentCursor()) {
|
|
outResult = TRUE;
|
|
return true;
|
|
}
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool EditorWindowMessageDispatcher::TryDispatch(
|
|
HWND hwnd,
|
|
EditorWindowHostRuntime& hostRuntime,
|
|
EditorWindowLifecycleCoordinator& lifecycleCoordinator,
|
|
EditorUtilityWindowCoordinator& utilityCoordinator,
|
|
EditorWindowWorkspaceCoordinator& workspaceCoordinator,
|
|
EditorWindow& window,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
LRESULT& outResult) {
|
|
const DispatchContext context = {
|
|
.hwnd = hwnd,
|
|
.hostRuntime = hostRuntime,
|
|
.lifecycleCoordinator = lifecycleCoordinator,
|
|
.utilityCoordinator = utilityCoordinator,
|
|
.workspaceCoordinator = workspaceCoordinator,
|
|
.window = window,
|
|
};
|
|
|
|
bool handled = false;
|
|
if (TryDispatchWindowChromeMessage(context, message, wParam, lParam, outResult)) {
|
|
handled = true;
|
|
} else if (TryDispatchWindowLifecycleMessage(context, message, wParam, lParam, outResult)) {
|
|
handled = true;
|
|
} else if (TryDispatchWindowInputMessage(context, message, wParam, lParam, outResult)) {
|
|
handled = true;
|
|
}
|
|
|
|
if (handled) {
|
|
FlushQueuedCompletedImmediateFrame(context);
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|