395 lines
9.1 KiB
C++
395 lines
9.1 KiB
C++
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
#if PLATFORM_GDK
|
|
|
|
#undef _GAMING_XBOX
|
|
#include "GDKWindow.h"
|
|
#include "GDKPlatform.h"
|
|
#include "Engine/Core/Log.h"
|
|
#include "Engine/Core/Math/Math.h"
|
|
#include "Engine/Graphics/GPUSwapChain.h"
|
|
#include "Engine/Graphics/RenderTask.h"
|
|
#include "Engine/Graphics/GPUDevice.h"
|
|
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
|
|
|
extern void OnMainWindowCreated(HWND hWnd);
|
|
|
|
GDKWindow::GDKWindow(const CreateWindowSettings& settings)
|
|
: WindowBase(settings)
|
|
{
|
|
int32 x = Math::TruncToInt(settings.Position.X);
|
|
int32 y = Math::TruncToInt(settings.Position.Y);
|
|
int32 clientWidth = Math::TruncToInt(settings.Size.X);
|
|
int32 clientHeight = Math::TruncToInt(settings.Size.Y);
|
|
int32 windowWidth = clientWidth;
|
|
int32 windowHeight = clientHeight;
|
|
_clientSize = Float2((float)clientWidth, (float)clientHeight);
|
|
|
|
// Setup window style
|
|
uint32 style = WS_POPUP, exStyle = 0;
|
|
if (settings.SupportsTransparency)
|
|
exStyle |= WS_EX_LAYERED;
|
|
if (!settings.ActivateWhenFirstShown)
|
|
exStyle |= WS_EX_NOACTIVATE;
|
|
if (settings.ShowInTaskbar)
|
|
exStyle |= WS_EX_APPWINDOW;
|
|
else
|
|
exStyle |= WS_EX_TOOLWINDOW;
|
|
if (settings.IsTopmost)
|
|
exStyle |= WS_EX_TOPMOST;
|
|
if (!settings.AllowInput)
|
|
exStyle |= WS_EX_TRANSPARENT;
|
|
if (settings.AllowMaximize)
|
|
style |= WS_MAXIMIZEBOX;
|
|
if (settings.AllowMinimize)
|
|
style |= WS_MINIMIZEBOX;
|
|
if (settings.HasSizingFrame)
|
|
style |= WS_THICKFRAME;
|
|
|
|
// Check if window should have a border
|
|
if (settings.HasBorder)
|
|
{
|
|
// Create window style flags
|
|
style |= WS_OVERLAPPED | WS_SYSMENU | WS_BORDER | WS_CAPTION;
|
|
exStyle |= 0;
|
|
|
|
// Adjust window size and positions to take into account window border
|
|
RECT winRect = { 0, 0, clientWidth, clientHeight };
|
|
AdjustWindowRectEx(&winRect, style, FALSE, exStyle);
|
|
x += winRect.left;
|
|
y += winRect.top;
|
|
windowWidth = winRect.right - winRect.left;
|
|
windowHeight = winRect.bottom - winRect.top;
|
|
}
|
|
else
|
|
{
|
|
// Create window style flags
|
|
style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
|
exStyle |= WS_EX_WINDOWEDGE;
|
|
}
|
|
|
|
// Creating the window
|
|
_handle = CreateWindowExW(
|
|
exStyle,
|
|
Platform::ApplicationWindowClass,
|
|
settings.Title.GetText(),
|
|
style,
|
|
x,
|
|
y,
|
|
windowWidth,
|
|
windowHeight,
|
|
settings.Parent ? static_cast<HWND>(settings.Parent->GetNativePtr()) : nullptr,
|
|
nullptr,
|
|
(HINSTANCE)Platform::Instance,
|
|
nullptr);
|
|
|
|
// Validate result
|
|
if (!HasHWND())
|
|
{
|
|
LOG_WIN32_LAST_ERROR;
|
|
Platform::Fatal(TEXT("Cannot create window."));
|
|
}
|
|
|
|
OnMainWindowCreated(_handle);
|
|
}
|
|
|
|
GDKWindow::~GDKWindow()
|
|
{
|
|
if (HasHWND())
|
|
{
|
|
// Destroy window
|
|
if (DestroyWindow(_handle) == 0)
|
|
{
|
|
LOG(Warning, "DestroyWindow failed! Error: {0:#x}", GetLastError());
|
|
}
|
|
|
|
// Clear
|
|
_handle = nullptr;
|
|
_visible = false;
|
|
}
|
|
}
|
|
|
|
void* GDKWindow::GetNativePtr() const
|
|
{
|
|
return _handle;
|
|
}
|
|
|
|
void GDKWindow::Show()
|
|
{
|
|
if (!_visible)
|
|
{
|
|
InitSwapChain();
|
|
if (_showAfterFirstPaint)
|
|
{
|
|
if (RenderTask)
|
|
RenderTask->Enabled = true;
|
|
return;
|
|
}
|
|
|
|
ASSERT(HasHWND());
|
|
|
|
// Show
|
|
ShowWindow(_handle, (_settings.AllowInput && _settings.ActivateWhenFirstShown) ? SW_SHOW : SW_SHOWNA);
|
|
|
|
// Base
|
|
WindowBase::Show();
|
|
|
|
_focused = true; // TODO: remove it and check if the initial focus works when game starts with rendering, do we get WM_ACTIVATEAPP?
|
|
}
|
|
}
|
|
|
|
void GDKWindow::Hide()
|
|
{
|
|
if (_visible)
|
|
{
|
|
ASSERT(HasHWND());
|
|
|
|
// Hide
|
|
ShowWindow(_handle, SW_HIDE);
|
|
|
|
// Base
|
|
WindowBase::Hide();
|
|
}
|
|
}
|
|
|
|
void GDKWindow::Minimize()
|
|
{
|
|
ASSERT(HasHWND());
|
|
ShowWindow(_handle, SW_MINIMIZE);
|
|
}
|
|
|
|
void GDKWindow::Maximize()
|
|
{
|
|
ASSERT(HasHWND());
|
|
ShowWindow(_handle, SW_MAXIMIZE);
|
|
}
|
|
|
|
void GDKWindow::Restore()
|
|
{
|
|
ASSERT(HasHWND());
|
|
ShowWindow(_handle, SW_RESTORE);
|
|
}
|
|
|
|
bool GDKWindow::IsClosed() const
|
|
{
|
|
return !HasHWND();
|
|
}
|
|
|
|
bool GDKWindow::IsForegroundWindow() const
|
|
{
|
|
return Platform::GetHasFocus();
|
|
}
|
|
|
|
void GDKWindow::SetIsFullscreen(bool isFullscreen)
|
|
{
|
|
}
|
|
|
|
void GDKWindow::GetScreenInfo(int32& x, int32& y, int32& width, int32& height) const
|
|
{
|
|
x = 0;
|
|
y = 0;
|
|
width = (int32)_clientSize.X;
|
|
height = (int32)_clientSize.Y;
|
|
}
|
|
|
|
void GDKWindow::SetCursor(CursorType type)
|
|
{
|
|
// Base
|
|
WindowBase::SetCursor(type);
|
|
|
|
UpdateCursor();
|
|
}
|
|
|
|
void GDKWindow::CheckForWindowResize()
|
|
{
|
|
// Skip for minimized window (GetClientRect for minimized window returns 0)
|
|
if (_minimized)
|
|
return;
|
|
|
|
ASSERT(HasHWND());
|
|
|
|
// Cache client size
|
|
RECT rect;
|
|
GetClientRect(_handle, &rect);
|
|
const int32 width = Math::Max(rect.right - rect.left, 0L);
|
|
const int32 height = Math::Max(rect.bottom - rect.top, 0L);
|
|
_clientSize = Float2(static_cast<float>(width), static_cast<float>(height));
|
|
|
|
// Check if window size has been changed
|
|
if (width > 0 && height > 0 && (_swapChain == nullptr || width != _swapChain->GetWidth() || height != _swapChain->GetHeight()))
|
|
{
|
|
OnResize(width, height);
|
|
}
|
|
}
|
|
|
|
void GDKWindow::UpdateCursor() const
|
|
{
|
|
if (_cursor == CursorType::Hidden)
|
|
{
|
|
::SetCursor(nullptr);
|
|
return;
|
|
}
|
|
|
|
int32 index = 0;
|
|
switch (_cursor)
|
|
{
|
|
case CursorType::Default:
|
|
break;
|
|
case CursorType::Cross:
|
|
index = 1;
|
|
break;
|
|
case CursorType::Hand:
|
|
index = 2;
|
|
break;
|
|
case CursorType::Help:
|
|
index = 3;
|
|
break;
|
|
case CursorType::IBeam:
|
|
index = 4;
|
|
break;
|
|
case CursorType::No:
|
|
index = 5;
|
|
break;
|
|
case CursorType::Wait:
|
|
index = 11;
|
|
break;
|
|
case CursorType::SizeAll:
|
|
index = 6;
|
|
break;
|
|
case CursorType::SizeNESW:
|
|
index = 7;
|
|
break;
|
|
case CursorType::SizeNS:
|
|
index = 8;
|
|
break;
|
|
case CursorType::SizeNWSE:
|
|
index = 9;
|
|
break;
|
|
case CursorType::SizeWE:
|
|
index = 10;
|
|
break;
|
|
}
|
|
|
|
static const LPCWSTR cursors[] =
|
|
{
|
|
IDC_ARROW,
|
|
IDC_CROSS,
|
|
IDC_HAND,
|
|
IDC_HELP,
|
|
IDC_IBEAM,
|
|
IDC_NO,
|
|
IDC_SIZEALL,
|
|
IDC_SIZENESW,
|
|
IDC_SIZENS,
|
|
IDC_SIZENWSE,
|
|
IDC_SIZEWE,
|
|
IDC_WAIT,
|
|
};
|
|
|
|
ASSERT(index >= 0 && index < ARRAY_COUNT(cursors));
|
|
const HCURSOR cursor = LoadCursorW(nullptr, cursors[index]);
|
|
::SetCursor(cursor);
|
|
}
|
|
|
|
Windows::LRESULT GDKWindow::WndProc(Windows::UINT msg, Windows::WPARAM wParam, Windows::LPARAM lParam)
|
|
{
|
|
switch (msg)
|
|
{
|
|
case WM_SETCURSOR:
|
|
{
|
|
if (LOWORD(lParam) == HTCLIENT)
|
|
{
|
|
UpdateCursor();
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
case WM_CREATE:
|
|
{
|
|
return 0;
|
|
}
|
|
case WM_SIZE:
|
|
{
|
|
if (SIZE_MINIMIZED == wParam)
|
|
{
|
|
// Set flags
|
|
_minimized = true;
|
|
_maximized = false;
|
|
}
|
|
else
|
|
{
|
|
RECT rcCurrentClient;
|
|
GetClientRect(_handle, &rcCurrentClient);
|
|
if (rcCurrentClient.top == 0 && rcCurrentClient.bottom == 0)
|
|
{
|
|
// Rapidly clicking the task bar to minimize and restore a window can cause a WM_SIZE message with SIZE_RESTORED when
|
|
// the window has actually become minimized due to rapid change so just ignore this message.
|
|
}
|
|
else if (SIZE_MAXIMIZED == wParam)
|
|
{
|
|
// Set flags
|
|
_minimized = false;
|
|
_maximized = true;
|
|
|
|
// Check size
|
|
CheckForWindowResize();
|
|
}
|
|
else if (SIZE_RESTORED == wParam)
|
|
{
|
|
if (_maximized)
|
|
{
|
|
// Clear flag
|
|
_maximized = false;
|
|
|
|
// Check size
|
|
CheckForWindowResize();
|
|
}
|
|
else if (_minimized)
|
|
{
|
|
// Clear flag
|
|
_minimized = false;
|
|
|
|
// Check size
|
|
CheckForWindowResize();
|
|
}
|
|
else
|
|
{
|
|
// This WM_SIZE come from resizing the window via an API like SetWindowPos() so resize
|
|
CheckForWindowResize();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WM_SETFOCUS:
|
|
OnGotFocus();
|
|
break;
|
|
case WM_KILLFOCUS:
|
|
OnLostFocus();
|
|
break;
|
|
case WM_ACTIVATEAPP:
|
|
if (wParam == TRUE && !_focused)
|
|
{
|
|
OnGotFocus();
|
|
}
|
|
else if (wParam == FALSE && _focused)
|
|
{
|
|
OnLostFocus();
|
|
}
|
|
break;
|
|
case WM_CLOSE:
|
|
Close(ClosingReason::User);
|
|
return 0;
|
|
case WM_DESTROY:
|
|
{
|
|
// Quit
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(_handle, msg, wParam, lParam);
|
|
}
|
|
|
|
#endif
|