160 lines
4.7 KiB
C++
160 lines
4.7 KiB
C++
#include "BorderlessWindowChrome.h"
|
|
|
|
#include <dwmapi.h>
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
|
|
namespace {
|
|
|
|
using DwmSetWindowAttributeFn = HRESULT(WINAPI*)(HWND, DWORD, LPCVOID, DWORD);
|
|
using DwmExtendFrameIntoClientAreaFn = HRESULT(WINAPI*)(HWND, const MARGINS*);
|
|
|
|
HMODULE GetDwmApiModule() {
|
|
static HMODULE dwmapi = []() -> HMODULE {
|
|
HMODULE module = GetModuleHandleW(L"dwmapi.dll");
|
|
if (module == nullptr) {
|
|
module = LoadLibraryW(L"dwmapi.dll");
|
|
}
|
|
return module;
|
|
}();
|
|
|
|
return dwmapi;
|
|
}
|
|
|
|
template <typename ProcedureType>
|
|
ProcedureType GetDwmApiProcedure(const char* name) {
|
|
const HMODULE dwmapi = GetDwmApiModule();
|
|
if (dwmapi == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
return reinterpret_cast<ProcedureType>(GetProcAddress(dwmapi, name));
|
|
}
|
|
|
|
bool IsWindowAlignedToMonitorWorkArea(HWND hwnd) {
|
|
if (hwnd == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
RECT windowRect = {};
|
|
if (!GetWindowRect(hwnd, &windowRect)) {
|
|
return false;
|
|
}
|
|
|
|
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
|
if (monitor == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
MONITORINFO monitorInfo = {};
|
|
monitorInfo.cbSize = sizeof(monitorInfo);
|
|
if (!GetMonitorInfoW(monitor, &monitorInfo)) {
|
|
return false;
|
|
}
|
|
|
|
const RECT& workArea = monitorInfo.rcWork;
|
|
return windowRect.left == workArea.left &&
|
|
windowRect.top == workArea.top &&
|
|
windowRect.right == workArea.right &&
|
|
windowRect.bottom == workArea.bottom;
|
|
}
|
|
|
|
template <typename ValueType>
|
|
void ApplyDwmWindowAttribute(HWND hwnd, DWORD attribute, const ValueType& value) {
|
|
if (hwnd == nullptr) {
|
|
return;
|
|
}
|
|
|
|
static const DwmSetWindowAttributeFn setWindowAttribute =
|
|
GetDwmApiProcedure<DwmSetWindowAttributeFn>("DwmSetWindowAttribute");
|
|
if (setWindowAttribute != nullptr) {
|
|
setWindowAttribute(hwnd, attribute, &value, sizeof(value));
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void EnableBorderlessWindowShadow(HWND hwnd) {
|
|
if (hwnd == nullptr) {
|
|
return;
|
|
}
|
|
|
|
static const DwmExtendFrameIntoClientAreaFn extendFrameIntoClientArea =
|
|
GetDwmApiProcedure<DwmExtendFrameIntoClientAreaFn>("DwmExtendFrameIntoClientArea");
|
|
if (extendFrameIntoClientArea != nullptr) {
|
|
const bool maximized = IsZoomed(hwnd) || IsWindowAlignedToMonitorWorkArea(hwnd);
|
|
const MARGINS margins = maximized
|
|
? MARGINS{ 0, 0, 0, 0 }
|
|
: MARGINS{ 1, 1, 1, 1 };
|
|
extendFrameIntoClientArea(hwnd, &margins);
|
|
}
|
|
}
|
|
|
|
void RefreshBorderlessWindowDwmDecorations(HWND hwnd) {
|
|
if (hwnd == nullptr) {
|
|
return;
|
|
}
|
|
|
|
const int ncRenderingPolicy = DWMNCRP_DISABLED;
|
|
const BOOL allowNcPaint = FALSE;
|
|
const BOOL disableTransitions = TRUE;
|
|
const BOOL useImmersiveDarkMode = TRUE;
|
|
const COLORREF captionColor = RGB(26, 26, 26);
|
|
const COLORREF textColor = RGB(235, 235, 235);
|
|
const COLORREF borderColor = RGB(26, 26, 26);
|
|
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, ncRenderingPolicy);
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_ALLOW_NCPAINT, allowNcPaint);
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, disableTransitions);
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, useImmersiveDarkMode);
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, captionColor);
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_TEXT_COLOR, textColor);
|
|
ApplyDwmWindowAttribute(hwnd, DWMWA_BORDER_COLOR, borderColor);
|
|
EnableBorderlessWindowShadow(hwnd);
|
|
}
|
|
|
|
bool HandleBorderlessWindowGetMinMaxInfo(HWND hwnd, LPARAM lParam) {
|
|
if (hwnd == nullptr || lParam == 0) {
|
|
return false;
|
|
}
|
|
|
|
auto* minMaxInfo = reinterpret_cast<MINMAXINFO*>(lParam);
|
|
if (minMaxInfo == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
|
if (monitor == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
MONITORINFO monitorInfo = {};
|
|
monitorInfo.cbSize = sizeof(monitorInfo);
|
|
if (!GetMonitorInfoW(monitor, &monitorInfo)) {
|
|
return false;
|
|
}
|
|
|
|
const RECT& workArea = monitorInfo.rcWork;
|
|
const RECT& monitorArea = monitorInfo.rcMonitor;
|
|
minMaxInfo->ptMaxPosition.x = workArea.left - monitorArea.left;
|
|
minMaxInfo->ptMaxPosition.y = workArea.top - monitorArea.top;
|
|
minMaxInfo->ptMaxSize.x = workArea.right - workArea.left;
|
|
minMaxInfo->ptMaxSize.y = workArea.bottom - workArea.top;
|
|
minMaxInfo->ptMaxTrackSize = minMaxInfo->ptMaxSize;
|
|
return true;
|
|
}
|
|
|
|
LRESULT HandleBorderlessWindowNcCalcSize(
|
|
HWND hwnd,
|
|
WPARAM wParam,
|
|
LPARAM lParam,
|
|
UINT dpi) {
|
|
(void)hwnd;
|
|
(void)wParam;
|
|
(void)lParam;
|
|
(void)dpi;
|
|
return 0;
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::Host
|