Rename Display to Window.
It makes more sense to be consistent and always call it window.
This commit is contained in:
parent
416a71f744
commit
24da7f45e0
33 changed files with 257 additions and 255 deletions
429
source/Platform/Win32/Win32Window.cpp
Normal file
429
source/Platform/Win32/Win32Window.cpp
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Spectre/Window/Window.h>
|
||||
#include <Spectre/System/Log.h>
|
||||
#include "Win32Application.h"
|
||||
#include "Win32Internal.h"
|
||||
#include "Win32Window.h"
|
||||
|
||||
namespace sp {
|
||||
|
||||
#define WND_CLASSNAME "SPECTRE_WIN32_WNDCLASS"
|
||||
|
||||
#if defined(_WIN64) && !defined(GWL_USERDATA)
|
||||
// x64 undefines this. So we define it again.
|
||||
#define GWL_USERDATA GWLP_USERDATA
|
||||
#endif /* defined(_WIN64) && !defined(GWL_USERDATA) */
|
||||
|
||||
static bool firstTime = true;
|
||||
|
||||
Win32Window::Win32Window() :
|
||||
m_handle (NULL),
|
||||
m_icon (0),
|
||||
m_cursor (0),
|
||||
m_inResizeModalLoop (false),
|
||||
m_minSize (200, 200)
|
||||
{
|
||||
}
|
||||
|
||||
Win32Window::~Win32Window()
|
||||
{
|
||||
if (m_icon) {
|
||||
DestroyIcon(m_icon);
|
||||
}
|
||||
|
||||
if (m_handle) {
|
||||
DestroyWindow(m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
bool Win32Window::create(WindowDescription description)
|
||||
{
|
||||
DWORD flags;
|
||||
Vector2i pos, actual_size;
|
||||
|
||||
if (firstTime) {
|
||||
registerClass();
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
// Store the size for use later.
|
||||
m_size = Vector2u(description.mode.width, description.mode.height);
|
||||
|
||||
// Set window to center and set decoration flags.
|
||||
pos = centerWindow(description.mode.width, description.mode.height);
|
||||
flags = getWin32Flags(description.decoration);
|
||||
|
||||
// Calculate the actuall window size (with borders and stuff)
|
||||
actual_size = calculateSize(flags, description.mode.width, description.mode.height);
|
||||
|
||||
// Create window.
|
||||
m_handle = CreateWindowExA(0, WND_CLASSNAME, "", flags,
|
||||
pos.x, pos.y, actual_size.x, actual_size.y,
|
||||
NULL, NULL, GetModuleHandle(NULL), (LPVOID) this);
|
||||
|
||||
if (!m_handle) {
|
||||
Log::error("Win32 - Could not create window: %s", Win32GetMessage(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32Window::destroy()
|
||||
{
|
||||
if (m_handle) {
|
||||
DestroyWindow(m_handle);
|
||||
m_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* Win32Window::getHandle() const
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
bool Win32Window::isValid()
|
||||
{
|
||||
return m_handle != NULL;
|
||||
}
|
||||
|
||||
void Win32Window::setSize(unsigned int width, unsigned int height)
|
||||
{
|
||||
Vector2i s = calculateSize(GetWindowLong(m_handle, GWL_STYLE), width, height);
|
||||
::SetWindowPos(m_handle, NULL, 0, 0, s.x, s.y, SWP_NOMOVE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
Vector2u Win32Window::getSize() const
|
||||
{
|
||||
RECT rect;
|
||||
Vector2u size;
|
||||
|
||||
if (GetClientRect(m_handle, &rect)) {
|
||||
size.x = rect.right - rect.left;
|
||||
size.y = rect.bottom - rect.top;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void Win32Window::setPosition(unsigned int x, unsigned int y)
|
||||
{
|
||||
::SetWindowPos(m_handle, NULL, x, y, 0, 0, SWP_NOSIZE);
|
||||
}
|
||||
|
||||
Vector2u Win32Window::getPosition() const
|
||||
{
|
||||
RECT r;
|
||||
GetWindowRect(m_handle, &r);
|
||||
return Vector2u(r.left, r.top);
|
||||
}
|
||||
|
||||
void Win32Window::setVisible(bool visible)
|
||||
{
|
||||
::ShowWindow(m_handle, visible ? SW_SHOW : SW_HIDE);
|
||||
}
|
||||
|
||||
void Win32Window::setDecoration(unsigned decoration)
|
||||
{
|
||||
::SetWindowLong(m_handle, GWL_STYLE, getWin32Flags(decoration));
|
||||
}
|
||||
|
||||
void Win32Window::minimize()
|
||||
{
|
||||
::ShowWindow(m_handle, SW_MINIMIZE);
|
||||
}
|
||||
|
||||
void Win32Window::maximize()
|
||||
{
|
||||
::ShowWindow(m_handle, SW_MAXIMIZE);
|
||||
}
|
||||
|
||||
void Win32Window::setCaption(const std::string& caption)
|
||||
{
|
||||
::SetWindowText(m_handle, caption.c_str());
|
||||
}
|
||||
|
||||
void Win32Window::showCursor(bool value)
|
||||
{
|
||||
if (value) {
|
||||
m_cursor = ::LoadCursor(NULL, IDC_ARROW);
|
||||
} else {
|
||||
m_cursor = 0;
|
||||
}
|
||||
|
||||
::SetCursor(m_cursor);
|
||||
}
|
||||
|
||||
void Win32Window::grabCursor(bool value)
|
||||
{
|
||||
if (value) {
|
||||
RECT rect;
|
||||
GetClientRect(m_handle, &rect);
|
||||
MapWindowPoints(m_handle, NULL, reinterpret_cast<LPPOINT>(&rect), 2);
|
||||
ClipCursor(&rect);
|
||||
} else {
|
||||
ClipCursor(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Window::setIcon(unsigned int width, unsigned int height, const uint8_t *pixels)
|
||||
{
|
||||
::HDC hdc;
|
||||
::ICONINFO ii;
|
||||
::BITMAPV5HEADER bi;
|
||||
::HBITMAP bmp_color, bmp_mask;
|
||||
unsigned char *bmp_data = NULL;
|
||||
|
||||
::ZeroMemory(&bi, sizeof(bi));
|
||||
bi.bV5Size = sizeof(bi);
|
||||
bi.bV5Width = width;
|
||||
bi.bV5Height = height;
|
||||
bi.bV5Planes = 1;
|
||||
bi.bV5BitCount = 32;
|
||||
bi.bV5Compression = BI_RGB;
|
||||
bi.bV5CSType = LCS_WINDOWS_COLOR_SPACE;
|
||||
bi.bV5Intent = LCS_GM_IMAGES;
|
||||
|
||||
hdc = ::GetDC(NULL);
|
||||
bmp_color = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bi),
|
||||
DIB_RGB_COLORS, (void **) &bmp_data, NULL, 0);
|
||||
::ReleaseDC(NULL, hdc);
|
||||
|
||||
if (!bmp_color) {
|
||||
Log::error("Win32Window::setIcon() - Failed to create RGBA bitmap");
|
||||
return;
|
||||
}
|
||||
|
||||
bmp_mask = CreateBitmap(width, height, 1, 1, NULL);
|
||||
if (!bmp_mask) {
|
||||
Log::error("Win32Window::setIcon() - Failed to create mask bitmap");
|
||||
::DeleteObject(bmp_color);
|
||||
return;
|
||||
}
|
||||
|
||||
// pixels are always RGBA, WinApi wants BGRA
|
||||
for(int i = 0; i < width * height; i++) {
|
||||
bmp_data[i * 4 + 0] = pixels[i * 4 + 2]; // R <- B
|
||||
bmp_data[i * 4 + 1] = pixels[i * 4 + 1]; // G <- G
|
||||
bmp_data[i * 4 + 2] = pixels[i * 4 + 0]; // B <- R
|
||||
bmp_data[i * 4 + 3] = pixels[i * 4 + 3]; // A <- A
|
||||
}
|
||||
|
||||
::ZeroMemory(&ii, sizeof(ii));
|
||||
ii.fIcon = TRUE;
|
||||
ii.xHotspot = 0;
|
||||
ii.yHotspot = 0;
|
||||
ii.hbmColor = bmp_color;
|
||||
ii.hbmMask = bmp_mask;
|
||||
|
||||
if (m_icon) {
|
||||
::DestroyIcon(m_icon);
|
||||
}
|
||||
|
||||
m_icon = CreateIconIndirect(&ii);
|
||||
|
||||
if (m_icon) {
|
||||
::SendMessage(m_handle, WM_SETICON, ICON_SMALL, (LPARAM) m_icon);
|
||||
::SendMessage(m_handle, WM_SETICON, ICON_BIG, (LPARAM) m_icon);
|
||||
} else {
|
||||
Log::error("Win32Window::setIcon() - Failed to create icon");
|
||||
}
|
||||
|
||||
::DeleteObject(bmp_color);
|
||||
::DeleteObject(bmp_mask);
|
||||
}
|
||||
|
||||
void Win32Window::registerClass()
|
||||
{
|
||||
WNDCLASSA wndcl;
|
||||
|
||||
ZeroMemory(&wndcl, sizeof(wndcl));
|
||||
|
||||
wndcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
||||
wndcl.lpfnWndProc = Win32Window::staticWndProc;
|
||||
wndcl.hInstance = ::GetModuleHandle(NULL);
|
||||
wndcl.lpszClassName = WND_CLASSNAME;
|
||||
|
||||
::RegisterClass(&wndcl);
|
||||
}
|
||||
|
||||
DWORD Win32Window::getWin32Flags(unsigned int flags)
|
||||
{
|
||||
DWORD win32_flags = WS_VISIBLE;
|
||||
|
||||
if (flags == WindowDecorate::Empty) {
|
||||
win32_flags |= WS_POPUP;
|
||||
} else {
|
||||
if (flags & WindowDecorate::Menu) {
|
||||
win32_flags |= WS_CAPTION | WS_MINIMIZEBOX;
|
||||
}
|
||||
|
||||
if (flags & WindowDecorate::Resize) {
|
||||
win32_flags |= WS_THICKFRAME | WS_MAXIMIZEBOX;
|
||||
}
|
||||
|
||||
if (flags & WindowDecorate::Close) {
|
||||
win32_flags |= WS_SYSMENU;
|
||||
}
|
||||
}
|
||||
return win32_flags;
|
||||
}
|
||||
|
||||
Vector2i Win32Window::centerWindow(int width, int height)
|
||||
{
|
||||
Vector2i v;
|
||||
v.x = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2;
|
||||
v.y = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2;
|
||||
return v;
|
||||
}
|
||||
|
||||
Vector2u Win32Window::calculateSize(DWORD flags, LONG width, LONG height)
|
||||
{
|
||||
RECT r = {0, 0, width, height};
|
||||
AdjustWindowRect(&r, flags, false);
|
||||
return Vector2u(r.right - r.left, r.bottom - r.top);
|
||||
}
|
||||
|
||||
void Win32Window::enterFullscreen(DisplayMode mode)
|
||||
{
|
||||
LONG rc;
|
||||
::DEVMODEW dev;
|
||||
dev.dmSize = sizeof(dev);
|
||||
dev.dmPelsWidth = mode.width;
|
||||
dev.dmPelsHeight = mode.height;
|
||||
dev.dmBitsPerPel = mode.bpp;
|
||||
dev.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
|
||||
|
||||
rc = ::ChangeDisplaySettingsW(&dev, CDS_FULLSCREEN);
|
||||
if (rc != DISP_CHANGE_SUCCESSFUL) {
|
||||
const char *msg;
|
||||
|
||||
switch(rc) {
|
||||
case DISP_CHANGE_BADDUALVIEW :
|
||||
msg = "The system is DualView capable"; break;
|
||||
case DISP_CHANGE_BADFLAGS :
|
||||
msg = "Invalid flags given"; break;
|
||||
case DISP_CHANGE_BADPARAM :
|
||||
msg = "Invalid parameter"; break;
|
||||
case DISP_CHANGE_BADMODE :
|
||||
msg = "Resolution not supported"; break;
|
||||
case DISP_CHANGE_FAILED :
|
||||
msg = "Display driver failed to set mode"; break;
|
||||
case DISP_CHANGE_NOTUPDATED :
|
||||
msg = "Unable to write settings to the registry"; break;
|
||||
case DISP_CHANGE_RESTART :
|
||||
msg = "System restart required"; break;
|
||||
default :
|
||||
msg = "Unkown error";
|
||||
}
|
||||
|
||||
sp::Log::error("Win32: Failed to switch to fullscreen mode: %s.", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
::SetWindowLong(m_handle, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
::SetWindowPos(m_handle, HWND_TOP, 0, 0, mode.width, mode.height, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
|
||||
|
||||
grabCursor(true);
|
||||
|
||||
m_fs_mode = mode;
|
||||
}
|
||||
|
||||
void Win32Window::exitFullscreen()
|
||||
{
|
||||
if (!m_fs_mode.empty()) {
|
||||
// Restore to previous mode.
|
||||
::ChangeDisplaySettingsW(NULL, 0);
|
||||
m_fs_mode = DisplayMode();
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Window::processResizeMessage(const Vector2u& new_size)
|
||||
{
|
||||
// Check if the size has actually changed.
|
||||
if (m_size != new_size) {
|
||||
|
||||
// Update the size and notify the higher layer.
|
||||
m_size = new_size;
|
||||
onReshape(m_size.x, m_size.y);
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Window::processMessage(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(message) {
|
||||
case WM_SETCURSOR :
|
||||
if (LOWORD(lParam) == HTCLIENT) {
|
||||
::SetCursor(m_cursor);
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY :
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
case WM_SETFOCUS :
|
||||
Log::debug("WM_SETFOCUS");
|
||||
if (m_fs_mode.empty() == false) {
|
||||
enterFullscreen(m_fs_mode);
|
||||
}
|
||||
break;
|
||||
case WM_KILLFOCUS :
|
||||
Log::debug("WM_KILLFOCUS");
|
||||
// If in fullscreen mode.
|
||||
if (m_fs_mode.empty() == false) {
|
||||
// Switch to window mode.
|
||||
::ChangeDisplaySettingsW(NULL, 0);
|
||||
|
||||
// also minimize the window to get it out of the way.
|
||||
minimize();
|
||||
}
|
||||
|
||||
grabCursor(false);
|
||||
break;
|
||||
case WM_SIZE :
|
||||
|
||||
if (!m_inResizeModalLoop && (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) {
|
||||
Vector2u size(LOWORD(lParam), HIWORD(lParam));
|
||||
processResizeMessage(size);
|
||||
}
|
||||
break;
|
||||
case WM_GETMINMAXINFO :
|
||||
{
|
||||
MINMAXINFO* info = (MINMAXINFO*)lParam;
|
||||
info->ptMinTrackSize.x = m_minSize.x;
|
||||
info->ptMinTrackSize.y = m_minSize.y;
|
||||
info->ptMaxTrackSize.x = 99999;
|
||||
info->ptMaxTrackSize.y = 99999;
|
||||
break;
|
||||
}
|
||||
case WM_ENTERSIZEMOVE :
|
||||
m_inResizeModalLoop = true;
|
||||
break;
|
||||
case WM_EXITSIZEMOVE :
|
||||
m_inResizeModalLoop = false;
|
||||
processResizeMessage(getSize());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Win32Window::staticWndProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
Win32Window *win;
|
||||
|
||||
if (message == WM_NCCREATE) {
|
||||
|
||||
LONG_PTR ptr = (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams;
|
||||
::SetWindowLongPtr(handle, GWL_USERDATA, ptr);
|
||||
|
||||
win = (Win32Window*) ptr;
|
||||
} else {
|
||||
win = (Win32Window*) ::GetWindowLongPtr(handle, GWL_USERDATA);
|
||||
}
|
||||
|
||||
if (win) {
|
||||
win->processMessage(message, wParam, lParam);
|
||||
}
|
||||
return DefWindowProc(handle, message, wParam, lParam);
|
||||
}
|
||||
|
||||
} // namespace sp
|
||||
Loading…
Add table
Add a link
Reference in a new issue