refactoring
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
#include "WinNativeWindow.h"
|
||||
|
||||
#include <dwmapi.h>
|
||||
#include <stdexcept>
|
||||
|
||||
HWND WinNativeWindow::childWindow = nullptr;
|
||||
QWidget *WinNativeWindow::childWidget = nullptr;
|
||||
|
||||
WinNativeWindow::WinNativeWindow(const int x, const int y, const int width, const int height)
|
||||
: hWnd(nullptr)
|
||||
{
|
||||
// The native window technically has a background color. You can set it here
|
||||
HBRUSH windowBackground = CreateSolidBrush(RGB(255, 255, 255));
|
||||
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
WNDCLASSEX wcx = {0};
|
||||
|
||||
wcx.cbSize = sizeof(WNDCLASSEX);
|
||||
wcx.style = CS_HREDRAW | CS_VREDRAW | CS_DROPSHADOW;
|
||||
wcx.hInstance = hInstance;
|
||||
wcx.lpfnWndProc = WndProc;
|
||||
wcx.cbClsExtra = 0;
|
||||
wcx.cbWndExtra = 0;
|
||||
wcx.lpszClassName = L"WindowClass";
|
||||
wcx.hbrBackground = windowBackground;
|
||||
wcx.hCursor = LoadCursor(hInstance, IDC_ARROW);
|
||||
|
||||
RegisterClassEx(&wcx);
|
||||
if (FAILED(RegisterClassEx(&wcx))) {
|
||||
throw std::runtime_error("Couldn't register window class");
|
||||
}
|
||||
|
||||
// Create a native window with the appropriate style
|
||||
hWnd = CreateWindow(L"WindowClass", L"WindowTitle", aero_borderless, x, y, width, height, 0, 0,
|
||||
hInstance, nullptr);
|
||||
if (!hWnd) {
|
||||
throw std::runtime_error("couldn't create window because of reasons");
|
||||
}
|
||||
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
|
||||
// This code may be required for aero shadows on some versions of Windows
|
||||
// const MARGINS aero_shadow_on = { 1, 1, 1, 1 };
|
||||
// DwmExtendFrameIntoClientArea(hWnd, &aero_shadow_on);
|
||||
|
||||
SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
WinNativeWindow::~WinNativeWindow()
|
||||
{
|
||||
// Hide the window & send the destroy message
|
||||
ShowWindow(hWnd, SW_HIDE);
|
||||
DestroyWindow(hWnd);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WinNativeWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
WinNativeWindow *window =
|
||||
reinterpret_cast<WinNativeWindow *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
|
||||
if (!window) {
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
// ALT + SPACE or F10 system menu
|
||||
case WM_SYSCOMMAND: {
|
||||
if (wParam == SC_KEYMENU) {
|
||||
RECT winrect;
|
||||
GetWindowRect(hWnd, &winrect);
|
||||
TrackPopupMenu(GetSystemMenu(hWnd, false), TPM_TOPALIGN | TPM_LEFTALIGN,
|
||||
winrect.left + 5, winrect.top + 5, 0, hWnd, NULL);
|
||||
break;
|
||||
} else {
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
case WM_NCCALCSIZE: {
|
||||
// this kills the window frame and title bar we added with
|
||||
// WS_THICKFRAME and WS_CAPTION
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the parent window gets any close messages, send them over to
|
||||
// QWinWidget and don't actually close here
|
||||
case WM_CLOSE: {
|
||||
if (childWindow) {
|
||||
SendMessage(childWindow, WM_CLOSE, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_DESTROY: {
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_NCHITTEST: {
|
||||
const LONG borderWidth =
|
||||
8 * childWidget->window()->devicePixelRatio(); // This value can be arbitrarily
|
||||
// large as only
|
||||
// intentionally-HTTRANSPARENT'd
|
||||
// messages arrive here
|
||||
RECT winrect;
|
||||
GetWindowRect(hWnd, &winrect);
|
||||
long x = GET_X_LPARAM(lParam);
|
||||
long y = GET_Y_LPARAM(lParam);
|
||||
|
||||
// bottom left corner
|
||||
if (x >= winrect.left && x < winrect.left + borderWidth && y < winrect.bottom &&
|
||||
y >= winrect.bottom - borderWidth) {
|
||||
return HTBOTTOMLEFT;
|
||||
}
|
||||
// bottom right corner
|
||||
if (x < winrect.right && x >= winrect.right - borderWidth && y < winrect.bottom &&
|
||||
y >= winrect.bottom - borderWidth) {
|
||||
return HTBOTTOMRIGHT;
|
||||
}
|
||||
// top left corner
|
||||
if (x >= winrect.left && x < winrect.left + borderWidth && y >= winrect.top &&
|
||||
y < winrect.top + borderWidth) {
|
||||
return HTTOPLEFT;
|
||||
}
|
||||
// top right corner
|
||||
if (x < winrect.right && x >= winrect.right - borderWidth && y >= winrect.top &&
|
||||
y < winrect.top + borderWidth) {
|
||||
return HTTOPRIGHT;
|
||||
}
|
||||
// left border
|
||||
if (x >= winrect.left && x < winrect.left + borderWidth) {
|
||||
return HTLEFT;
|
||||
}
|
||||
// right border
|
||||
if (x < winrect.right && x >= winrect.right - borderWidth) {
|
||||
return HTRIGHT;
|
||||
}
|
||||
// bottom border
|
||||
if (y < winrect.bottom && y >= winrect.bottom - borderWidth) {
|
||||
return HTBOTTOM;
|
||||
}
|
||||
// top border
|
||||
if (y >= winrect.top && y < winrect.top + borderWidth) {
|
||||
return HTTOP;
|
||||
}
|
||||
|
||||
// If it wasn't a border but we still got the message, return
|
||||
// HTCAPTION to allow click-dragging the window
|
||||
return HTCAPTION;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// When this native window changes size, it needs to manually resize the
|
||||
// QWinWidget child
|
||||
case WM_SIZE: {
|
||||
RECT winrect;
|
||||
GetClientRect(hWnd, &winrect);
|
||||
|
||||
WINDOWPLACEMENT wp;
|
||||
wp.length = sizeof(WINDOWPLACEMENT);
|
||||
GetWindowPlacement(hWnd, &wp);
|
||||
if (childWidget) {
|
||||
if (wp.showCmd == SW_MAXIMIZE) {
|
||||
childWidget->setGeometry(
|
||||
8, 8 // Maximized window draw 8 pixels off screen
|
||||
,
|
||||
winrect.right / childWidget->window()->devicePixelRatio() - 16,
|
||||
winrect.bottom / childWidget->window()->devicePixelRatio() - 16);
|
||||
} else {
|
||||
childWidget->setGeometry(
|
||||
0, 0, winrect.right / childWidget->window()->devicePixelRatio(),
|
||||
winrect.bottom / childWidget->window()->devicePixelRatio());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_GETMINMAXINFO: {
|
||||
MINMAXINFO *minMaxInfo = (MINMAXINFO *)lParam;
|
||||
if (window->minimumSize.required) {
|
||||
minMaxInfo->ptMinTrackSize.x = window->getMinimumWidth();
|
||||
;
|
||||
minMaxInfo->ptMinTrackSize.y = window->getMinimumHeight();
|
||||
}
|
||||
|
||||
if (window->maximumSize.required) {
|
||||
minMaxInfo->ptMaxTrackSize.x = window->getMaximumWidth();
|
||||
minMaxInfo->ptMaxTrackSize.y = window->getMaximumHeight();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void WinNativeWindow::setGeometry(const int x, const int y, const int width, const int height)
|
||||
{
|
||||
MoveWindow(hWnd, x, y, width, height, 1);
|
||||
}
|
||||
|
||||
void WinNativeWindow::setMinimumSize(const int width, const int height)
|
||||
{
|
||||
this->minimumSize.required = true;
|
||||
this->minimumSize.width = width;
|
||||
this->minimumSize.height = height;
|
||||
}
|
||||
|
||||
int WinNativeWindow::getMinimumWidth()
|
||||
{
|
||||
return minimumSize.width;
|
||||
}
|
||||
|
||||
int WinNativeWindow::getMinimumHeight()
|
||||
{
|
||||
return minimumSize.height;
|
||||
}
|
||||
|
||||
void WinNativeWindow::setMaximumSize(const int width, const int height)
|
||||
{
|
||||
this->maximumSize.required = true;
|
||||
this->maximumSize.width = width;
|
||||
this->maximumSize.height = height;
|
||||
}
|
||||
|
||||
int WinNativeWindow::getMaximumWidth()
|
||||
{
|
||||
return maximumSize.width;
|
||||
}
|
||||
|
||||
int WinNativeWindow::getMaximumHeight()
|
||||
{
|
||||
return maximumSize.height;
|
||||
}
|
||||
Reference in New Issue
Block a user