#include #include #include #include #include "Win32Application.h" #include "Win32Internal.h" #include "Win32Display.h" namespace sp { #define WND_CLASSNAME "SPECTRE_WIN32_WNDCLASS" static bool firstTime = true; Win32Display::Win32Display() : m_handle (NULL), m_icon (0), m_cursor (0), m_inResizeModalLoop (false), m_minSize (200, 200) { } Win32Display::~Win32Display() { if (m_icon) { DestroyIcon(m_icon); } if (m_handle) { DestroyWindow(m_handle); } } bool Win32Display::create(DisplayDescription description) { DWORD flags = getWin32Flags(description.decoration); int x, y; if (firstTime) { registerClass(); firstTime = false; } centerWindow(x, y, description.mode.width, description.mode.height); // Create window. m_handle = CreateWindowExA(0, WND_CLASSNAME, "", flags, x, y, description.mode.width, description.mode.height, NULL, NULL, GetModuleHandle(NULL), (LPVOID) this); if (!m_handle) { log("Win32 - Could not create window: %s", Win32GetMessage(GetLastError())); return false; } setSize(description.mode.width, description.mode.height); // Store the size for use later. m_size = getSize(); return true; } void Win32Display::destroy() { if (m_handle) { DestroyWindow(m_handle); m_handle = NULL; } } void* Win32Display::getHandle() const { return m_handle; } bool Win32Display::isValid() { return m_handle != NULL; } void Win32Display::setSize(unsigned int width, unsigned int height) { int w, h; RECT rect = {0, 0, width, height}; AdjustWindowRect(&rect, GetWindowLong(m_handle, GWL_STYLE), false); w = rect.right - rect.left; h = rect.bottom - rect.top; ::SetWindowPos(m_handle, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_NOZORDER); } Vector2u Win32Display::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 Win32Display::setPosition(unsigned int x, unsigned int y) { ::SetWindowPos(m_handle, NULL, x, y, 0, 0, SWP_NOSIZE); } void Win32Display::setCaption(const std::string& caption) { ::SetWindowText(m_handle, caption.c_str()); } void Win32Display::showCursor(bool value) { if (value) { m_cursor = ::LoadCursor(NULL, IDC_ARROW); } else { m_cursor = 0; } ::SetCursor(m_cursor); } void Win32Display::setIcon(const std::string& icon) { HICON hIcon = (HICON) ::LoadImage(0, icon.c_str(), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); if (hIcon) { if (m_icon) { DestroyIcon(m_icon); } m_icon = hIcon; ::SendMessage(m_handle, WM_SETICON, ICON_SMALL, (LPARAM) hIcon); ::SendMessage(m_handle, WM_SETICON, ICON_BIG, (LPARAM) hIcon); } } void Win32Display::registerClass() { WNDCLASSA wndcl; ZeroMemory(&wndcl, sizeof(wndcl)); wndcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndcl.lpfnWndProc = Win32Display::staticWndProc; wndcl.hInstance = ::GetModuleHandle(NULL); wndcl.lpszClassName = WND_CLASSNAME; ::RegisterClass(&wndcl); } DWORD Win32Display::getWin32Flags(unsigned int flags) { DWORD win32_flags = WS_VISIBLE; if (flags == DisplayDecorate::None) { win32_flags |= WS_POPUP; } else { if (flags & DisplayDecorate::Menu) { win32_flags |= WS_CAPTION | WS_MINIMIZEBOX; } if (flags & DisplayDecorate::Resize) { win32_flags |= WS_THICKFRAME | WS_MAXIMIZEBOX; } if (flags & DisplayDecorate::Close) { win32_flags |= WS_SYSMENU; } } return win32_flags; } void Win32Display::centerWindow(int &x, int &y, int width, int height) { x = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2; y = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2; } void Win32Display::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 Win32Display::processMessage(UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_SETCURSOR : if (LOWORD(lParam) == HTCLIENT) { ::SetCursor(m_cursor); } break; case WM_DESTROY : destroy(); PostQuitMessage(0); break; case WM_SETFOCUS : OutputDebugString("WM_SETFOCUS\n"); break; case WM_KILLFOCUS : OutputDebugString("WM_KILLFOCUS\n"); break; case WM_SIZE : if (!m_inResizeModalLoop && (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)) { processResizeMessage(getSize()); } 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 Win32Display::staticWndProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { Win32Display *display; if (message == WM_NCCREATE) { LONG_PTR ptr = (LONG_PTR) ((LPCREATESTRUCT)lParam)->lpCreateParams; ::SetWindowLong(handle, GWL_USERDATA, ptr); display = (Win32Display*) ptr; } else { display = (Win32Display*) ::GetWindowLong(handle, GWL_USERDATA); } if (display) { display->processMessage(message, wParam, lParam); } return DefWindowProc(handle, message, wParam, lParam); } } // namespace sp